1 /*
<lambda>null2 * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3 */
4
5 package kotlinx.serialization.encoding
6
7 import kotlinx.serialization.*
8 import kotlinx.serialization.builtins.*
9 import kotlinx.serialization.descriptors.*
10 import kotlinx.serialization.modules.*
11
12 /**
13 * Encoder is a core serialization primitive that encapsulates the knowledge of the underlying
14 * format and its storage, exposing only structural methods to the serializer, making it completely
15 * format-agnostic. Serialization process transforms a single value into the sequence of its
16 * primitive elements, also called its serial form, while encoding transforms these primitive elements into an actual
17 * format representation: JSON string, ProtoBuf ByteArray, in-memory map representation etc.
18 *
19 * Encoder provides high-level API that operates with basic primitive types, collections
20 * and nested structures. Internally, encoder represents output storage and operates with its state
21 * and lower level format-specific details.
22 *
23 * To be more specific, serialization transforms a value into a sequence of "here is an int, here is
24 * a double, here a list of strings and here is another object that is a nested int", while encoding
25 * transforms this sequence into a format-specific commands such as "insert opening curly bracket
26 * for a nested object start, insert a name of the value, and the value separated with colon for an int etc."
27 *
28 * The symmetric interface for the deserialization process is [Decoder].
29 *
30 * ### Serialization. Primitives
31 *
32 * If a class is represented as a single [primitive][PrimitiveKind] value in its serialized form,
33 * then one of the `encode*` methods (e.g. [encodeInt]) can be used directly.
34 *
35 * ### Serialization. Structured types.
36 *
37 * If a class is represented as a structure or has multiple values in its serialized form,
38 * `encode*` methods are not that helpful, because they do not allow working with collection types or establish structure boundaries.
39 * All these capabilities are delegated to the [CompositeEncoder] interface with a more specific API surface.
40 * To denote a structure start, [beginStructure] should be used.
41 * ```
42 * // Denote the structure start,
43 * val composite = encoder.beginStructure(descriptor)
44 * // Encoding all elements within the structure using 'composite'
45 * ...
46 * // Denote the structure end
47 * composite.endStructure(descriptor)
48 * ```
49 *
50 * E.g. if the encoder belongs to JSON format, then [beginStructure] will write an opening bracket
51 * (`{` or `[`, depending on the descriptor kind), returning the [CompositeEncoder] that is aware of colon separator,
52 * that should be appended between each key-value pair, whilst [CompositeEncoder.endStructure] will write a closing bracket.
53 *
54 * ### Exception guarantees.
55 * For the regular exceptions, such as invalid input, conflicting serial names,
56 * [SerializationException] can be thrown by any encoder methods.
57 * It is recommended to declare a format-specific subclass of [SerializationException] and throw it.
58 *
59 * ### Format encapsulation
60 *
61 * For example, for the following serializer:
62 * ```
63 * class StringHolder(val stringValue: String)
64 *
65 * object StringPairDeserializer : SerializationStrategy<StringHolder> {
66 * override val descriptor = ...
67 *
68 * override fun serializer(encoder: Encoder, value: StringHolder) {
69 * // Denotes start of the structure, StringHolder is not a "plain" data type
70 * val composite = encoder.beginStructure(descriptor)
71 * // Encode the nested string value
72 * composite.encodeStringElement(descriptor, index = 0)
73 * // Denotes end of the structure
74 * composite.endStructure(descriptor)
75 * }
76 * }
77 * ```
78 *
79 * This serializer does not know anything about the underlying storage and will work with any properly-implemented encoder.
80 * JSON, for example, writes an opening bracket `{` during the `beginStructure` call, writes 'stringValue` key along
81 * with its value in `encodeStringElement` and writes the closing bracket `}` during the `endStructure`.
82 * XML would do roughly the same, but with different separators and structures, while ProtoBuf
83 * machinery could be completely different.
84 * In any case, all these parsing details are encapsulated by an encoder.
85 *
86 * ### Exception safety
87 *
88 * In general, catching [SerializationException] from any of `encode*` methods is not allowed and produces unspecified behaviour.
89 * After thrown exception, current encoder is left in an arbitrary state, no longer suitable for further encoding.
90 *
91 * ### Encoder implementation.
92 *
93 * While being strictly typed, an underlying format can transform actual types in the way it wants.
94 * For example, a format can support only string types and encode/decode all primitives in a string form:
95 * ```
96 * StringFormatEncoder : Encoder {
97 *
98 * ...
99 * override fun encodeDouble(value: Double) = encodeString(value.toString())
100 * override fun encodeInt(value: Int) = encodeString(value.toString())
101 * ...
102 * }
103 * ```
104 *
105 * ### Not stable for inheritance
106 *
107 * `Encoder` interface is not stable for inheritance in 3rd party libraries, as new methods
108 * might be added to this interface or contracts of the existing methods can be changed.
109 */
110 public interface Encoder {
111 /**
112 * Context of the current serialization process, including contextual and polymorphic serialization and,
113 * potentially, a format-specific configuration.
114 */
115 public val serializersModule: SerializersModule
116
117 /**
118 * Notifies the encoder that value of a nullable type that is
119 * being serialized is not null. It should be called before writing a non-null value
120 * of nullable type:
121 * ```
122 * // Could be String? serialize method
123 * if (value != null) {
124 * encoder.encodeNotNullMark()
125 * encoder.encodeStringValue(value)
126 * } else {
127 * encoder.encodeNull()
128 * }
129 * ```
130 *
131 * This method has a use in highly-performant binary formats and can
132 * be safely ignore by most of the regular formats.
133 */
134 @ExperimentalSerializationApi
135 public fun encodeNotNullMark() {}
136
137 /**
138 * Encodes `null` value.
139 */
140 @ExperimentalSerializationApi
141 public fun encodeNull()
142
143 /**
144 * Encodes a boolean value.
145 * Corresponding kind is [PrimitiveKind.BOOLEAN].
146 */
147 public fun encodeBoolean(value: Boolean)
148
149 /**
150 * Encodes a single byte value.
151 * Corresponding kind is [PrimitiveKind.BYTE].
152 */
153 public fun encodeByte(value: Byte)
154
155 /**
156 * Encodes a 16-bit short value.
157 * Corresponding kind is [PrimitiveKind.SHORT].
158 */
159 public fun encodeShort(value: Short)
160
161 /**
162 * Encodes a 16-bit unicode character value.
163 * Corresponding kind is [PrimitiveKind.CHAR].
164 */
165 public fun encodeChar(value: Char)
166
167 /**
168 * Encodes a 32-bit integer value.
169 * Corresponding kind is [PrimitiveKind.INT].
170 */
171 public fun encodeInt(value: Int)
172
173 /**
174 * Encodes a 64-bit integer value.
175 * Corresponding kind is [PrimitiveKind.LONG].
176 */
177 public fun encodeLong(value: Long)
178
179 /**
180 * Encodes a 32-bit IEEE 754 floating point value.
181 * Corresponding kind is [PrimitiveKind.FLOAT].
182 */
183 public fun encodeFloat(value: Float)
184
185 /**
186 * Encodes a 64-bit IEEE 754 floating point value.
187 * Corresponding kind is [PrimitiveKind.DOUBLE].
188 */
189 public fun encodeDouble(value: Double)
190
191 /**
192 * Encodes a string value.
193 * Corresponding kind is [PrimitiveKind.STRING].
194 */
195 public fun encodeString(value: String)
196
197 /**
198 * Encodes a enum value that is stored at the [index] in [enumDescriptor] elements collection.
199 * Corresponding kind is [SerialKind.ENUM].
200 *
201 * E.g. for the enum `enum class Letters { A, B, C, D }` and
202 * serializable value "C", [encodeEnum] method should be called with `2` as am index.
203 *
204 * This method does not imply any restrictions on the output format,
205 * the format is free to store the enum by its name, index, ordinal or any other
206 */
207 public fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int)
208
209 /**
210 * Returns [Encoder] for encoding an underlying type of a value class in an inline manner.
211 * [descriptor] describes a serializable value class.
212 *
213 * Namely, for the `@Serializable @JvmInline value class MyInt(val my: Int)`,
214 * the following sequence is used:
215 * ```
216 * thisEncoder.encodeInline(MyInt.serializer().descriptor).encodeInt(my)
217 * ```
218 *
219 * Current encoder may return any other instance of [Encoder] class, depending on the provided [descriptor].
220 * For example, when this function is called on Json encoder with `UInt.serializer().descriptor`, the returned encoder is able
221 * to encode unsigned integers.
222 *
223 * Note that this function returns [Encoder] instead of the [CompositeEncoder]
224 * because value classes always have the single property.
225 * Calling [Encoder.beginStructure] on returned instance leads to an unspecified behavior and, in general, is prohibited.
226 */
227 public fun encodeInline(descriptor: SerialDescriptor): Encoder
228
229 /**
230 * Encodes the beginning of the nested structure in a serialized form
231 * and returns [CompositeDecoder] responsible for encoding this very structure.
232 * E.g the hierarchy:
233 * ```
234 * class StringHolder(val stringValue: String)
235 * class Holder(val stringHolder: StringHolder)
236 * ```
237 *
238 * with the following serialized form in JSON:
239 * ```
240 * {
241 * "stringHolder" : { "stringValue": "value" }
242 * }
243 * ```
244 *
245 * will be roughly represented as the following sequence of calls:
246 * ```
247 * // Holder serializer
248 * fun serialize(encoder: Encoder, value: Holder) {
249 * val composite = encoder.beginStructure(descriptor) // the very first opening bracket '{'
250 * composite.encodeSerializableElement(descriptor, 0, value.stringHolder) // Serialize nested StringHolder
251 * composite.endStructure(descriptor) // The very last closing bracket
252 * }
253 *
254 * // StringHolder serializer
255 * fun serialize(encoder: Encoder, value: StringHolder) {
256 * val composite = encoder.beginStructure(descriptor) // One more '{' when the key "stringHolder" is already written
257 * composite.encodeStringElement(descriptor, 0, value.stringValue) // Serialize actual value
258 * composite.endStructure(descriptor) // Closing bracket
259 * }
260 * ```
261 */
262 public fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder
263
264 /**
265 * Encodes the beginning of the collection with size [collectionSize] and the given serializer of its type parameters.
266 * This method has to be implemented only if you need to know collection size in advance, otherwise, [beginStructure] can be used.
267 */
268 public fun beginCollection(
269 descriptor: SerialDescriptor,
270 collectionSize: Int
271 ): CompositeEncoder = beginStructure(descriptor)
272
273 /**
274 * Encodes the [value] of type [T] by delegating the encoding process to the given [serializer].
275 * For example, `encodeInt` call is equivalent to delegating integer encoding to [Int.serializer][Int.Companion.serializer]:
276 * `encodeSerializableValue(Int.serializer())`
277 */
278 public fun <T : Any?> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
279 serializer.serialize(this, value)
280 }
281
282 /**
283 * Encodes the nullable [value] of type [T] by delegating the encoding process to the given [serializer].
284 */
285 @Suppress("UNCHECKED_CAST")
286 @ExperimentalSerializationApi
287 public fun <T : Any> encodeNullableSerializableValue(serializer: SerializationStrategy<T>, value: T?) {
288 val isNullabilitySupported = serializer.descriptor.isNullable
289 if (isNullabilitySupported) {
290 // Instead of `serializer.serialize` to be able to intercept this
291 return encodeSerializableValue(serializer as SerializationStrategy<T?>, value)
292 }
293
294 // Else default path used to avoid allocation of NullableSerializer
295 if (value == null) {
296 encodeNull()
297 } else {
298 encodeNotNullMark()
299 encodeSerializableValue(serializer, value)
300 }
301 }
302 }
303
304 /**
305 * [CompositeEncoder] is a part of encoding process that is bound to a particular structured part of
306 * the serialized form, described by the serial descriptor passed to [Encoder.beginStructure].
307 *
308 * All `encode*` methods have `index` and `serialDescriptor` parameters with a strict semantics and constraints:
309 * * `descriptor` is always the same as one used in [Encoder.beginStructure]. While this parameter may seem redundant,
310 * it is required for efficient serialization process to avoid excessive field spilling.
311 * If you are writing your own format, you can safely ignore this parameter and use one used in `beginStructure`
312 * for simplicity.
313 * * `index` of the element being encoded. This element at this index in the descriptor should be associated with
314 * the one being written.
315 *
316 * The symmetric interface for the deserialization process is [CompositeDecoder].
317 *
318 * ### Not stable for inheritance
319 *
320 * `CompositeEncoder` interface is not stable for inheritance in 3rd party libraries, as new methods
321 * might be added to this interface or contracts of the existing methods can be changed.
322 */
323 public interface CompositeEncoder {
324 /**
325 * Context of the current serialization process, including contextual and polymorphic serialization and,
326 * potentially, a format-specific configuration.
327 */
328 public val serializersModule: SerializersModule
329
330 /**
331 * Denotes the end of the structure associated with current encoder.
332 * For example, composite encoder of JSON format will write
333 * a closing bracket in the underlying input and reduce the number of nesting for pretty printing.
334 */
endStructurenull335 public fun endStructure(descriptor: SerialDescriptor)
336
337 /**
338 * Whether the format should encode values that are equal to the default values.
339 * This method is used by plugin-generated serializers for properties with default values:
340 * ```
341 * @Serializable
342 * class WithDefault(val int: Int = 42)
343 * // serialize method
344 * if (value.int != 42 || output.shouldEncodeElementDefault(serialDesc, 0)) {
345 * encoder.encodeIntElement(serialDesc, 0, value.int);
346 * }
347 * ```
348 *
349 * This method is never invoked for properties annotated with [EncodeDefault].
350 */
351 @ExperimentalSerializationApi
352 public fun shouldEncodeElementDefault(descriptor: SerialDescriptor, index: Int): Boolean = true
353
354 /**
355 * Encodes a boolean [value] associated with an element at the given [index] in [serial descriptor][descriptor].
356 * The element at the given [index] should have [PrimitiveKind.BOOLEAN] kind.
357 */
358 public fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean)
359
360 /**
361 * Encodes a single byte [value] associated with an element at the given [index] in [serial descriptor][descriptor].
362 * The element at the given [index] should have [PrimitiveKind.BYTE] kind.
363 */
364 public fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte)
365
366 /**
367 * Encodes a 16-bit short [value] associated with an element at the given [index] in [serial descriptor][descriptor].
368 * The element at the given [index] should have [PrimitiveKind.SHORT] kind.
369 */
370 public fun encodeShortElement(descriptor: SerialDescriptor, index: Int, value: Short)
371
372 /**
373 * Encodes a 16-bit unicode character [value] associated with an element at the given [index] in [serial descriptor][descriptor].
374 * The element at the given [index] should have [PrimitiveKind.CHAR] kind.
375 */
376 public fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char)
377
378 /**
379 * Encodes a 32-bit integer [value] associated with an element at the given [index] in [serial descriptor][descriptor].
380 * The element at the given [index] should have [PrimitiveKind.INT] kind.
381 */
382 public fun encodeIntElement(descriptor: SerialDescriptor, index: Int, value: Int)
383
384 /**
385 * Encodes a 64-bit integer [value] associated with an element at the given [index] in [serial descriptor][descriptor].
386 * The element at the given [index] should have [PrimitiveKind.LONG] kind.
387 */
388 public fun encodeLongElement(descriptor: SerialDescriptor, index: Int, value: Long)
389
390 /**
391 * Encodes a 32-bit IEEE 754 floating point [value] associated with an element
392 * at the given [index] in [serial descriptor][descriptor].
393 * The element at the given [index] should have [PrimitiveKind.FLOAT] kind.
394 */
395 public fun encodeFloatElement(descriptor: SerialDescriptor, index: Int, value: Float)
396
397 /**
398 * Encodes a 64-bit IEEE 754 floating point [value] associated with an element
399 * at the given [index] in [serial descriptor][descriptor].
400 * The element at the given [index] should have [PrimitiveKind.DOUBLE] kind.
401 */
402 public fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double)
403
404 /**
405 * Encodes a string [value] associated with an element at the given [index] in [serial descriptor][descriptor].
406 * The element at the given [index] should have [PrimitiveKind.STRING] kind.
407 */
408 public fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String)
409
410 /**
411 * Returns [Encoder] for decoding an underlying type of a value class in an inline manner.
412 * Serializable value class is described by the [child descriptor][SerialDescriptor.getElementDescriptor]
413 * of given [descriptor] at [index].
414 *
415 * Namely, for the `@Serializable @JvmInline value class MyInt(val my: Int)`,
416 * and `@Serializable class MyData(val myInt: MyInt)` the following sequence is used:
417 * ```
418 * thisEncoder.encodeInlineElement(MyData.serializer.descriptor, 0).encodeInt(my)
419 * ```
420 *
421 * This method provides an opportunity for the optimization to avoid boxing of a carried value
422 * and its invocation should be equivalent to the following:
423 * ```
424 * thisEncoder.encodeSerializableElement(MyData.serializer.descriptor, 0, MyInt.serializer(), myInt)
425 * ```
426 *
427 * Current encoder may return any other instance of [Encoder] class, depending on provided descriptor.
428 * For example, when this function is called on Json encoder with descriptor that has
429 * `UInt.serializer().descriptor` at the given [index], the returned encoder is able
430 * to encode unsigned integers.
431 *
432 * Note that this function returns [Encoder] instead of the [CompositeEncoder]
433 * because value classes always have the single property.
434 * Calling [Encoder.beginStructure] on returned instance leads to an unspecified behavior and, in general, is prohibited.
435 *
436 * @see Encoder.encodeInline
437 * @see SerialDescriptor.getElementDescriptor
438 */
439 public fun encodeInlineElement(
440 descriptor: SerialDescriptor,
441 index: Int
442 ): Encoder
443
444 /**
445 * Delegates [value] encoding of the type [T] to the given [serializer].
446 * [value] is associated with an element at the given [index] in [serial descriptor][descriptor].
447 */
448 public fun <T : Any?> encodeSerializableElement(
449 descriptor: SerialDescriptor,
450 index: Int,
451 serializer: SerializationStrategy<T>,
452 value: T
453 )
454
455 /**
456 * Delegates nullable [value] encoding of the type [T] to the given [serializer].
457 * [value] is associated with an element at the given [index] in [serial descriptor][descriptor].
458 */
459 @ExperimentalSerializationApi
460 public fun <T : Any> encodeNullableSerializableElement(
461 descriptor: SerialDescriptor,
462 index: Int,
463 serializer: SerializationStrategy<T>,
464 value: T?
465 )
466 }
467
468 /**
469 * Begins a structure, encodes it using the given [block] and ends it.
470 */
471 public inline fun Encoder.encodeStructure(
472 descriptor: SerialDescriptor,
473 crossinline block: CompositeEncoder.() -> Unit
474 ) {
475 val composite = beginStructure(descriptor)
476 composite.block()
477 composite.endStructure(descriptor)
478 }
479
480 /**
481 * Begins a collection, encodes it using the given [block] and ends it.
482 */
encodeCollectionnull483 public inline fun Encoder.encodeCollection(
484 descriptor: SerialDescriptor,
485 collectionSize: Int,
486 crossinline block: CompositeEncoder.() -> Unit
487 ) {
488 val composite = beginCollection(descriptor, collectionSize)
489 composite.block()
490 composite.endStructure(descriptor)
491 }
492
493 /**
494 * Begins a collection, calls [block] with each item and ends the collections.
495 */
encodeCollectionnull496 public inline fun <E> Encoder.encodeCollection(
497 descriptor: SerialDescriptor,
498 collection: Collection<E>,
499 crossinline block: CompositeEncoder.(index: Int, E) -> Unit
500 ) {
501 encodeCollection(descriptor, collection.size) {
502 collection.forEachIndexed { index, e ->
503 block(index, e)
504 }
505 }
506 }
507