Skip to content

Commit

Permalink
Don't refer to classes in @sample tags (#300)
Browse files Browse the repository at this point in the history
* Don't refer to classes in @sample tags

Starting from 1.9.20, Dokka no longer supports
classes being referred in the @sample tag.

This change moves declarations of sample classes,
 illustrating how interfaces could be implemented 
into corresponding sample functions.
  • Loading branch information
fzhinkin committed Apr 24, 2024
1 parent 870e96f commit c2d5220
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 103 deletions.
1 change: 0 additions & 1 deletion core/common/src/RawSink.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ package kotlinx.io
*
* Implementors should abstain from throwing exceptions other than those that are documented for RawSink methods.
*
* @sample kotlinx.io.samples.CRC32Sink
* @sample kotlinx.io.samples.Crc32Sample.crc32
*/
@OptIn(ExperimentalStdlibApi::class)
Expand Down
1 change: 0 additions & 1 deletion core/common/src/RawSource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ package kotlinx.io
*
* Implementors should abstain from throwing exceptions other than those that are documented for RawSource methods.
*
* @sample kotlinx.io.samples.RC4DecryptingSource
* @sample kotlinx.io.samples.RC4SourceSample.rc4
*/
@OptIn(ExperimentalStdlibApi::class)
Expand Down
90 changes: 44 additions & 46 deletions core/common/test/samples/rawSinkSample.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,62 +9,60 @@ import kotlinx.io.*
import kotlin.test.Test
import kotlin.test.assertEquals

