0
# Encoding System
1
2
The encoding system provides format-agnostic interfaces for serializing and deserializing data. Format implementations use these interfaces to read and write data without being tied to specific serialization formats.
3
4
## Encoder Interfaces
5
6
### Encoder
7
8
Base interface for encoding primitive values and beginning structured encoding.
9
10
```kotlin { .api }
11
interface Encoder {
12
val serializersModule: SerializersModule
13
14
// Primitive encoding methods
15
fun encodeBoolean(value: Boolean)
16
fun encodeByte(value: Byte)
17
fun encodeShort(value: Short)
18
fun encodeInt(value: Int)
19
fun encodeLong(value: Long)
20
fun encodeFloat(value: Float)
21
fun encodeDouble(value: Double)
22
fun encodeChar(value: Char)
23
fun encodeString(value: String)
24
25
// Special encoding methods
26
fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int)
27
fun encodeInline(descriptor: SerialDescriptor): Encoder
28
29
// Nullable handling (experimental)
30
@ExperimentalSerializationApi
31
fun encodeNotNullMark()
32
@ExperimentalSerializationApi
33
fun encodeNull()
34
35
// Structure encoding
36
fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder
37
fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder
38
39
// Serialization helpers
40
fun <T : Any?> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T)
41
42
@ExperimentalSerializationApi
43
fun <T : Any> encodeNullableSerializableValue(
44
serializer: SerializationStrategy<T>,
45
value: T?
46
)
47
}
48
```
49
50
### CompositeEncoder
51
52
Interface for encoding structured data with multiple elements.
53
54
```kotlin { .api }
55
interface CompositeEncoder {
56
val serializersModule: SerializersModule
57
58
// Element encoding methods for primitives
59
fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean)
60
fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte)
61
fun encodeShortElement(descriptor: SerialDescriptor, index: Int, value: Short)
62
fun encodeIntElement(descriptor: SerialDescriptor, index: Int, value: Int)
63
fun encodeLongElement(descriptor: SerialDescriptor, index: Int, value: Long)
64
fun encodeFloatElement(descriptor: SerialDescriptor, index: Int, value: Float)
65
fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double)
66
fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char)
67
fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String)
68
69
// Complex element encoding
70
fun <T : Any?> encodeSerializableElement(
71
descriptor: SerialDescriptor,
72
index: Int,
73
serializer: SerializationStrategy<T>,
74
value: T
75
)
76
77
@ExperimentalSerializationApi
78
fun <T : Any> encodeNullableSerializableElement(
79
descriptor: SerialDescriptor,
80
index: Int,
81
serializer: SerializationStrategy<T>,
82
value: T?
83
)
84
85
// Inline element encoding
86
fun encodeInlineElement(descriptor: SerialDescriptor, index: Int): Encoder
87
88
// Structure control
89
fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder
90
fun endStructure(descriptor: SerialDescriptor)
91
92
// Encoding behavior control
93
@ExperimentalSerializationApi
94
fun shouldEncodeElementDefault(descriptor: SerialDescriptor, index: Int): Boolean
95
}
96
```
97
98
## Decoder Interfaces
99
100
### Decoder
101
102
Base interface for decoding primitive values and beginning structured decoding.
103
104
```kotlin { .api }
105
interface Decoder {
106
val serializersModule: SerializersModule
107
108
// Primitive decoding methods
109
fun decodeBoolean(): Boolean
110
fun decodeByte(): Byte
111
fun decodeShort(): Short
112
fun decodeInt(): Int
113
fun decodeLong(): Long
114
fun decodeFloat(): Float
115
fun decodeDouble(): Double
116
fun decodeChar(): Char
117
fun decodeString(): String
118
119
// Special decoding methods
120
fun decodeEnum(enumDescriptor: SerialDescriptor): Int
121
fun decodeInline(descriptor: SerialDescriptor): Decoder
122
123
// Nullable handling (experimental)
124
@ExperimentalSerializationApi
125
fun decodeNotNullMark(): Boolean
126
@ExperimentalSerializationApi
127
fun decodeNull(): Nothing?
128
129
// Structure decoding
130
fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder
131
132
// Serialization helpers
133
fun <T : Any?> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T
134
135
@ExperimentalSerializationApi
136
fun <T : Any> decodeNullableSerializableValue(
137
deserializer: DeserializationStrategy<T?>
138
): T?
139
}
140
```
141
142
### CompositeDecoder
143
144
Interface for decoding structured data with multiple elements.
145
146
```kotlin { .api }
147
interface CompositeDecoder {
148
val serializersModule: SerializersModule
149
150
// Element discovery
151
fun decodeElementIndex(descriptor: SerialDescriptor): Int
152
fun decodeCollectionSize(descriptor: SerialDescriptor): Int
153
154
@ExperimentalSerializationApi
155
fun decodeSequentially(): Boolean
156
157
// Element decoding methods for primitives
158
fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int): Boolean
159
fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte
160
fun decodeShortElement(descriptor: SerialDescriptor, index: Int): Short
161
fun decodeIntElement(descriptor: SerialDescriptor, index: Int): Int
162
fun decodeLongElement(descriptor: SerialDescriptor, index: Int): Long
163
fun decodeFloatElement(descriptor: SerialDescriptor, index: Int): Float
164
fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int): Double
165
fun decodeCharElement(descriptor: SerialDescriptor, index: Int): Char
166
fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String
167
168
// Complex element decoding
169
fun <T : Any?> decodeSerializableElement(
170
descriptor: SerialDescriptor,
171
index: Int,
172
deserializer: DeserializationStrategy<T>,
173
previousValue: T? = null
174
): T
175
176
@ExperimentalSerializationApi
177
fun <T : Any> decodeNullableSerializableElement(
178
descriptor: SerialDescriptor,
179
index: Int,
180
deserializer: DeserializationStrategy<T?>,
181
previousValue: T? = null
182
): T?
183
184
// Inline element decoding
185
fun decodeInlineElement(descriptor: SerialDescriptor, index: Int): Decoder
186
187
// Structure control
188
fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder
189
fun endStructure(descriptor: SerialDescriptor)
190
191
companion object {
192
const val DECODE_DONE: Int = -1
193
const val UNKNOWN_NAME: Int = -3
194
}
195
}
196
```
197
198
## Encoding Usage Examples
199
200
### Basic Encoder Implementation
201
202
```kotlin
203
class CustomEncoder : Encoder {
204
override val serializersModule: SerializersModule = EmptySerializersModule()
205
206
override fun encodeString(value: String) {
207
// Custom string encoding logic
208
println("Encoding string: $value")
209
}
210
211
override fun encodeInt(value: Int) {
212
// Custom integer encoding logic
213
println("Encoding int: $value")
214
}
215
216
override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder {
217
println("Beginning structure: ${descriptor.serialName}")
218
return CustomCompositeEncoder()
219
}
220
221
// ... implement other required methods
222
}
223
```
224
225
### Basic Decoder Implementation
226
227
```kotlin
228
class CustomDecoder(private val data: Map<String, Any>) : Decoder {
229
override val serializersModule: SerializersModule = EmptySerializersModule()
230
231
override fun decodeString(): String {
232
// Custom string decoding logic
233
return data["current"] as String
234
}
235
236
override fun decodeInt(): Int {
237
// Custom integer decoding logic
238
return data["current"] as Int
239
}
240
241
override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
242
println("Beginning structure: ${descriptor.serialName}")
243
return CustomCompositeDecoder(data)
244
}
245
246
// ... implement other required methods
247
}
248
```
249
250
### Composite Encoding Pattern
251
252
```kotlin
253
class CustomCompositeEncoder : CompositeEncoder {
254
override val serializersModule: SerializersModule = EmptySerializersModule()
255
256
override fun encodeStringElement(
257
descriptor: SerialDescriptor,
258
index: Int,
259
value: String
260
) {
261
val elementName = descriptor.getElementName(index)
262
println("Encoding element '$elementName' at index $index: $value")
263
}
264
265
override fun <T> encodeSerializableElement(
266
descriptor: SerialDescriptor,
267
index: Int,
268
serializer: SerializationStrategy<T>,
269
value: T
270
) {
271
val elementName = descriptor.getElementName(index)
272
println("Encoding serializable element '$elementName' at index $index")
273
274
// Create nested encoder for the element
275
val elementEncoder = createNestedEncoder()
276
serializer.serialize(elementEncoder, value)
277
}
278
279
override fun endStructure(descriptor: SerialDescriptor) {
280
println("Ending structure: ${descriptor.serialName}")
281
}
282
283
// ... implement other required methods
284
}
285
```
286
287
### Composite Decoding Pattern
288
289
```kotlin
290
class CustomCompositeDecoder(
291
private val data: Map<String, Any>
292
) : CompositeDecoder {
293
override val serializersModule: SerializersModule = EmptySerializersModule()
294
private var currentIndex = 0
295
296
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
297
// Return next available element index or DECODE_DONE when finished
298
return if (currentIndex < descriptor.elementsCount) {
299
currentIndex++
300
} else {
301
CompositeDecoder.DECODE_DONE
302
}
303
}
304
305
override fun decodeStringElement(
306
descriptor: SerialDescriptor,
307
index: Int
308
): String {
309
val elementName = descriptor.getElementName(index)
310
return data[elementName] as String
311
}
312
313
override fun <T> decodeSerializableElement(
314
descriptor: SerialDescriptor,
315
index: Int,
316
deserializer: DeserializationStrategy<T>,
317
previousValue: T?
318
): T {
319
val elementName = descriptor.getElementName(index)
320
val elementData = data[elementName] as Map<String, Any>
321
322
// Create nested decoder for the element
323
val elementDecoder = CustomDecoder(elementData)
324
return deserializer.deserialize(elementDecoder)
325
}
326
327
// ... implement other required methods
328
}
329
```
330
331
## Advanced Encoding Features
332
333
### Inline Value Handling
334
335
```kotlin
336
// In custom encoder
337
override fun encodeInline(descriptor: SerialDescriptor): Encoder {
338
// Return encoder for inline value content
339
return this // or create specialized inline encoder
340
}
341
342
// In custom decoder
343
override fun decodeInline(descriptor: SerialDescriptor): Decoder {
344
// Return decoder for inline value content
345
return this // or create specialized inline decoder
346
}
347
```
348
349
### Null Handling
350
351
```kotlin
352
// Encoding nulls
353
override fun encodeNull() {
354
println("Encoding null value")
355
}
356
357
override fun encodeNotNullMark() {
358
println("Encoding not-null marker")
359
}
360
361
// Decoding nulls
362
override fun decodeNotNullMark(): Boolean {
363
// Return true if next value is not null
364
return true
365
}
366
367
override fun decodeNull(): Nothing? {
368
println("Decoding null value")
369
return null
370
}
371
```
372
373
### Default Value Handling
374
375
```kotlin
376
// In CompositeEncoder
377
override fun shouldEncodeElementDefault(
378
descriptor: SerialDescriptor,
379
index: Int
380
): Boolean {
381
// Control whether default values should be encoded
382
val elementName = descriptor.getElementName(index)
383
return !elementName.startsWith("optional")
384
}
385
```
386
387
## Extension Functions
388
389
### Encoder Extensions
390
391
```kotlin { .api }
392
// Structure encoding helpers
393
inline fun Encoder.encodeStructure(
394
descriptor: SerialDescriptor,
395
crossinline block: CompositeEncoder.() -> Unit
396
)
397
398
inline fun Encoder.encodeCollection(
399
descriptor: SerialDescriptor,
400
collectionSize: Int,
401
crossinline block: CompositeEncoder.() -> Unit
402
)
403
404
inline fun <E> Encoder.encodeCollection(
405
descriptor: SerialDescriptor,
406
collection: Collection<E>,
407
crossinline block: CompositeEncoder.(index: Int, E) -> Unit
408
)
409
```
410
411
### Decoder Extensions
412
413
```kotlin { .api }
414
// Structure decoding helpers
415
inline fun <T> Decoder.decodeStructure(
416
descriptor: SerialDescriptor,
417
crossinline block: CompositeDecoder.() -> T
418
): T
419
```
420
421
## Format Implementation Tips
422
423
1. **Stateful Encoders/Decoders**: Maintain state for tracking current position, nesting levels, etc.
424
2. **Error Handling**: Throw descriptive `SerializationException`s for format-specific errors
425
3. **Performance**: Cache frequently accessed data like element names and descriptors
426
4. **Validation**: Validate data structure matches descriptor expectations
427
5. **Null Safety**: Properly handle nullable types and null markers