KEncode turns your data into short strings. It's useful when you need to fit data into a URL, a file name, a Kubernetes label, or anywhere else with a tight length limit.
There are three parts. ByteEncoding turns bytes into text. PackedFormat turns your Kotlin classes into as few bytes as possible. EncodedFormat does both, so you go straight from an object to a short string. If you want to know how it works, read the technical deep dive.
dependencies {
implementation("com.eignex:kencode:1.4.0")
}You also need the kotlinx.serialization plugin to use the formats.
@Serializable
data class Payload(
@PackedType(IntPacking.DEFAULT) val id: ULong, // varint
@PackedType(IntPacking.SIGNED) val delta: Int, // zigzag
val urgent: Boolean, // 1 bit
val handled: Instant?, // 1 bit when null
val type: PayloadType, // 2 bits
)
enum class PayloadType { TYPE1, TYPE2, TYPE3 }
val payload = Payload(123u, -2, true, null, PayloadType.TYPE1)
val encoded = EncodedFormat.encodeToString(payload) // "00Xl1", 3 raw bytes
val decoded = EncodedFormat.decodeFromString<Payload>(encoded)PackedFormat stores booleans, nulls, and enums in just a few bits each. Numbers are stored in as few bytes as they need. Add PackedType to a field if it is often negative (SIGNED) or if you want a fixed size (FIXED).
val format = PackedFormat {
defaultEncoding = IntPacking.FIXED
serializersModule = myCustomModule
}
val bytes = format.encodeToByteArray(payload)Fields are written in the order you declare them, with no names or tags. So if you change a class, old strings may no longer decode.
The encoded format only stays the same between patch versions. A new minor version may change it, so encode stored strings again after upgrading.
EncodedFormat serializes your object, optionally transforms the bytes, and then turns them into text. You can swap each step. For example, you can use ProtoBuf instead of PackedFormat, add a checksum, or pick a different codec.
val format = EncodedFormat {
codec = Base36
checksum = Crc16
binaryFormat = ProtoBuf
}
val compacted = EncodedFormat {
transform = CompactZeros.then(Crc16.asTransform())
}You can also write your own transforms, like these examples for encryption and error correction.
Every codec can be used on its own, and you can give it your own alphabet. Here is what the text "any byte data" (13 bytes) looks like in each:
| Codec | Output | Length | Alphabet |
|---|---|---|---|
| Base62 | 2BVj6VHhfNlsGmoMQF |
18 | [0-9A-Za-z] |
| Base36 | 0ksef5o4kvegb70nre15t |
21 | [0-9a-z] |
| Base64 | YW55IGJ5dGUgZGF0YQ== |
20 | [0-9A-Za-z+/=] |
| Base85 | @;^?5@X3',+Cno&@/ |
17 | ASCII 33–117 |
For even shorter strings, BaseRadix can use a large range of Unicode characters.