Skip to content

Commit 3d16338

Browse files
committed
added kdocs
1 parent 0322b04 commit 3d16338

14 files changed

Lines changed: 185 additions & 173 deletions

File tree

src/main/kotlin/com/eignex/kencode/Base64.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ open class Base64(val alphabet: CharArray) : ByteEncoding {
2828
companion object Default : Base64(BASE_64.toCharArray())
2929

3030
init {
31-
require(alphabet.size == 64) {"Base64 requires a 64 length alphabet" }
31+
require(alphabet.size == 64) { "Base64 requires a 64 length alphabet" }
3232
}
3333

3434
private val decodeTable: IntArray = IntArray(256) { -1 }.apply {
@@ -39,9 +39,7 @@ open class Base64(val alphabet: CharArray) : ByteEncoding {
3939
}
4040

4141
override fun encode(
42-
input: ByteArray,
43-
offset: Int,
44-
length: Int
42+
input: ByteArray, offset: Int, length: Int
4543
): String {
4644
require(offset >= 0 && length >= 0 && offset + length <= input.size) {
4745
"Invalid offset/length for input of size ${input.size}"

src/main/kotlin/com/eignex/kencode/Base85.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ open class Base85(
7878
val fullGroups = len / 5
7979
val rem = len % 5
8080

81-
// Remainder of 1 is invalid in ASCII85 (n bytes → n+1 chars, so remainder is 0 or 2–4).
81+
// Remainder of 1 is invalid in ASCII85 (n bytes → n+1 chars,
82+
// so remainder is 0 or 2–4).
8283
if (rem == 1) {
8384
throw IllegalArgumentException("Invalid ASCII85 length: remainder of 1 is not allowed")
8485
}

src/main/kotlin/com/eignex/kencode/BaseRadix.kt

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package com.eignex.kencode
22

33
import java.math.BigInteger
4-
import kotlin.math.ceil
5-
import kotlin.math.log2
6-
import kotlin.math.min
4+
import kotlin.math.*
75

8-
const val BASE_62: String = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
6+
const val BASE_62: String =
7+
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
98

109
/**
1110
* Base62 encoder/decoder using digits, lowercase, then uppercase characters.
@@ -39,8 +38,7 @@ object Base36 : BaseRadix(BASE_62.take(36))
3938
* @property blockSize maximum bytes processed per block.
4039
*/
4140
open class BaseRadix(
42-
private val alphabet: String,
43-
val blockSize: Int = 32
41+
private val alphabet: String, val blockSize: Int = 32
4442
) : ByteEncoding {
4543

4644
init {
@@ -62,11 +60,12 @@ open class BaseRadix(
6260
/**
6361
* Maps a UTF-16 code unit (Char.code) to its index in [alphabet], or -1 if not present.
6462
*/
65-
private val inverseAlphabet: IntArray = IntArray(65536) { -1 }.also { lookup ->
66-
alphabet.forEachIndexed { index, c ->
67-
lookup[c.code] = index
63+
private val inverseAlphabet: IntArray =
64+
IntArray(65536) { -1 }.also { lookup ->
65+
alphabet.forEachIndexed { index, c ->
66+
lookup[c.code] = index
67+
}
6868
}
69-
}
7069

7170
private fun charFromIndex(index: Int): Char = alphabet[index]
7271

@@ -129,9 +128,7 @@ open class BaseRadix(
129128
* Encode the given [input] byte array range into a base-[alphabetSize] string.
130129
*/
131130
override fun encode(
132-
input: ByteArray,
133-
offset: Int,
134-
length: Int
131+
input: ByteArray, offset: Int, length: Int
135132
): String {
136133
require(offset >= 0 && length >= 0 && offset + length <= input.size) {
137134
"Invalid offset/length: offset=$offset, length=$length, size=${input.size}"
@@ -176,7 +173,8 @@ open class BaseRadix(
176173
throw IllegalArgumentException("Invalid encoded length: ${input.length}")
177174
}
178175

179-
val capacityRatio = ceil(maxDecodedBlockLength / maxEncodedBlockLength.toDouble()).toInt()
176+
val capacityRatio =
177+
ceil(maxDecodedBlockLength / maxEncodedBlockLength.toDouble()).toInt()
180178
val output = ByteArray(input.length * capacityRatio)
181179

182180
var inPos = 0

src/main/kotlin/com/eignex/kencode/ByteEncoding.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ interface ByteEncoding {
2929
* length.
3030
*/
3131
fun encode(
32-
input: ByteArray,
33-
offset: Int = 0,
34-
length: Int = input.size - offset
32+
input: ByteArray, offset: Int = 0, length: Int = input.size - offset
3533
): String
3634

3735
/**

src/main/kotlin/com/eignex/kencode/Crc.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ open class Crc16(
3030

3131
private val mask = (1 shl width) - 1
3232

33-
// Internal representation is reflected (LSB-first), so pre-reflect poly and init.
33+
// Internal representation is reflected (LSB-first),
34+
// so pre-reflect poly and init.
3435
private val refPoly: Int = poly.reverseBits(width)
3536
private val refInit: Int = init.reverseBits(width)
3637

@@ -97,9 +98,8 @@ open class Crc32(
9798

9899
companion object Default : Crc32()
99100

100-
private val mask: Long =
101-
if (width == 32) 0xFFFFFFFFL
102-
else (1L shl width) - 1L
101+
private val mask: Long = if (width == 32) 0xFFFFFFFFL
102+
else (1L shl width) - 1L
103103

104104
// Internal representation: reflected
105105
private val refPoly: Long = poly.reverseBits(width).toLong() and mask
@@ -143,7 +143,6 @@ open class Crc32(
143143
}
144144

145145
/** Bit helpers */
146-
147146
private fun Int.reverseBits(width: Int): Int {
148147
var v = this
149148
var r = 0

src/main/kotlin/com/eignex/kencode/EncodedFormat.kt

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,44 @@ import kotlinx.serialization.*
55
import kotlinx.serialization.modules.EmptySerializersModule
66
import kotlinx.serialization.modules.SerializersModule
77

8+
/**
9+
* Text `StringFormat` that combines:
10+
*
11+
* - A binary format (e.g. [PackedFormat], `ProtoBuf`)
12+
* - An optional checksum
13+
* - An ASCII-safe byte encoding (e.g. [Base62], [Base64], [Base36], [Base85])
14+
*
15+
* Typical use:
16+
*
17+
* - `encodeToString`: serialize → (optionally) append checksum → encode bytes
18+
* - `decodeFromString`: decode bytes → (optionally) verify checksum → deserialize
19+
*
20+
* This is intended for short, predictable tokens for URLs, headers, file names, etc.
21+
*
22+
* @property codec ASCII-safe byte codec used to turn raw bytes into text.
23+
* @property checksum Optional checksum appended to the binary payload and verified on decode.
24+
* @property binaryFormat Binary serialization format used before encoding.
25+
*/
826
@OptIn(ExperimentalSerializationApi::class)
927
open class EncodedFormat(
1028
val codec: ByteEncoding = Base62,
1129
val checksum: Checksum? = null,
1230
val binaryFormat: BinaryFormat = PackedFormat
1331
) : StringFormat {
1432

33+
/**
34+
* Default format: `PackedFormat` + `Base62` without checksum.
35+
*/
1536
companion object Default : EncodedFormat()
1637

1738
override val serializersModule: SerializersModule = EmptySerializersModule()
1839

40+
/**
41+
* Serializes [value] with [binaryFormat], optionally appends [checksum],
42+
* and encodes the result using [codec].
43+
*/
1944
override fun <T> encodeToString(
20-
serializer: SerializationStrategy<T>,
21-
value: T
45+
serializer: SerializationStrategy<T>, value: T
2246
): String {
2347
val bytes = binaryFormat.encodeToByteArray(serializer, value)
2448
val checked = if (checksum != null) {
@@ -27,9 +51,14 @@ open class EncodedFormat(
2751
return codec.encode(checked)
2852
}
2953

54+
/**
55+
* Decodes [string] using [codec], optionally verifies [checksum],
56+
* then deserializes the remaining bytes with [binaryFormat].
57+
*
58+
* @throws IllegalArgumentException if a checksum is configured and does not match.
59+
*/
3060
override fun <T> decodeFromString(
31-
deserializer: DeserializationStrategy<T>,
32-
string: String
61+
deserializer: DeserializationStrategy<T>, string: String
3362
): T {
3463
val input = codec.decode(string)
3564
val bytes = if (checksum != null) {

src/main/kotlin/com/eignex/kencode/PackedDecoder.kt

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@ class PackedDecoder(
3131
inStructure = true
3232
currentDescriptor = descriptor
3333

34-
val boolIdx = (0 until descriptor.elementsCount)
35-
.filter { descriptor.getElementDescriptor(it).kind == PrimitiveKind.BOOLEAN }
34+
val boolIdx = (0 until descriptor.elementsCount).filter {
35+
descriptor.getElementDescriptor(it).kind == PrimitiveKind.BOOLEAN
36+
}
3637
booleanIndices = boolIdx.toIntArray()
3738

38-
val nullableIdx = (0 until descriptor.elementsCount)
39-
.filter { descriptor.getElementDescriptor(it).isNullable }
39+
val nullableIdx = (0 until descriptor.elementsCount).filter {
40+
descriptor.getElementDescriptor(it).isNullable
41+
}
4042
nullableIndices = nullableIdx.toIntArray()
4143

4244
val (flagsLong, bytesRead) = PackedUtils.decodeVarLong(input, position)
@@ -47,7 +49,8 @@ class PackedDecoder(
4749
booleanValues = BooleanArray(0)
4850
nullValues = BooleanArray(0)
4951
} else {
50-
val allFlags = PackedUtils.unpackFlagsFromLong(flagsLong, totalFlags)
52+
val allFlags =
53+
PackedUtils.unpackFlagsFromLong(flagsLong, totalFlags)
5154
booleanValues = if (booleanIndices.isEmpty()) {
5255
BooleanArray(0)
5356
} else {
@@ -211,17 +214,15 @@ class PackedDecoder(
211214
}
212215

213216
override fun decodeBooleanElement(
214-
descriptor: SerialDescriptor,
215-
index: Int
217+
descriptor: SerialDescriptor, index: Int
216218
): Boolean {
217219
val pos = booleanPos(index)
218220
if (pos == -1) error("Element $index is not a boolean")
219221
return booleanValues[pos]
220222
}
221223

222224
override fun decodeIntElement(
223-
descriptor: SerialDescriptor,
224-
index: Int
225+
descriptor: SerialDescriptor, index: Int
225226
): Int {
226227
val anns = descriptor.getElementAnnotations(index)
227228
val zigZag = anns.hasVarInt()
@@ -237,8 +238,7 @@ class PackedDecoder(
237238
}
238239

239240
override fun decodeLongElement(
240-
descriptor: SerialDescriptor,
241-
index: Int
241+
descriptor: SerialDescriptor, index: Int
242242
): Long {
243243
val anns = descriptor.getElementAnnotations(index)
244244
val zigZag = anns.hasVarInt()
@@ -254,8 +254,7 @@ class PackedDecoder(
254254
}
255255

256256
override fun decodeByteElement(
257-
descriptor: SerialDescriptor,
258-
index: Int
257+
descriptor: SerialDescriptor, index: Int
259258
): Byte {
260259
require(position < input.size) {
261260
"Unexpected EOF while decoding Byte element at index $index"
@@ -264,41 +263,36 @@ class PackedDecoder(
264263
}
265264

266265
override fun decodeShortElement(
267-
descriptor: SerialDescriptor,
268-
index: Int
266+
descriptor: SerialDescriptor, index: Int
269267
): Short {
270268
return readShortPos()
271269
}
272270

273271
override fun decodeCharElement(
274-
descriptor: SerialDescriptor,
275-
index: Int
272+
descriptor: SerialDescriptor, index: Int
276273
): Char {
277274
return readUtf8Char()
278275
}
279276

280277
override fun decodeFloatElement(
281-
descriptor: SerialDescriptor,
282-
index: Int
278+
descriptor: SerialDescriptor, index: Int
283279
): Float {
284280
return java.lang.Float.intBitsToFloat(readIntPos())
285281
}
286282

287283
override fun decodeDoubleElement(
288-
descriptor: SerialDescriptor,
289-
index: Int
284+
descriptor: SerialDescriptor, index: Int
290285
): Double {
291286
return java.lang.Double.longBitsToDouble(readLongPos())
292287
}
293288

294289
override fun decodeStringElement(
295-
descriptor: SerialDescriptor,
296-
index: Int
290+
descriptor: SerialDescriptor, index: Int
297291
): String {
298292
val (len, bytesRead) = PackedUtils.decodeVarInt(input, position)
299293
position += bytesRead
300294
require(len >= 0 && position + len <= input.size) {
301-
"Unexpected EOF while decoding String element at index $index: need $len bytes from position=$position, size=${input.size}"
295+
"Unexpected EOF while decoding String element at index $index: " + "need $len bytes from position=$position, size=${input.size}"
302296
}
303297
val bytes = input.copyOfRange(position, position + len)
304298
position += len
@@ -307,8 +301,7 @@ class PackedDecoder(
307301

308302
@ExperimentalSerializationApi
309303
override fun decodeInlineElement(
310-
descriptor: SerialDescriptor,
311-
index: Int
304+
descriptor: SerialDescriptor, index: Int
312305
): Decoder {
313306
currentIndex = index
314307
return this
@@ -324,12 +317,7 @@ class PackedDecoder(
324317

325318
if (!deserializer.descriptor.isInline) {
326319
val kind = deserializer.descriptor.kind
327-
if (kind is StructureKind.CLASS ||
328-
kind is StructureKind.OBJECT ||
329-
kind is StructureKind.LIST ||
330-
kind is StructureKind.MAP ||
331-
kind is PolymorphicKind
332-
) {
320+
if (kind is StructureKind.CLASS || kind is StructureKind.OBJECT || kind is StructureKind.LIST || kind is StructureKind.MAP || kind is PolymorphicKind) {
333321
error("Nested objects/collections are not supported")
334322
}
335323
}
@@ -407,8 +395,7 @@ class PackedDecoder(
407395
"Invalid UTF-8 continuation byte: 0x${b1.toString(16)}"
408396
}
409397
val codePoint =
410-
((b0 and 0b0001_1111) shl 6) or
411-
(b1 and 0b0011_1111)
398+
((b0 and 0b0001_1111) shl 6) or (b1 and 0b0011_1111)
412399
2 to codePoint
413400
}
414401

@@ -419,19 +406,22 @@ class PackedDecoder(
419406
}
420407
val b1 = input[position + 1].toInt() and 0xFF
421408
val b2 = input[position + 2].toInt() and 0xFF
422-
require((b1 and 0b1100_0000) == 0b1000_0000 &&
423-
(b2 and 0b1100_0000) == 0b1000_0000) {
409+
require(
410+
(b1 and 0b1100_0000) == 0b1000_0000 && (b2 and 0b1100_0000) == 0b1000_0000
411+
) {
424412
"Invalid UTF-8 continuation byte in 3-byte char"
425413
}
426414
val codePoint =
427-
((b0 and 0b0000_1111) shl 12) or
428-
((b1 and 0b0011_1111) shl 6) or
429-
(b2 and 0b0011_1111)
415+
((b0 and 0b0000_1111) shl 12) or ((b1 and 0b0011_1111) shl 6) or (b2 and 0b0011_1111)
430416
3 to codePoint
431417
}
432418

433419
else -> throw IllegalArgumentException(
434-
"UTF-8 sequence too long for Char (leading byte: 0x${b0.toString(16)})"
420+
"UTF-8 sequence too long for Char (leading byte: 0x${
421+
b0.toString(
422+
16
423+
)
424+
})"
435425
)
436426
}
437427

0 commit comments

Comments
 (0)