KEncode produces short, predictable text payloads for environments with strict character or length limits such as URLs, file names, Kubernetes labels, and log keys.
KEncode provides three standalone entry points:
- ByteEncoding text codecs: Base62, Base36, Base64, and Base85 encoders for raw binary data.
- PackedFormat: A binary format serializer that supports nested objects, lists, and maps. It uses bitsets for booleans and nullability to minimize overhead.
- EncodedFormat: A string format serializer that wraps the above to produce small deterministic string identifiers.
dependencies {
implementation("com.eignex:kencode:1.1.0")
}For PackedFormat and EncodedFormat you also need to load the
kotlinx.serialization plugin and core library.
Minimal example using the default EncodedFormat (Base62 + PackedFormat):
@Serializable
data class Payload(
@VarUInt val id: ULong, // low numbers are compacted
@VarInt val delta: Int, // low numbers are compacted and zigzagged to improve negative numbers
val urgent: Boolean, // Packed into bitset
val handled: Instant?, // Nullability tracked via bitset
val type: PayloadType
)
enum class PayloadType { TYPE1, TYPE2, TYPE3 }
val payload = Payload(123u, -2, true, null, PayloadType.TYPE1)
val encoded = EncodedFormat.encodeToString(payload)
// > 0fiXYI (that's it, this specific payload fits in 4 raw bytes)
val decoded = EncodedFormat.decodeFromString<Payload>(encoded)PackedFormat is a BinaryFormat designed to produce the smallest feasible payloads for Kotlin classes by moving structural metadata into a compact header.
- Bit-Packing: Booleans and nullability markers are stored in a single bit-header (about 1 bit per field).
- VarInts: Int/Long fields can be optimized using @VarUInt or @VarInt (ZigZag) annotations.
- Full Graph Support: Handles nested objects, lists, maps, and polymorphism recursively. While this is supported it will not produce as compact representations as flat structures that can pack all metadata into the same header.
val compactFormat = PackedFormat {
defaultVarInt = true // All Int/Long use VarInt by default
defaultZigZag = true // All Int/Long use ZigZag by default
serializersModule = myCustomModule
}
val bytes = PackedFormat.encodeToBytes(payload)EncodedFormat provides a StringFormat API that produces short tokens by composing three layers:
- Binary Layer: PackedFormat (default) or ProtoBuf (recommended for cross-language compatibility).
- Checksum Layer: Optional Crc16 or Crc32 appended to the binary payload.
- Text Layer: Base62 (default), Base36, Base64, or Base85.
val customFormat = EncodedFormat {
codec = Base36 // Use Base36 instead of Base62 (for lowercase)
checksum = Crc16 // Append a 2-byte checksum
binaryFormat = ProtoBuf // Use ProtoBuf instead of PackedFormat (or the compactFormat from previous example)
}
val token = customFormat.encodeToString(payload)KEncode includes standalone codecs for byte-to-text conversion. All implementations support custom alphabets.
- Base62 / Base36: Uses fixed-block encoding for predictable lengths without padding. Main use is to have 100% alpha-numeric output, with or without upper-case.
- Base85: High-density encoding (4 bytes to 5 characters).
- Base64 / Base64UrlSafe: RFC 4648 compatible.
Typical confidential payload pattern:
@Serializable
data class SecretPayload(val id: Long)
// 1. Serialize
val binary = PackedFormat.encodeToByteArray(payload)
// 2. Encrypt (e.g., AES or XTEA)
val encrypted = cipher.doFinal(binary)
// 3. Encode to Text
val token = Base62.encode(encrypted)See Examples for a BouncyCastle demo.