@@ -17,6 +17,11 @@ stable, these are currently experimental features of Kotlin Serialization.
1717 * [ Tags and Labels] ( #tags-and-labels )
1818 * [ Arrays] ( #arrays )
1919 * [ Custom CBOR-specific Serializers] ( #custom-cbor-specific-serializers )
20+ * [ CBOR Elements] ( #cbor-elements )
21+ * [ Encoding from/to ` CborElement ` ] ( #encoding-fromto-cborelement )
22+ * [ Tagging ` CborElement ` s] ( #tagging-cborelements )
23+ * [ Caution] ( #caution )
24+ * [ Types of CBOR Elements] ( #types-of-cbor-elements )
2025* [ ProtoBuf (experimental)] ( #protobuf-experimental )
2126 * [ Field numbers] ( #field-numbers )
2227 * [ Integer types] ( #integer-types )
@@ -308,13 +313,125 @@ When annotated with `@CborArray`, serialization of the same object will produce
308313```
309314This may be used to encode COSE structures, see [ RFC 9052 2. Basic COSE Structure] ( https://www.rfc-editor.org/rfc/rfc9052#section-2 ) .
310315
311-
312316### Custom CBOR-specific Serializers
313317Cbor encoders and decoders implement the interfaces [ CborEncoder] ( CborEncoder.kt ) and [ CborDecoder] ( CborDecoder.kt ) , respectively.
314318These interfaces contain a single property, ` cbor ` , exposing the current CBOR serialization configuration.
315319This enables custom cbor-specific serializers to reuse the current ` Cbor ` instance to produce embedded byte arrays or
316320react to configuration settings such as ` preferCborLabelsOverNames ` or ` useDefiniteLengthEncoding ` , for example.
317321
322+
323+ ### CBOR Elements
324+
325+ Aside from direct conversions between bytearray and CBOR objects, Kotlin serialization offers APIs that allow
326+ other ways of working with CBOR in the code. For example, you might need to tweak the data before it can parse
327+ or otherwise work with such unstructured data that it does not readily fit into the typesafe world of Kotlin
328+ serialization.
329+
330+ The main concept in this part of the library is [ CborElement] . Read on to learn what you can do with it.
331+
332+ #### Encoding from/to ` CborElement `
333+
334+ Bytes can be decoded into an instance of ` CborElement ` with the [ Cbor.decodeFromByteArray] function by either manually
335+ specifying [ CborElement.serializer()] or specifying [ CborElement] as generic type parameter.
336+ It is also possible to encode arbitrary serializable structures to a ` CborElement ` through [ Cbor.encodeToCborElement] .
337+
338+ Since these operations use the same code paths as regular serialization (but with specialized serializers), the config flags
339+ behave as expected:
340+
341+ ``` kotlin
342+ fun main () {
343+ val element: CborElement = Cbor .decodeFromHexString(" a165627974657343666f6f" )
344+ println (element)
345+ }
346+ ```
347+
348+ The above snippet will print the following diagnostic notation
349+
350+ ``` text
351+ CborMap(tags=[], content={CborString(tags=[], value=bytes)=CborByteString(tags=[], value=h'666f6f)})
352+ ```
353+
354+ #### Tagging ` CborElement ` s
355+
356+ Every CborElement—whether it is used as a property, a value inside a collection, or even a complex key inside a map
357+ (which is perfectly legal in CBOR)—supports tags. Tags can be specified by passing them s varargs parameters upon
358+ CborElement creation.
359+ For example, take following structure (represented in diagnostic notation):
360+
361+ <!-- - TEST -->
362+
363+ ``` hexdump
364+ bf # map(*)
365+ 61 # text(1)
366+ 61 # "a"
367+ cc # tag(12)
368+ 1a 0fffffff # unsigned(268,435,455)
369+ d8 22 # base64 encoded text, tag(34)
370+ 61 # text(1)
371+ 62 # "b"
372+ # invalid length at 0 for base64
373+ 20 # negative(-1)
374+ d8 38 # tag(56)
375+ 61 # text(1)
376+ 63 # "c"
377+ d8 4e # typed array of i32, little endian, twos-complement, tag(78)
378+ 42 # bytes(2)
379+ cafe # "\xca\xfe"
380+ # invalid data length for typed array
381+ 61 # text(1)
382+ 64 # "d"
383+ d8 5a # tag(90)
384+ cc # tag(12)
385+ 6b # text(11)
386+ 48656c6c6f20576f726c64 # "Hello World"
387+ ff # break
388+ ```
389+
390+ Decoding it results in the following CborElement (shown in manually formatted diagnostic notation):
391+
392+ ```
393+ CborMap(tags=[], content={
394+ CborString(tags=[], value=a) = CborPositiveInt( tags=[12], value=268435455),
395+ CborString(tags=[34], value=b) = CborNegativeInt( tags=[], value=-1),
396+ CborString(tags=[56], value=c) = CborByteString( tags=[78], value=h'cafe),
397+ CborString(tags=[], value=d) = CborString( tags=[90, 12], value=Hello World)
398+ })
399+ ```
400+
401+ ##### Caution
402+
403+ Tags are properties of ` CborElements ` , and it is possible to mixing arbitrary serializable values with ` CborElement ` s that
404+ contain tags inside a serializable structure. It is also possible to annotate any [ CborElement] property
405+ of a generic serializable class with ` @ValueTags ` .
406+ ** This can lead to asymmetric behavior when serializing and deserializing such structures!**
407+
408+ #### Types of CBOR Elements
409+
410+ A [ CborElement] class has three direct subtypes, closely following CBOR grammar:
411+
412+ * [ CborPrimitive] represents primitive CBOR elements, such as string, integer, float boolean, and null.
413+ CBOR byte strings are also treated as primitives
414+ Each primitive has a [ value] [ CborPrimitive.value ] . Depending on the concrete type of the primitive, it maps
415+ to corresponding Kotlin Types such as ` String ` , ` Int ` , ` Double ` , etc.
416+ Note that Cbor discriminates between positive ("unsigned") and negative ("signed") integers!
417+ ` CborPrimitive ` is itself an umbrella type (a sealed class) for the following concrete primitives:
418+ * [ CborNull] mapping to a Kotlin ` null `
419+ * [ CborBoolean] mapping to a Kotlin ` Boolean `
420+ * [ CborInt] which is an umbrella type (a sealed class) itself for the following concrete types
421+ (it is still possible to instantiate it as the ` invoke ` operator on its companion is overridden accordingly):
422+ * [ CborPositiveInt] represents all ` Long ` numbers ` ≥0 `
423+ * [ CborNegativeInt] represents all ` Long ` numbers ` <0 `
424+ * [ CborString] maps to a Kotlin ` String `
425+ * [ CborFloat] maps to Kotlin ` Double `
426+ * [ CborByteString] maps to a Kotlin ` ByteArray ` and is used to encode them as CBOR byte string (in contrast to a list
427+ of individual bytes)
428+
429+ * [ CborList] represents a CBOR array. It is a Kotlin [ List] of ` CborElement ` items.
430+
431+ * [ CborMap] represents a CBOR map/object. It is a Kotlin [ Map] from ` CborElement ` keys to ` CborElement ` values.
432+ This is typically the result of serializing an arbitrary
433+
434+
318435## ProtoBuf (experimental)
319436
320437[ Protocol Buffers] ( https://developers.google.com/protocol-buffers ) is a language-neutral binary format that normally
@@ -1673,5 +1790,19 @@ This chapter concludes [Kotlin Serialization Guide](serialization-guide.md).
16731790[ Cbor.decodeFromByteArray ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor/decode-from-byte-array.html
16741791[ CborBuilder.ignoreUnknownKeys ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-builder/ignore-unknown-keys.html
16751792[ ByteString ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-byte-string/index.html
1793+ [ CborElement ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-element/index.html
1794+ [ Cbor.encodeToCborElement ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/encode-to-cbor-element.html
1795+ [ CborPrimitive ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-primitive/index.html
1796+ [ CborPrimitive.value ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-primitive/value.html
1797+ [ CborNull ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-null/index.html
1798+ [ CborBoolean ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-boolean/index.html
1799+ [ CborInt ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-int/index.html
1800+ [ CborPositiveInt ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-positive-int/index.html
1801+ [ CborNegativeInt ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-negative-int/index.html
1802+ [ CborString ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-string/index.html
1803+ [ CborFloat ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-float/index.html
1804+ [ CborByteString ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-byte-string/index.html
1805+ [ CborList ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-list/index.html
1806+ [ CborMap ] : https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-map/index.html
16761807
16771808<!-- - END -->
0 commit comments