@OptIn(ExperimentalUnsignedTypes::class)
private fun generateCrc32Table(): UIntArray {
val table = UIntArray(256)

for (idx in table.indices) {
table[idx] = idx.toUInt()
for (bit in 8 downTo 1) {
table[idx] = if (table[idx] % 2U == 0U) {
table[idx].shr(1)
} else {
table[idx].shr(1).xor(0xEDB88320U)
class Crc32Sample {
@OptIn(ExperimentalStdlibApi::class, ExperimentalUnsignedTypes::class)
@Test
fun crc32() {
/**
* Sink calculating CRC-32 code for all the data written to it and sending this data to the upstream afterward.
* The CRC-32 value could be obtained using [crc32] method.
*
* See https://en.wikipedia.org/wiki/Cyclic_redundancy_check for more information about CRC-32.
*/
class CRC32Sink(private val upstream: RawSink): RawSink {
private val tempBuffer = Buffer()
private val crc32Table = generateCrc32Table()
private var crc32: UInt = 0xffffffffU

private fun update(value: Byte) {
val index = value.xor(crc32.toByte()).toUByte()
crc32 = crc32Table[index.toInt()].xor(crc32.shr(8))
}
}
}

return table
}
fun crc32(): UInt = crc32.xor(0xffffffffU)

/**
* Sink calculating CRC-32 code for all the data written to it and sending this data to the upstream afterward.
* The CRC-32 value could be obtained using [crc32] method.
*
* See https://en.wikipedia.org/wiki/Cyclic_redundancy_check for more information about CRC-32.
*/
@OptIn(ExperimentalUnsignedTypes::class)
class CRC32Sink(private val upstream: RawSink): RawSink {
private val tempBuffer = Buffer()
private val crc32Table = generateCrc32Table()
private var crc32: UInt = 0xffffffffU

private fun update(value: Byte) {
val index = value.xor(crc32.toByte()).toUByte()
crc32 = crc32Table[index.toInt()].xor(crc32.shr(8))
}
override fun write(source: Buffer, byteCount: Long) {
source.copyTo(tempBuffer, 0, byteCount)

while (!tempBuffer.exhausted()) {
update(tempBuffer.readByte())
}

fun crc32(): UInt = crc32.xor(0xffffffffU)
upstream.write(source, byteCount)
}

override fun write(source: Buffer, byteCount: Long) {
source.copyTo(tempBuffer, 0, byteCount)
override fun flush() = upstream.flush()

while (!tempBuffer.exhausted()) {
update(tempBuffer.readByte())
}
override fun close() = upstream.close()

upstream.write(source, byteCount)
}
private fun generateCrc32Table(): UIntArray {
val table = UIntArray(256)

override fun flush() = upstream.flush()
for (idx in table.indices) {
table[idx] = idx.toUInt()
for (bit in 8 downTo 1) {
table[idx] = if (table[idx] % 2U == 0U) {
table[idx].shr(1)
} else {
table[idx].shr(1).xor(0xEDB88320U)
}
}
}

override fun close() = upstream.close()
}
return table
}
}

class Crc32Sample {
@OptIn(ExperimentalStdlibApi::class)
@Test
fun crc32() {
val crc32Sink = CRC32Sink(discardingSink())

crc32Sink.buffered().use {
Expand Down
110 changes: 55 additions & 55 deletions core/common/test/samples/rawSourceSample.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,72 +9,72 @@ import kotlinx.io.*
import kotlin.test.Test
import kotlin.test.assertEquals

/**
* Source decrypting all the data read from the downstream using RC4 algorithm.
*
* See https://en.wikipedia.org/wiki/RC4 for more information about the cypher.
*
* Implementation of RC4 stream cypher based on http://cypherpunks.venona.com/archive/1994/09/msg00304.html
*/
@OptIn(ExperimentalUnsignedTypes::class)
class RC4DecryptingSource(private val downstream: RawSource, key: String): RawSource {
private val buffer = Buffer()
private val key = RC4Key(key)
class RC4SourceSample {
@Test
fun rc4() {
/**
* Source decrypting all the data read from the downstream using RC4 algorithm.
*
* See https://en.wikipedia.org/wiki/RC4 for more information about the cypher.
*
* Implementation of RC4 stream cypher based on http://cypherpunks.venona.com/archive/1994/09/msg00304.html
*/
@OptIn(ExperimentalUnsignedTypes::class)
class RC4DecryptingSource(private val downstream: RawSource, key: String): RawSource {
private val buffer = Buffer()
private val key = RC4Key(key)

override fun readAtMostTo(sink: Buffer, byteCount: Long): Long {
val bytesRead = downstream.readAtMostTo(buffer, byteCount)
if (bytesRead == -1L) {
return -1L
}
override fun readAtMostTo(sink: Buffer, byteCount: Long): Long {
val bytesRead = downstream.readAtMostTo(buffer, byteCount)
if (bytesRead == -1L) {
return -1L
}

while (!buffer.exhausted()) {
val byte = buffer.readByte()
sink.writeByte(byte.xor(key.nextByte()))
}
while (!buffer.exhausted()) {
val byte = buffer.readByte()
sink.writeByte(byte.xor(key.nextByte()))
}

return bytesRead
}
return bytesRead
}

override fun close() = downstream.close()
override fun close() = downstream.close()

private class RC4Key(key: String) {
private var keyState: UByteArray
private var keyX: Int = 0
private var keyY: Int = 0
private inner class RC4Key(key: String) {
private var keyState: UByteArray
private var keyX: Int = 0
private var keyY: Int = 0

init {
require(key.isNotEmpty()) { "Key could not be empty" }
val keyBytes = key.encodeToByteArray()
keyState = UByteArray(256) { it.toUByte() }
var index1 = 0
var index2 = 0
init {
require(key.isNotEmpty()) { "Key could not be empty" }
val keyBytes = key.encodeToByteArray()
keyState = UByteArray(256) { it.toUByte() }
var index1 = 0
var index2 = 0

for (idx in keyState.indices) {
index2 = (keyBytes[index1] + keyState[idx].toInt() + index2) % 256
swapStateBytes(idx, index2)
index1 = (index1 + 1) % keyBytes.size
}
}
for (idx in keyState.indices) {
index2 = (keyBytes[index1] + keyState[idx].toInt() + index2) % 256
swapStateBytes(idx, index2)
index1 = (index1 + 1) % keyBytes.size
}
}

fun nextByte(): Byte {
keyX = (keyX + 1) % 256
keyY = (keyState[keyX].toInt() + keyY) % 256
swapStateBytes(keyX, keyY)
val idx = (keyState[keyX] + keyState[keyY]) % 256U
return keyState[idx.toInt()].toByte()
}
fun nextByte(): Byte {
keyX = (keyX + 1) % 256
keyY = (keyState[keyX].toInt() + keyY) % 256
swapStateBytes(keyX, keyY)
val idx = (keyState[keyX] + keyState[keyY]) % 256U
return keyState[idx.toInt()].toByte()
}

private fun swapStateBytes(x: Int, y: Int) {
val tmp = keyState[x]
keyState[x] = keyState[y]
keyState[y] = tmp
private fun swapStateBytes(x: Int, y: Int) {
val tmp = keyState[x]
keyState[x] = keyState[y]
keyState[y] = tmp
}
}
}
}
}

class RC4SourceSample {
@Test
fun rc4() {
val key = "key"
val source = Buffer().also { it.write(byteArrayOf(0x58, 0x09, 0x57, 0x9fU.toByte(), 0x41, 0xfbU.toByte())) }
val rc4Source = RC4DecryptingSource(source, key).buffered()
Expand Down

0 comments on commit c2d5220

Please sign in to comment.