diff --git a/benchmark/src/jmh/kotlin/kotlinx/benchmarks/cbor/CborBaseLine.kt b/benchmark/src/jmh/kotlin/kotlinx/benchmarks/cbor/CborBaseLine.kt
index 8b71d92b7f..0b05d8f50e 100644
--- a/benchmark/src/jmh/kotlin/kotlinx/benchmarks/cbor/CborBaseLine.kt
+++ b/benchmark/src/jmh/kotlin/kotlinx/benchmarks/cbor/CborBaseLine.kt
@@ -52,6 +52,7 @@ open class CborBaseline {
}
val baseBytes = cbor.encodeToByteArray(KTestOuterMessage.serializer(), baseMessage)
+ val baseStruct = cbor.encodeToCborElement(KTestOuterMessage.serializer(), baseMessage)
@Benchmark
fun toBytes() = cbor.encodeToByteArray(KTestOuterMessage.serializer(), baseMessage)
@@ -59,4 +60,17 @@ open class CborBaseline {
@Benchmark
fun fromBytes() = cbor.decodeFromByteArray(KTestOuterMessage.serializer(), baseBytes)
+
+ @Benchmark
+ fun structToBytes() = cbor.encodeToByteArray(CborElement.serializer(), baseStruct)
+
+ @Benchmark
+ fun structFromBytes() = cbor.decodeFromByteArray(CborElement.serializer(), baseBytes)
+
+ @Benchmark
+ fun fromStruct() = cbor.decodeFromCborElement(KTestOuterMessage.serializer(), baseStruct)
+
+ @Benchmark
+ fun toStruct() = cbor.encodeToCborElement(KTestOuterMessage.serializer(), baseMessage)
+
}
diff --git a/docs/formats.md b/docs/formats.md
index ec4e6cb820..9472ee4902 100644
--- a/docs/formats.md
+++ b/docs/formats.md
@@ -17,6 +17,11 @@ stable, these are currently experimental features of Kotlin Serialization.
* [Tags and Labels](#tags-and-labels)
* [Arrays](#arrays)
* [Custom CBOR-specific Serializers](#custom-cbor-specific-serializers)
+ * [CBOR Elements](#cbor-elements)
+ * [Encoding from/to `CborElement`](#encoding-fromto-cborelement)
+ * [Tagging `CborElement`s](#tagging-cborelements)
+ * [Caution](#caution)
+ * [Types of CBOR Elements](#types-of-cbor-elements)
* [ProtoBuf (experimental)](#protobuf-experimental)
* [Field numbers](#field-numbers)
* [Integer types](#integer-types)
@@ -299,7 +304,7 @@ A2 # map(2)
F6 # primitive(22)
```
-When annotated with `@CborArray`, serialization of the same object will produce a Cbor array: bytes `0x8226F6`, or in diagnostic notation:
+When annotated with `@CborObjectAsArray`, serialization of the same object will produce a Cbor array: bytes `0x8226F6`, or in diagnostic notation:
```
82 # array(2)
@@ -308,12 +313,138 @@ When annotated with `@CborArray`, serialization of the same object will produce
```
This may be used to encode COSE structures, see [RFC 9052 2. Basic COSE Structure](https://www.rfc-editor.org/rfc/rfc9052#section-2).
-
### Custom CBOR-specific Serializers
Cbor encoders and decoders implement the interfaces [CborEncoder](CborEncoder.kt) and [CborDecoder](CborDecoder.kt), respectively.
-These interfaces contain a single property, `cbor`, exposing the current CBOR serialization configuration.
-This enables custom cbor-specific serializers to reuse the current `Cbor` instance to produce embedded byte arrays or
-react to configuration settings such as `preferCborLabelsOverNames` or `useDefiniteLengthEncoding`, for example.
+These interfaces expose the current CBOR serialization configuration through the `cbor` property.
+In addition, [CborEncoder](CborEncoder.kt) can encode a complete [CborElement] with `encodeCborElement`, and
+[CborDecoder](CborDecoder.kt) can decode the next data item as a [CborElement] with `decodeCborElement`.
+This enables custom cbor-specific serializers to reuse the current `Cbor` instance to produce embedded byte arrays,
+encode or decode a whole CBOR subtree, or react to configuration settings such as `preferCborLabelsOverNames` or
+`useDefiniteLengthEncoding`, for example.
+
+
+### CBOR Elements
+
+Aside from direct conversions between bytearray and CBOR objects, Kotlin serialization offers APIs that allow
+other ways of working with CBOR in the code. For example, you might need to tweak the data before it can parse
+or otherwise work with such unstructured data that it does not readily fit into the typesafe world of Kotlin
+serialization.
+
+The main concept in this part of the library is [CborElement]. Read on to learn what you can do with it.
+
+#### Encoding from/to `CborElement`
+
+Bytes can be decoded into an instance of `CborElement` with the [Cbor.decodeFromByteArray] function by either manually
+specifying `CborElement.serializer()` or specifying [CborElement] as generic type parameter.
+It is also possible to encode arbitrary serializable structures to a `CborElement` through [Cbor.encodeToCborElement].
+
+Since these operations use the same code paths as regular serialization (but with specialized serializers), the config flags
+behave as expected:
+
+```kotlin
+fun main() {
+ val element: CborElement = Cbor.decodeFromHexString("a165627974657343666f6f")
+ println(element)
+}
+```
+
+The above snippet will print the following diagnostic notation
+
+```text
+CborMap(tags=[], content={CborString(tags=[], value=bytes)=CborByteString(tags=[], bytes=h'666f6f)})
+```
+
+#### Tagging `CborElement`s
+
+Every CborElement—whether it is used as a property, a value inside a collection, or even a complex key inside a map
+(which is perfectly legal in CBOR)—supports tags. Tags can be specified by passing them as vararg parameters upon
+CborElement creation.
+
+When encoding raw [CborElement] instances, the usual tag configuration switches still apply. Tags on a root element,
+on an array item, or on a map value are encoded only when `encodeValueTags` is enabled. Tags on a map key are encoded
+only when `encodeKeyTags` is enabled. Decoding a [CborElement] always preserves tags present in the input.
+
+Tag and label annotations describe properties of serializable classes, while [CborElement] already models CBOR data
+directly. For that reason, `@KeyTags`, `@ValueTags`, and `@CborLabel` cannot be applied to [CborElement]-typed
+properties. Put value tags on the `CborElement.tags` array directly, and model tagged or numeric keys as [CborMap]
+keys such as `CborString("key", 42u)` or `CborInteger(1)`.
+For example, take the following structure (represented in diagnostic notation):
+
+
+
+```hexdump
+bf # map(*)
+ 61 # text(1)
+ 61 # "a"
+ cc # tag(12)
+ 1a 0fffffff # unsigned(268,435,455)
+ d8 22 # base64 encoded text, tag(34)
+ 61 # text(1)
+ 62 # "b"
+ # invalid length at 0 for base64
+ 20 # negative(-1)
+ d8 38 # tag(56)
+ 61 # text(1)
+ 63 # "c"
+ d8 4e # typed array of i32, little endian, twos-complement, tag(78)
+ 42 # bytes(2)
+ cafe # "\xca\xfe"
+ # invalid data length for typed array
+ 61 # text(1)
+ 64 # "d"
+ d8 5a # tag(90)
+ cc # tag(12)
+ 6b # text(11)
+ 48656c6c6f20576f726c64 # "Hello World"
+ ff # break
+```
+
+Decoding it results in the following CborElement (shown in manually formatted diagnostic notation):
+
+```
+CborMap(tags=[], content={
+ CborString(tags=[], value=a) = CborInt(tags=[12], absoluteValue = 268435455 ),
+ CborString(tags=[34], value=b) = CborInt(tags=[], absoluteValue = -1 ),
+ CborString(tags=[56], value=c) = CborByteString(tags=[78], bytes = h'cafe ),
+ CborString(tags=[], value=d) = CborString(tags=[90, 12], value = Hello World )
+})
+```
+
+##### Caution
+
+Tags are properties of `CborElement`s, and it is possible to mix arbitrary serializable values with `CborElement`s that
+contain tags inside a serializable structure. Be aware that raw `CborElement.tags` are controlled by `encodeKeyTags` or
+`encodeValueTags` depending on the element position. If the matching switch is disabled, encoded output omits those tags,
+and decoding that output will produce an otherwise equal [CborElement] without the omitted tags.
+
+#### Types of CBOR Elements
+
+A [CborElement] class has three direct subtypes, closely following CBOR grammar:
+
+* [CborPrimitive] represents primitive CBOR elements, such as string, integer, float, boolean, and null.
+ CBOR byte strings are also treated as primitives.
+ [CborElement] and [CborPrimitive] do not expose a generic `value` property. Concrete primitive types expose dedicated
+ accessors where their CBOR content maps cleanly to Kotlin values.
+ Note that Cbor discriminates between positive ("unsigned") and negative ("signed") integers!
+ `CborPrimitive` is itself an umbrella type (a sealed class) for the following concrete primitives:
+ * [CborNull] mapping to a Kotlin `null`
+ * [CborUndefined] mapping to CBOR `undefined`
+ * [CborBoolean] mapping to a Kotlin `Boolean`
+ * [CborInteger] represents signed CBOR integer (major type 1 encompassing `-2^64..-1`) and unsigned CBOR integer (major
+ type 0 encompassing `0..2^64-1`). Since this exceeds the range of Kotlin's built-in `Long` type, CborInteger features
+ `isPositive` and `absoluteValue` representing the absolute value as an `ULong`.
+ It also features `long`, `int`, `short`, and `byte` conversion properties that throw when the value cannot be
+ represented in the requested Kotlin type.
+ * [CborString] maps to a Kotlin `String`
+ * [CborFloat] maps to Kotlin `Double`
+ * [CborByteString] maps to a Kotlin `ByteArray` and is used to encode them as CBOR byte string (in contrast to a list
+ of individual bytes)
+
+* [CborArray] represents a CBOR array. It is a Kotlin `List` of `CborElement` items.
+
+* [CborMap] represents a CBOR map/object. It is a Kotlin `Map` from `CborElement` keys to `CborElement` values.
+ This is typically the result of serializing an arbitrary
+
## ProtoBuf (experimental)
@@ -1673,5 +1804,17 @@ This chapter concludes [Kotlin Serialization Guide](serialization-guide.md).
[Cbor.decodeFromByteArray]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor/decode-from-byte-array.html
[CborBuilder.ignoreUnknownKeys]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-builder/ignore-unknown-keys.html
[ByteString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-byte-string/index.html
+[CborElement]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-element/index.html
+[Cbor.encodeToCborElement]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/encode-to-cbor-element.html
+[CborPrimitive]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-primitive/index.html
+[CborNull]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-null/index.html
+[CborUndefined]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-undefined/index.html
+[CborBoolean]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-boolean/index.html
+[CborInteger]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-integer/index.html
+[CborString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-string/index.html
+[CborFloat]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-float/index.html
+[CborByteString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-byte-string/index.html
+[CborArray]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-array/index.html
+[CborMap]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-map/index.html
diff --git a/docs/serialization-guide.md b/docs/serialization-guide.md
index c01eb6231c..d03f518f01 100644
--- a/docs/serialization-guide.md
+++ b/docs/serialization-guide.md
@@ -155,6 +155,11 @@ Once the project is set up, we can start serializing some classes.
* [Tags and Labels](formats.md#tags-and-labels)
* [Arrays](formats.md#arrays)
* [Custom CBOR-specific Serializers](formats.md#custom-cbor-specific-serializers)
+ * [CBOR Elements](formats.md#cbor-elements)
+ * [Encoding from/to `CborElement`](formats.md#encoding-fromto-cborelement)
+ * [Tagging `CborElement`s](formats.md#tagging-cborelements)
+ * [Caution](formats.md#caution)
+ * [Types of CBOR Elements](formats.md#types-of-cbor-elements)
* [ProtoBuf (experimental)](formats.md#protobuf-experimental)
* [Field numbers](formats.md#field-numbers)
* [Integer types](formats.md#integer-types)
diff --git a/formats/cbor/api/kotlinx-serialization-cbor.api b/formats/cbor/api/kotlinx-serialization-cbor.api
index 6b580add00..56d640e541 100644
--- a/formats/cbor/api/kotlinx-serialization-cbor.api
+++ b/formats/cbor/api/kotlinx-serialization-cbor.api
@@ -9,7 +9,9 @@ public abstract class kotlinx/serialization/cbor/Cbor : kotlinx/serialization/Bi
public static final field Default Lkotlinx/serialization/cbor/Cbor$Default;
public synthetic fun (Lkotlinx/serialization/cbor/CborConfiguration;Lkotlinx/serialization/modules/SerializersModule;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun decodeFromByteArray (Lkotlinx/serialization/DeserializationStrategy;[B)Ljava/lang/Object;
+ public final fun decodeFromCborElement (Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/cbor/CborElement;)Ljava/lang/Object;
public fun encodeToByteArray (Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)[B
+ public final fun encodeToCborElement (Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)Lkotlinx/serialization/cbor/CborElement;
public final fun getConfiguration ()Lkotlinx/serialization/cbor/CborConfiguration;
public fun getSerializersModule ()Lkotlinx/serialization/modules/SerializersModule;
}
@@ -18,11 +20,63 @@ public final class kotlinx/serialization/cbor/Cbor$Default : kotlinx/serializati
public final fun getCoseCompliant ()Lkotlinx/serialization/cbor/Cbor;
}
-public abstract interface annotation class kotlinx/serialization/cbor/CborArray : java/lang/annotation/Annotation {
+public final class kotlinx/serialization/cbor/CborArray : kotlinx/serialization/cbor/CborElement, java/util/List, kotlin/jvm/internal/markers/KMappedMarker {
+ public static final field Companion Lkotlinx/serialization/cbor/CborArray$Companion;
+ public synthetic fun (Ljava/util/List;[JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public synthetic fun add (ILjava/lang/Object;)V
+ public fun add (ILkotlinx/serialization/cbor/CborElement;)V
+ public synthetic fun add (Ljava/lang/Object;)Z
+ public fun add (Lkotlinx/serialization/cbor/CborElement;)Z
+ public fun addAll (ILjava/util/Collection;)Z
+ public fun addAll (Ljava/util/Collection;)Z
+ public fun clear ()V
+ public final fun contains (Ljava/lang/Object;)Z
+ public fun contains (Lkotlinx/serialization/cbor/CborElement;)Z
+ public fun containsAll (Ljava/util/Collection;)Z
+ public fun equals (Ljava/lang/Object;)Z
+ public synthetic fun get (I)Ljava/lang/Object;
+ public fun get (I)Lkotlinx/serialization/cbor/CborElement;
+ public fun getSize ()I
+ public fun hashCode ()I
+ public final fun indexOf (Ljava/lang/Object;)I
+ public fun indexOf (Lkotlinx/serialization/cbor/CborElement;)I
+ public fun isEmpty ()Z
+ public fun iterator ()Ljava/util/Iterator;
+ public final fun lastIndexOf (Ljava/lang/Object;)I
+ public fun lastIndexOf (Lkotlinx/serialization/cbor/CborElement;)I
+ public fun listIterator ()Ljava/util/ListIterator;
+ public fun listIterator (I)Ljava/util/ListIterator;
+ public synthetic fun remove (I)Ljava/lang/Object;
+ public fun remove (I)Lkotlinx/serialization/cbor/CborElement;
+ public fun remove (Ljava/lang/Object;)Z
+ public fun removeAll (Ljava/util/Collection;)Z
+ public fun replaceAll (Ljava/util/function/UnaryOperator;)V
+ public fun retainAll (Ljava/util/Collection;)Z
+ public synthetic fun set (ILjava/lang/Object;)Ljava/lang/Object;
+ public fun set (ILkotlinx/serialization/cbor/CborElement;)Lkotlinx/serialization/cbor/CborElement;
+ public final fun size ()I
+ public fun sort (Ljava/util/Comparator;)V
+ public fun subList (II)Ljava/util/List;
+ public fun toArray ()[Ljava/lang/Object;
+ public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object;
+ public fun toString ()Ljava/lang/String;
}
-public final synthetic class kotlinx/serialization/cbor/CborArray$Impl : kotlinx/serialization/cbor/CborArray {
- public fun ()V
+public final class kotlinx/serialization/cbor/CborArray$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
+public final class kotlinx/serialization/cbor/CborBoolean : kotlinx/serialization/cbor/CborPrimitive {
+ public static final field Companion Lkotlinx/serialization/cbor/CborBoolean$Companion;
+ public synthetic fun (Z[JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getValue ()Z
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class kotlinx/serialization/cbor/CborBoolean$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public final class kotlinx/serialization/cbor/CborBuilder {
@@ -52,6 +106,19 @@ public final class kotlinx/serialization/cbor/CborBuilder {
public final fun setVerifyValueTags (Z)V
}
+public final class kotlinx/serialization/cbor/CborByteString : kotlinx/serialization/cbor/CborPrimitive {
+ public static final field Companion Lkotlinx/serialization/cbor/CborByteString$Companion;
+ public synthetic fun ([B[JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public fun hashCode ()I
+ public final fun toByteArray ()[B
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class kotlinx/serialization/cbor/CborByteString$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
public final class kotlinx/serialization/cbor/CborConfiguration {
public final fun getAlwaysUseByteString ()Z
public final fun getEncodeDefaults ()Z
@@ -68,6 +135,7 @@ public final class kotlinx/serialization/cbor/CborConfiguration {
}
public abstract interface class kotlinx/serialization/cbor/CborDecoder : kotlinx/serialization/encoding/Decoder {
+ public abstract fun decodeCborElement ()Lkotlinx/serialization/cbor/CborElement;
public abstract fun getCbor ()Lkotlinx/serialization/cbor/Cbor;
}
@@ -76,17 +144,72 @@ public final class kotlinx/serialization/cbor/CborDecoder$DefaultImpls {
public static fun decodeSerializableValue (Lkotlinx/serialization/cbor/CborDecoder;Lkotlinx/serialization/DeserializationStrategy;)Ljava/lang/Object;
}
+public abstract class kotlinx/serialization/cbor/CborElement {
+ public static final field Companion Lkotlinx/serialization/cbor/CborElement$Companion;
+ public synthetic fun ([JILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public synthetic fun ([JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getTags-Y2RjT0g ()[J
+ public fun hashCode ()I
+}
+
+public final class kotlinx/serialization/cbor/CborElement$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
+public final class kotlinx/serialization/cbor/CborElementKt {
+ public static final fun CborInteger-SIFponk (J[J)Lkotlinx/serialization/cbor/CborInteger;
+ public static final fun CborInteger-ahITK_k (J[J)Lkotlinx/serialization/cbor/CborInteger;
+ public static final fun getByte (Lkotlinx/serialization/cbor/CborInteger;)B
+ public static final fun getByteOrNull (Lkotlinx/serialization/cbor/CborInteger;)Ljava/lang/Byte;
+ public static final fun getInt (Lkotlinx/serialization/cbor/CborInteger;)I
+ public static final fun getIntOrNull (Lkotlinx/serialization/cbor/CborInteger;)Ljava/lang/Integer;
+ public static final fun getLong (Lkotlinx/serialization/cbor/CborInteger;)J
+ public static final fun getLongOrNull (Lkotlinx/serialization/cbor/CborInteger;)Ljava/lang/Long;
+ public static final fun getShort (Lkotlinx/serialization/cbor/CborInteger;)S
+ public static final fun getShortOrNull (Lkotlinx/serialization/cbor/CborInteger;)Ljava/lang/Short;
+}
+
public abstract interface class kotlinx/serialization/cbor/CborEncoder : kotlinx/serialization/encoding/Encoder {
+ public fun encodeCborElement (Lkotlinx/serialization/cbor/CborElement;)V
public abstract fun getCbor ()Lkotlinx/serialization/cbor/Cbor;
}
public final class kotlinx/serialization/cbor/CborEncoder$DefaultImpls {
public static fun beginCollection (Lkotlinx/serialization/cbor/CborEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;I)Lkotlinx/serialization/encoding/CompositeEncoder;
+ public static fun encodeCborElement (Lkotlinx/serialization/cbor/CborEncoder;Lkotlinx/serialization/cbor/CborElement;)V
public static fun encodeNotNullMark (Lkotlinx/serialization/cbor/CborEncoder;)V
public static fun encodeNullableSerializableValue (Lkotlinx/serialization/cbor/CborEncoder;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
public static fun encodeSerializableValue (Lkotlinx/serialization/cbor/CborEncoder;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
}
+public final class kotlinx/serialization/cbor/CborFloat : kotlinx/serialization/cbor/CborPrimitive {
+ public static final field Companion Lkotlinx/serialization/cbor/CborFloat$Companion;
+ public synthetic fun (D[JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getValue ()D
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class kotlinx/serialization/cbor/CborFloat$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
+public final class kotlinx/serialization/cbor/CborInteger : kotlinx/serialization/cbor/CborPrimitive {
+ public static final field Companion Lkotlinx/serialization/cbor/CborInteger$Companion;
+ public synthetic fun (JZ[JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getAbsoluteValue-s-VKNKU ()J
+ public fun hashCode ()I
+ public final fun isPositive ()Z
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class kotlinx/serialization/cbor/CborInteger$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
public final class kotlinx/serialization/cbor/CborKt {
public static final fun Cbor (Lkotlinx/serialization/cbor/Cbor;Lkotlin/jvm/functions/Function1;)Lkotlinx/serialization/cbor/Cbor;
public static synthetic fun Cbor$default (Lkotlinx/serialization/cbor/Cbor;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/serialization/cbor/Cbor;
@@ -101,6 +224,104 @@ public final synthetic class kotlinx/serialization/cbor/CborLabel$Impl : kotlinx
public final synthetic fun label ()J
}
+public final class kotlinx/serialization/cbor/CborMap : kotlinx/serialization/cbor/CborElement, java/util/Map, kotlin/jvm/internal/markers/KMappedMarker {
+ public static final field Companion Lkotlinx/serialization/cbor/CborMap$Companion;
+ public synthetic fun (Ljava/util/Map;[JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun clear ()V
+ public synthetic fun compute (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
+ public fun compute (Lkotlinx/serialization/cbor/CborElement;Ljava/util/function/BiFunction;)Lkotlinx/serialization/cbor/CborElement;
+ public synthetic fun computeIfAbsent (Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;
+ public fun computeIfAbsent (Lkotlinx/serialization/cbor/CborElement;Ljava/util/function/Function;)Lkotlinx/serialization/cbor/CborElement;
+ public synthetic fun computeIfPresent (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
+ public fun computeIfPresent (Lkotlinx/serialization/cbor/CborElement;Ljava/util/function/BiFunction;)Lkotlinx/serialization/cbor/CborElement;
+ public final fun containsKey (Ljava/lang/Object;)Z
+ public fun containsKey (Lkotlinx/serialization/cbor/CborElement;)Z
+ public final fun containsValue (Ljava/lang/Object;)Z
+ public fun containsValue (Lkotlinx/serialization/cbor/CborElement;)Z
+ public final fun entrySet ()Ljava/util/Set;
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun get (I)Lkotlinx/serialization/cbor/CborElement;
+ public final fun get (J)Lkotlinx/serialization/cbor/CborElement;
+ public final synthetic fun get (Ljava/lang/Object;)Ljava/lang/Object;
+ public final fun get (Ljava/lang/Object;)Lkotlinx/serialization/cbor/CborElement;
+ public final fun get (Ljava/lang/String;)Lkotlinx/serialization/cbor/CborElement;
+ public fun get (Lkotlinx/serialization/cbor/CborElement;)Lkotlinx/serialization/cbor/CborElement;
+ public fun getEntries ()Ljava/util/Set;
+ public fun getKeys ()Ljava/util/Set;
+ public fun getSize ()I
+ public final fun getValue (I)Lkotlinx/serialization/cbor/CborElement;
+ public final fun getValue (J)Lkotlinx/serialization/cbor/CborElement;
+ public final fun getValue (Ljava/lang/String;)Lkotlinx/serialization/cbor/CborElement;
+ public fun getValues ()Ljava/util/Collection;
+ public fun hashCode ()I
+ public fun isEmpty ()Z
+ public final fun keySet ()Ljava/util/Set;
+ public synthetic fun merge (Ljava/lang/Object;Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
+ public fun merge (Lkotlinx/serialization/cbor/CborElement;Lkotlinx/serialization/cbor/CborElement;Ljava/util/function/BiFunction;)Lkotlinx/serialization/cbor/CborElement;
+ public synthetic fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+ public fun put (Lkotlinx/serialization/cbor/CborElement;Lkotlinx/serialization/cbor/CborElement;)Lkotlinx/serialization/cbor/CborElement;
+ public fun putAll (Ljava/util/Map;)V
+ public synthetic fun putIfAbsent (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+ public fun putIfAbsent (Lkotlinx/serialization/cbor/CborElement;Lkotlinx/serialization/cbor/CborElement;)Lkotlinx/serialization/cbor/CborElement;
+ public synthetic fun remove (Ljava/lang/Object;)Ljava/lang/Object;
+ public fun remove (Ljava/lang/Object;)Lkotlinx/serialization/cbor/CborElement;
+ public fun remove (Ljava/lang/Object;Ljava/lang/Object;)Z
+ public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+ public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z
+ public fun replace (Lkotlinx/serialization/cbor/CborElement;Lkotlinx/serialization/cbor/CborElement;)Lkotlinx/serialization/cbor/CborElement;
+ public fun replace (Lkotlinx/serialization/cbor/CborElement;Lkotlinx/serialization/cbor/CborElement;Lkotlinx/serialization/cbor/CborElement;)Z
+ public fun replaceAll (Ljava/util/function/BiFunction;)V
+ public final fun size ()I
+ public fun toString ()Ljava/lang/String;
+ public final fun values ()Ljava/util/Collection;
+}
+
+public final class kotlinx/serialization/cbor/CborMap$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
+public final class kotlinx/serialization/cbor/CborNull : kotlinx/serialization/cbor/CborPrimitive {
+ public static final field Companion Lkotlinx/serialization/cbor/CborNull$Companion;
+ public synthetic fun ([JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class kotlinx/serialization/cbor/CborNull$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
+public abstract interface annotation class kotlinx/serialization/cbor/CborObjectAsArray : java/lang/annotation/Annotation {
+}
+
+public final synthetic class kotlinx/serialization/cbor/CborObjectAsArray$Impl : kotlinx/serialization/cbor/CborObjectAsArray {
+ public fun ()V
+}
+
+public abstract class kotlinx/serialization/cbor/CborPrimitive : kotlinx/serialization/cbor/CborElement {
+ public static final field Companion Lkotlinx/serialization/cbor/CborPrimitive$Companion;
+ public synthetic fun ([JILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public synthetic fun ([JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+}
+
+public final class kotlinx/serialization/cbor/CborPrimitive$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
+public final class kotlinx/serialization/cbor/CborString : kotlinx/serialization/cbor/CborPrimitive {
+ public static final field Companion Lkotlinx/serialization/cbor/CborString$Companion;
+ public synthetic fun (Ljava/lang/String;[JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getValue ()Ljava/lang/String;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class kotlinx/serialization/cbor/CborString$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
public final class kotlinx/serialization/cbor/CborTag {
public static final field BASE16 J
public static final field BASE64 J
@@ -122,6 +343,18 @@ public final class kotlinx/serialization/cbor/CborTag {
public static final field URI J
}
+public final class kotlinx/serialization/cbor/CborUndefined : kotlinx/serialization/cbor/CborPrimitive {
+ public static final field Companion Lkotlinx/serialization/cbor/CborUndefined$Companion;
+ public synthetic fun ([JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class kotlinx/serialization/cbor/CborUndefined$Companion {
+ public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
public abstract interface annotation class kotlinx/serialization/cbor/KeyTags : java/lang/annotation/Annotation {
public abstract fun tags ()[J
}
diff --git a/formats/cbor/api/kotlinx-serialization-cbor.klib.api b/formats/cbor/api/kotlinx-serialization-cbor.klib.api
index 346416c8fa..9e98d3e192 100644
--- a/formats/cbor/api/kotlinx-serialization-cbor.klib.api
+++ b/formats/cbor/api/kotlinx-serialization-cbor.klib.api
@@ -10,10 +10,6 @@ open annotation class kotlinx.serialization.cbor/ByteString : kotlin/Annotation
constructor () // kotlinx.serialization.cbor/ByteString.|(){}[0]
}
-open annotation class kotlinx.serialization.cbor/CborArray : kotlin/Annotation { // kotlinx.serialization.cbor/CborArray|null[0]
- constructor () // kotlinx.serialization.cbor/CborArray.|(){}[0]
-}
-
open annotation class kotlinx.serialization.cbor/CborLabel : kotlin/Annotation { // kotlinx.serialization.cbor/CborLabel|null[0]
constructor (kotlin/Long) // kotlinx.serialization.cbor/CborLabel.|(kotlin.Long){}[0]
@@ -21,6 +17,10 @@ open annotation class kotlinx.serialization.cbor/CborLabel : kotlin/Annotation {
final fun (): kotlin/Long // kotlinx.serialization.cbor/CborLabel.label.|(){}[0]
}
+open annotation class kotlinx.serialization.cbor/CborObjectAsArray : kotlin/Annotation { // kotlinx.serialization.cbor/CborObjectAsArray|null[0]
+ constructor () // kotlinx.serialization.cbor/CborObjectAsArray.|(){}[0]
+}
+
open annotation class kotlinx.serialization.cbor/KeyTags : kotlin/Annotation { // kotlinx.serialization.cbor/KeyTags|null[0]
constructor (kotlin/ULongArray...) // kotlinx.serialization.cbor/KeyTags.|(kotlin.ULongArray...){}[0]
@@ -45,11 +45,58 @@ open annotation class kotlinx.serialization.cbor/ValueTags : kotlin/Annotation {
abstract interface kotlinx.serialization.cbor/CborDecoder : kotlinx.serialization.encoding/Decoder { // kotlinx.serialization.cbor/CborDecoder|null[0]
abstract val cbor // kotlinx.serialization.cbor/CborDecoder.cbor|{}cbor[0]
abstract fun (): kotlinx.serialization.cbor/Cbor // kotlinx.serialization.cbor/CborDecoder.cbor.|(){}[0]
+
+ abstract fun decodeCborElement(): kotlinx.serialization.cbor/CborElement // kotlinx.serialization.cbor/CborDecoder.decodeCborElement|decodeCborElement(){}[0]
}
abstract interface kotlinx.serialization.cbor/CborEncoder : kotlinx.serialization.encoding/Encoder { // kotlinx.serialization.cbor/CborEncoder|null[0]
abstract val cbor // kotlinx.serialization.cbor/CborEncoder.cbor|{}cbor[0]
abstract fun (): kotlinx.serialization.cbor/Cbor // kotlinx.serialization.cbor/CborEncoder.cbor.|(){}[0]
+
+ open fun encodeCborElement(kotlinx.serialization.cbor/CborElement) // kotlinx.serialization.cbor/CborEncoder.encodeCborElement|encodeCborElement(kotlinx.serialization.cbor.CborElement){}[0]
+}
+
+final class kotlinx.serialization.cbor/CborArray : kotlin.collections/List, kotlinx.serialization.cbor/CborElement { // kotlinx.serialization.cbor/CborArray|null[0]
+ constructor (kotlin.collections/List, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborArray.|(kotlin.collections.List;kotlin.ULongArray...){}[0]
+
+ final val size // kotlinx.serialization.cbor/CborArray.size|{}size[0]
+ final fun (): kotlin/Int // kotlinx.serialization.cbor/CborArray.size.|(){}[0]
+
+ final fun contains(kotlinx.serialization.cbor/CborElement): kotlin/Boolean // kotlinx.serialization.cbor/CborArray.contains|contains(kotlinx.serialization.cbor.CborElement){}[0]
+ final fun containsAll(kotlin.collections/Collection): kotlin/Boolean // kotlinx.serialization.cbor/CborArray.containsAll|containsAll(kotlin.collections.Collection){}[0]
+ final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborArray.equals|equals(kotlin.Any?){}[0]
+ final fun get(kotlin/Int): kotlinx.serialization.cbor/CborElement // kotlinx.serialization.cbor/CborArray.get|get(kotlin.Int){}[0]
+ final fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborArray.hashCode|hashCode(){}[0]
+ final fun indexOf(kotlinx.serialization.cbor/CborElement): kotlin/Int // kotlinx.serialization.cbor/CborArray.indexOf|indexOf(kotlinx.serialization.cbor.CborElement){}[0]
+ final fun isEmpty(): kotlin/Boolean // kotlinx.serialization.cbor/CborArray.isEmpty|isEmpty(){}[0]
+ final fun iterator(): kotlin.collections/Iterator // kotlinx.serialization.cbor/CborArray.iterator|iterator(){}[0]
+ final fun lastIndexOf(kotlinx.serialization.cbor/CborElement): kotlin/Int // kotlinx.serialization.cbor/CborArray.lastIndexOf|lastIndexOf(kotlinx.serialization.cbor.CborElement){}[0]
+ final fun listIterator(): kotlin.collections/ListIterator // kotlinx.serialization.cbor/CborArray.listIterator|listIterator(){}[0]
+ final fun listIterator(kotlin/Int): kotlin.collections/ListIterator // kotlinx.serialization.cbor/CborArray.listIterator|listIterator(kotlin.Int){}[0]
+ final fun subList(kotlin/Int, kotlin/Int): kotlin.collections/List // kotlinx.serialization.cbor/CborArray.subList|subList(kotlin.Int;kotlin.Int){}[0]
+ final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborArray.toString|toString(){}[0]
+
+ final object Companion { // kotlinx.serialization.cbor/CborArray.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborArray.Companion.serializer|serializer(){}[0]
+ }
+
+ // Targets: [js]
+ final fun asJsReadonlyArrayView(): kotlin.js.collections/JsReadonlyArray // kotlinx.serialization.cbor/CborArray.asJsReadonlyArrayView|asJsReadonlyArrayView(){}[0]
+}
+
+final class kotlinx.serialization.cbor/CborBoolean : kotlinx.serialization.cbor/CborPrimitive { // kotlinx.serialization.cbor/CborBoolean|null[0]
+ constructor (kotlin/Boolean, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborBoolean.|(kotlin.Boolean;kotlin.ULongArray...){}[0]
+
+ final val value // kotlinx.serialization.cbor/CborBoolean.value|{}value[0]
+ final fun (): kotlin/Boolean // kotlinx.serialization.cbor/CborBoolean.value.|(){}[0]
+
+ final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborBoolean.equals|equals(kotlin.Any?){}[0]
+ final fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborBoolean.hashCode|hashCode(){}[0]
+ final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborBoolean.toString|toString(){}[0]
+
+ final object Companion { // kotlinx.serialization.cbor/CborBoolean.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborBoolean.Companion.serializer|serializer(){}[0]
+ }
}
final class kotlinx.serialization.cbor/CborBuilder { // kotlinx.serialization.cbor/CborBuilder|null[0]
@@ -91,6 +138,19 @@ final class kotlinx.serialization.cbor/CborBuilder { // kotlinx.serialization.cb
final fun (kotlin/Boolean) // kotlinx.serialization.cbor/CborBuilder.verifyValueTags.|(kotlin.Boolean){}[0]
}
+final class kotlinx.serialization.cbor/CborByteString : kotlinx.serialization.cbor/CborPrimitive { // kotlinx.serialization.cbor/CborByteString|null[0]
+ constructor (kotlin/ByteArray, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborByteString.|(kotlin.ByteArray;kotlin.ULongArray...){}[0]
+
+ final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborByteString.equals|equals(kotlin.Any?){}[0]
+ final fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborByteString.hashCode|hashCode(){}[0]
+ final fun toByteArray(): kotlin/ByteArray // kotlinx.serialization.cbor/CborByteString.toByteArray|toByteArray(){}[0]
+ final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborByteString.toString|toString(){}[0]
+
+ final object Companion { // kotlinx.serialization.cbor/CborByteString.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborByteString.Companion.serializer|serializer(){}[0]
+ }
+}
+
final class kotlinx.serialization.cbor/CborConfiguration { // kotlinx.serialization.cbor/CborConfiguration|null[0]
final val alwaysUseByteString // kotlinx.serialization.cbor/CborConfiguration.alwaysUseByteString|{}alwaysUseByteString[0]
final fun (): kotlin/Boolean // kotlinx.serialization.cbor/CborConfiguration.alwaysUseByteString.|(){}[0]
@@ -118,12 +178,119 @@ final class kotlinx.serialization.cbor/CborConfiguration { // kotlinx.serializat
final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborConfiguration.toString|toString(){}[0]
}
+final class kotlinx.serialization.cbor/CborFloat : kotlinx.serialization.cbor/CborPrimitive { // kotlinx.serialization.cbor/CborFloat|null[0]
+ constructor (kotlin/Double, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborFloat.|(kotlin.Double;kotlin.ULongArray...){}[0]
+
+ final val value // kotlinx.serialization.cbor/CborFloat.value|{}value[0]
+ final fun (): kotlin/Double // kotlinx.serialization.cbor/CborFloat.value.|(){}[0]
+
+ final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborFloat.equals|equals(kotlin.Any?){}[0]
+ final fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborFloat.hashCode|hashCode(){}[0]
+ final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborFloat.toString|toString(){}[0]
+
+ final object Companion { // kotlinx.serialization.cbor/CborFloat.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborFloat.Companion.serializer|serializer(){}[0]
+ }
+}
+
+final class kotlinx.serialization.cbor/CborInteger : kotlinx.serialization.cbor/CborPrimitive { // kotlinx.serialization.cbor/CborInteger|null[0]
+ constructor (kotlin/ULong, kotlin/Boolean, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborInteger.|(kotlin.ULong;kotlin.Boolean;kotlin.ULongArray...){}[0]
+
+ final val absoluteValue // kotlinx.serialization.cbor/CborInteger.absoluteValue|{}absoluteValue[0]
+ final fun (): kotlin/ULong // kotlinx.serialization.cbor/CborInteger.absoluteValue.|(){}[0]
+ final val isPositive // kotlinx.serialization.cbor/CborInteger.isPositive|{}isPositive[0]
+ final fun (): kotlin/Boolean // kotlinx.serialization.cbor/CborInteger.isPositive.|(){}[0]
+
+ final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborInteger.equals|equals(kotlin.Any?){}[0]
+ final fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborInteger.hashCode|hashCode(){}[0]
+ final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborInteger.toString|toString(){}[0]
+
+ final object Companion { // kotlinx.serialization.cbor/CborInteger.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborInteger.Companion.serializer|serializer(){}[0]
+ }
+}
+
+final class kotlinx.serialization.cbor/CborMap : kotlin.collections/Map, kotlinx.serialization.cbor/CborElement { // kotlinx.serialization.cbor/CborMap|null[0]
+ constructor (kotlin.collections/Map, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborMap.|(kotlin.collections.Map;kotlin.ULongArray...){}[0]
+
+ final val entries // kotlinx.serialization.cbor/CborMap.entries|{}entries[0]
+ final fun (): kotlin.collections/Set> // kotlinx.serialization.cbor/CborMap.entries.|(){}[0]
+ final val keys // kotlinx.serialization.cbor/CborMap.keys|{}keys[0]
+ final fun (): kotlin.collections/Set // kotlinx.serialization.cbor/CborMap.keys.|(){}[0]
+ final val size // kotlinx.serialization.cbor/CborMap.size|{}size[0]
+ final fun (): kotlin/Int // kotlinx.serialization.cbor/CborMap.size.|(){}[0]
+ final val values // kotlinx.serialization.cbor/CborMap.values|{}values[0]
+ final fun (): kotlin.collections/Collection // kotlinx.serialization.cbor/CborMap.values.|(){}[0]
+
+ final fun containsKey(kotlinx.serialization.cbor/CborElement): kotlin/Boolean // kotlinx.serialization.cbor/CborMap.containsKey|containsKey(kotlinx.serialization.cbor.CborElement){}[0]
+ final fun containsValue(kotlinx.serialization.cbor/CborElement): kotlin/Boolean // kotlinx.serialization.cbor/CborMap.containsValue|containsValue(kotlinx.serialization.cbor.CborElement){}[0]
+ final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborMap.equals|equals(kotlin.Any?){}[0]
+ final fun get(kotlin/Int): kotlinx.serialization.cbor/CborElement? // kotlinx.serialization.cbor/CborMap.get|get(kotlin.Int){}[0]
+ final fun get(kotlin/Long): kotlinx.serialization.cbor/CborElement? // kotlinx.serialization.cbor/CborMap.get|get(kotlin.Long){}[0]
+ final fun get(kotlin/String): kotlinx.serialization.cbor/CborElement? // kotlinx.serialization.cbor/CborMap.get|get(kotlin.String){}[0]
+ final fun get(kotlinx.serialization.cbor/CborElement): kotlinx.serialization.cbor/CborElement? // kotlinx.serialization.cbor/CborMap.get|get(kotlinx.serialization.cbor.CborElement){}[0]
+ final fun getValue(kotlin/Int): kotlinx.serialization.cbor/CborElement // kotlinx.serialization.cbor/CborMap.getValue|getValue(kotlin.Int){}[0]
+ final fun getValue(kotlin/Long): kotlinx.serialization.cbor/CborElement // kotlinx.serialization.cbor/CborMap.getValue|getValue(kotlin.Long){}[0]
+ final fun getValue(kotlin/String): kotlinx.serialization.cbor/CborElement // kotlinx.serialization.cbor/CborMap.getValue|getValue(kotlin.String){}[0]
+ final fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborMap.hashCode|hashCode(){}[0]
+ final fun isEmpty(): kotlin/Boolean // kotlinx.serialization.cbor/CborMap.isEmpty|isEmpty(){}[0]
+ final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborMap.toString|toString(){}[0]
+
+ final object Companion { // kotlinx.serialization.cbor/CborMap.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborMap.Companion.serializer|serializer(){}[0]
+ }
+
+ // Targets: [js]
+ final fun asJsReadonlyMapView(): kotlin.js.collections/JsReadonlyMap // kotlinx.serialization.cbor/CborMap.asJsReadonlyMapView|asJsReadonlyMapView(){}[0]
+}
+
+final class kotlinx.serialization.cbor/CborNull : kotlinx.serialization.cbor/CborPrimitive { // kotlinx.serialization.cbor/CborNull|null[0]
+ constructor (kotlin/ULongArray...) // kotlinx.serialization.cbor/CborNull.|(kotlin.ULongArray...){}[0]
+
+ final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborNull.equals|equals(kotlin.Any?){}[0]
+ final fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborNull.hashCode|hashCode(){}[0]
+ final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborNull.toString|toString(){}[0]
+
+ final object Companion { // kotlinx.serialization.cbor/CborNull.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborNull.Companion.serializer|serializer(){}[0]
+ }
+}
+
+final class kotlinx.serialization.cbor/CborString : kotlinx.serialization.cbor/CborPrimitive { // kotlinx.serialization.cbor/CborString|null[0]
+ constructor (kotlin/String, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborString.|(kotlin.String;kotlin.ULongArray...){}[0]
+
+ final val value // kotlinx.serialization.cbor/CborString.value|{}value[0]
+ final fun (): kotlin/String // kotlinx.serialization.cbor/CborString.value.|(){}[0]
+
+ final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborString.equals|equals(kotlin.Any?){}[0]
+ final fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborString.hashCode|hashCode(){}[0]
+ final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborString.toString|toString(){}[0]
+
+ final object Companion { // kotlinx.serialization.cbor/CborString.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborString.Companion.serializer|serializer(){}[0]
+ }
+}
+
+final class kotlinx.serialization.cbor/CborUndefined : kotlinx.serialization.cbor/CborPrimitive { // kotlinx.serialization.cbor/CborUndefined|null[0]
+ constructor (kotlin/ULongArray...) // kotlinx.serialization.cbor/CborUndefined.|(kotlin.ULongArray...){}[0]
+
+ final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborUndefined.equals|equals(kotlin.Any?){}[0]
+ final fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborUndefined.hashCode|hashCode(){}[0]
+ final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborUndefined.toString|toString(){}[0]
+
+ final object Companion { // kotlinx.serialization.cbor/CborUndefined.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborUndefined.Companion.serializer|serializer(){}[0]
+ }
+}
+
sealed class kotlinx.serialization.cbor/Cbor : kotlinx.serialization/BinaryFormat { // kotlinx.serialization.cbor/Cbor|null[0]
final val configuration // kotlinx.serialization.cbor/Cbor.configuration|{}configuration[0]
final fun (): kotlinx.serialization.cbor/CborConfiguration // kotlinx.serialization.cbor/Cbor.configuration.|(){}[0]
open val serializersModule // kotlinx.serialization.cbor/Cbor.serializersModule|{}serializersModule[0]
open fun (): kotlinx.serialization.modules/SerializersModule // kotlinx.serialization.cbor/Cbor.serializersModule.|(){}[0]
+ final fun <#A1: kotlin/Any?> decodeFromCborElement(kotlinx.serialization/DeserializationStrategy<#A1>, kotlinx.serialization.cbor/CborElement): #A1 // kotlinx.serialization.cbor/Cbor.decodeFromCborElement|decodeFromCborElement(kotlinx.serialization.DeserializationStrategy<0:0>;kotlinx.serialization.cbor.CborElement){0§}[0]
+ final fun <#A1: kotlin/Any?> encodeToCborElement(kotlinx.serialization/SerializationStrategy<#A1>, #A1): kotlinx.serialization.cbor/CborElement // kotlinx.serialization.cbor/Cbor.encodeToCborElement|encodeToCborElement(kotlinx.serialization.SerializationStrategy<0:0>;0:0){0§}[0]
open fun <#A1: kotlin/Any?> decodeFromByteArray(kotlinx.serialization/DeserializationStrategy<#A1>, kotlin/ByteArray): #A1 // kotlinx.serialization.cbor/Cbor.decodeFromByteArray|decodeFromByteArray(kotlinx.serialization.DeserializationStrategy<0:0>;kotlin.ByteArray){0§}[0]
open fun <#A1: kotlin/Any?> encodeToByteArray(kotlinx.serialization/SerializationStrategy<#A1>, #A1): kotlin/ByteArray // kotlinx.serialization.cbor/Cbor.encodeToByteArray|encodeToByteArray(kotlinx.serialization.SerializationStrategy<0:0>;0:0){0§}[0]
@@ -133,6 +300,24 @@ sealed class kotlinx.serialization.cbor/Cbor : kotlinx.serialization/BinaryForma
}
}
+sealed class kotlinx.serialization.cbor/CborElement { // kotlinx.serialization.cbor/CborElement|null[0]
+ final var tags // kotlinx.serialization.cbor/CborElement.tags|{}tags[0]
+ final fun (): kotlin/ULongArray // kotlinx.serialization.cbor/CborElement.tags.|(){}[0]
+
+ open fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborElement.equals|equals(kotlin.Any?){}[0]
+ open fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborElement.hashCode|hashCode(){}[0]
+
+ final object Companion { // kotlinx.serialization.cbor/CborElement.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborElement.Companion.serializer|serializer(){}[0]
+ }
+}
+
+sealed class kotlinx.serialization.cbor/CborPrimitive : kotlinx.serialization.cbor/CborElement { // kotlinx.serialization.cbor/CborPrimitive|null[0]
+ final object Companion { // kotlinx.serialization.cbor/CborPrimitive.Companion|null[0]
+ final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.serialization.cbor/CborPrimitive.Companion.serializer|serializer(){}[0]
+ }
+}
+
final object kotlinx.serialization.cbor/CborTag { // kotlinx.serialization.cbor/CborTag|null[0]
final const val BASE16 // kotlinx.serialization.cbor/CborTag.BASE16|{}BASE16[0]
final fun (): kotlin/ULong // kotlinx.serialization.cbor/CborTag.BASE16.|(){}[0]
@@ -170,4 +355,25 @@ final object kotlinx.serialization.cbor/CborTag { // kotlinx.serialization.cbor/
final fun (): kotlin/ULong // kotlinx.serialization.cbor/CborTag.URI.|(){}[0]
}
+final val kotlinx.serialization.cbor/byte // kotlinx.serialization.cbor/byte|@kotlinx.serialization.cbor.CborInteger{}byte[0]
+ final fun (kotlinx.serialization.cbor/CborInteger).(): kotlin/Byte // kotlinx.serialization.cbor/byte.|@kotlinx.serialization.cbor.CborInteger(){}[0]
+final val kotlinx.serialization.cbor/byteOrNull // kotlinx.serialization.cbor/byteOrNull|@kotlinx.serialization.cbor.CborInteger{}byteOrNull[0]
+ final fun (kotlinx.serialization.cbor/CborInteger).(): kotlin/Byte? // kotlinx.serialization.cbor/byteOrNull.|@kotlinx.serialization.cbor.CborInteger(){}[0]
+final val kotlinx.serialization.cbor/int // kotlinx.serialization.cbor/int|@kotlinx.serialization.cbor.CborInteger{}int[0]
+ final fun (kotlinx.serialization.cbor/CborInteger).(): kotlin/Int // kotlinx.serialization.cbor/int.|@kotlinx.serialization.cbor.CborInteger(){}[0]
+final val kotlinx.serialization.cbor/intOrNull // kotlinx.serialization.cbor/intOrNull|@kotlinx.serialization.cbor.CborInteger{}intOrNull[0]
+ final fun (kotlinx.serialization.cbor/CborInteger).(): kotlin/Int? // kotlinx.serialization.cbor/intOrNull.|@kotlinx.serialization.cbor.CborInteger(){}[0]
+final val kotlinx.serialization.cbor/long // kotlinx.serialization.cbor/long|@kotlinx.serialization.cbor.CborInteger{}long[0]
+ final fun (kotlinx.serialization.cbor/CborInteger).(): kotlin/Long // kotlinx.serialization.cbor/long.|@kotlinx.serialization.cbor.CborInteger(){}[0]
+final val kotlinx.serialization.cbor/longOrNull // kotlinx.serialization.cbor/longOrNull|@kotlinx.serialization.cbor.CborInteger{}longOrNull[0]
+ final fun (kotlinx.serialization.cbor/CborInteger).(): kotlin/Long? // kotlinx.serialization.cbor/longOrNull.|@kotlinx.serialization.cbor.CborInteger(){}[0]
+final val kotlinx.serialization.cbor/short // kotlinx.serialization.cbor/short|@kotlinx.serialization.cbor.CborInteger{}short[0]
+ final fun (kotlinx.serialization.cbor/CborInteger).(): kotlin/Short // kotlinx.serialization.cbor/short.|@kotlinx.serialization.cbor.CborInteger(){}[0]
+final val kotlinx.serialization.cbor/shortOrNull // kotlinx.serialization.cbor/shortOrNull|@kotlinx.serialization.cbor.CborInteger{}shortOrNull[0]
+ final fun (kotlinx.serialization.cbor/CborInteger).(): kotlin/Short? // kotlinx.serialization.cbor/shortOrNull.|@kotlinx.serialization.cbor.CborInteger(){}[0]
+
final fun kotlinx.serialization.cbor/Cbor(kotlinx.serialization.cbor/Cbor = ..., kotlin/Function1): kotlinx.serialization.cbor/Cbor // kotlinx.serialization.cbor/Cbor|Cbor(kotlinx.serialization.cbor.Cbor;kotlin.Function1){}[0]
+final fun kotlinx.serialization.cbor/CborInteger(kotlin/Long, kotlin/ULongArray...): kotlinx.serialization.cbor/CborInteger // kotlinx.serialization.cbor/CborInteger|CborInteger(kotlin.Long;kotlin.ULongArray...){}[0]
+final fun kotlinx.serialization.cbor/CborInteger(kotlin/ULong, kotlin/ULongArray...): kotlinx.serialization.cbor/CborInteger // kotlinx.serialization.cbor/CborInteger|CborInteger(kotlin.ULong;kotlin.ULongArray...){}[0]
+final inline fun <#A: reified kotlin/Any?> (kotlinx.serialization.cbor/Cbor).kotlinx.serialization.cbor/decodeFromCborElement(kotlinx.serialization.cbor/CborElement): #A // kotlinx.serialization.cbor/decodeFromCborElement|decodeFromCborElement@kotlinx.serialization.cbor.Cbor(kotlinx.serialization.cbor.CborElement){0§}[0]
+final inline fun <#A: reified kotlin/Any?> (kotlinx.serialization.cbor/Cbor).kotlinx.serialization.cbor/encodeToCborElement(#A): kotlinx.serialization.cbor/CborElement // kotlinx.serialization.cbor/encodeToCborElement|encodeToCborElement@kotlinx.serialization.cbor.Cbor(0:0){0§}[0]
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Cbor.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Cbor.kt
index d922044847..7d8c135884 100644
--- a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Cbor.kt
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Cbor.kt
@@ -78,6 +78,7 @@ public sealed class Cbor(
output
)
dumper.encodeSerializableValue(serializer, value)
+ dumper.ensureNoDanglingTagsAtEndOfSerialization()
return output.toByteArray()
@@ -85,7 +86,7 @@ public sealed class Cbor(
override fun decodeFromByteArray(deserializer: DeserializationStrategy, bytes: ByteArray): T {
val stream = ByteArrayInput(bytes)
- val reader = CborReader(this, CborParser(stream, configuration.verifyObjectTags))
+ val reader = CborReader(this, CborParserImpl(stream, configuration.verifyObjectTags))
val result = reader.decodeSerializableValue(deserializer)
if (stream.availableBytes > 0) {
throw CborDecodingException(
@@ -94,7 +95,50 @@ public sealed class Cbor(
}
return result
}
+
+ /**
+ * Deserializes the given [element] into a value of type [T] using the given [deserializer].
+ *
+ * @throws [SerializationException] if the given CBOR element is not a valid CBOR input for the type [T]
+ * @throws [IllegalArgumentException] if the decoded input cannot be represented as a valid instance of type [T]
+ */
+ public fun decodeFromCborElement(deserializer: DeserializationStrategy, element: CborElement): T {
+ val reader = CborReader(this, StructuredCborParser(element, configuration.verifyObjectTags))
+ return reader.decodeSerializableValue(deserializer)
+ }
+
+ /**
+ * Serializes the given [value] into an equivalent [CborElement] using the given [serializer]
+ *
+ * @throws [SerializationException] if the given value cannot be serialized to CBOR
+ */
+ public fun encodeToCborElement(serializer: SerializationStrategy, value: T): CborElement {
+ val writer = StructuredCborWriter(this)
+ writer.encodeSerializableValue(serializer, value)
+ writer.ensureNoDanglingTagsAtEndOfSerialization()
+ return writer.finalize()
+ }
}
+/**
+ * Serializes the given [value] into an equivalent [CborElement] using a serializer retrieved
+ * from reified type parameter.
+ *
+ * @throws [SerializationException] if the given value cannot be serialized to CBOR.
+ */
+@ExperimentalSerializationApi
+public inline fun Cbor.encodeToCborElement(value: T): CborElement =
+ encodeToCborElement(serializersModule.serializer(), value)
+
+/**
+ * Deserializes the given [element] element into a value of type [T] using a deserializer retrieved
+ * from reified type parameter.
+ *
+ * @throws [SerializationException] if the given CBOR element is not a valid CBOR input for the type [T]
+ * @throws [IllegalArgumentException] if the decoded input cannot be represented as a valid instance of type [T]
+ */
+@ExperimentalSerializationApi
+public inline fun Cbor.decodeFromCborElement(element: CborElement): T =
+ decodeFromCborElement(serializersModule.serializer(), element)
@OptIn(ExperimentalSerializationApi::class)
private class CborImpl(
@@ -114,18 +158,20 @@ private class CborImpl(
public fun Cbor(from: Cbor = Cbor, builderAction: CborBuilder.() -> Unit): Cbor {
val builder = CborBuilder(from)
builder.builderAction()
- return CborImpl(CborConfiguration(
- builder.encodeDefaults,
- builder.ignoreUnknownKeys,
- builder.encodeKeyTags,
- builder.encodeValueTags,
- builder.encodeObjectTags,
- builder.verifyKeyTags,
- builder.verifyValueTags,
- builder.verifyObjectTags,
- builder.useDefiniteLengthEncoding,
- builder.preferCborLabelsOverNames,
- builder.alwaysUseByteString),
+ return CborImpl(
+ CborConfiguration(
+ builder.encodeDefaults,
+ builder.ignoreUnknownKeys,
+ builder.encodeKeyTags,
+ builder.encodeValueTags,
+ builder.encodeObjectTags,
+ builder.verifyKeyTags,
+ builder.verifyValueTags,
+ builder.verifyObjectTags,
+ builder.useDefiniteLengthEncoding,
+ builder.preferCborLabelsOverNames,
+ builder.alwaysUseByteString
+ ),
builder.serializersModule
)
}
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborDecoder.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborDecoder.kt
index 13a773f3fa..3a3de2279c 100644
--- a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborDecoder.kt
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborDecoder.kt
@@ -31,4 +31,15 @@ public interface CborDecoder : Decoder {
* Exposes the current [Cbor] instance and all its configuration flags. Useful for low-level custom serializers.
*/
public val cbor: Cbor
+
+ /**
+ * Decodes the next element in the current input as [CborElement].
+ * The type of the decoded element depends on the current state of the input and, when received
+ * by [serializer][KSerializer] in its [KSerializer.serialize] method, the type of the token directly matches
+ * the [kind][kotlinx.serialization.descriptors.SerialDescriptor.kind].
+ *
+ * This method is allowed to invoke only as the part of the whole deserialization process of the class,
+ * calling this method after invoking [beginStructure] or any `decode*` method will lead to unspecified behaviour.
+ */
+ public fun decodeCborElement(): CborElement
}
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborElement.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborElement.kt
new file mode 100644
index 0000000000..13960ac6d5
--- /dev/null
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborElement.kt
@@ -0,0 +1,608 @@
+@file:Suppress("unused")
+@file:OptIn(ExperimentalUnsignedTypes::class, DelicateCborApi::class, ExperimentalSerializationApi::class)
+
+package kotlinx.serialization.cbor
+
+import kotlinx.serialization.*
+import kotlinx.serialization.cbor.internal.*
+import kotlin.jvm.*
+
+@OptIn(ExperimentalUnsignedTypes::class)
+internal val EMPTY_TAGS: ULongArray = ULongArray(0)
+
+/**
+ * Class representing single CBOR element.
+ * Can be [CborPrimitive], [CborMap] or [CborArray].
+ *
+ * [CborElement.toString] properly prints CBOR tree as a human-readable representation.
+ * Whole hierarchy is serializable, but only when used with [Cbor] as [CborElement] is purely CBOR-specific structure
+ * which has meaningful schemaless semantics only for CBOR.
+ *
+ * The whole hierarchy is [serializable][Serializable] only by [Cbor] format.
+ */
+@Serializable(with = CborElementSerializer::class)
+public sealed class CborElement(
+ /**
+ * CBOR tags associated with this element.
+ * Tags are optional semantic tagging of other major types (major type 6).
+ * See [RFC 8949 3.4. Tagging of Items](https://datatracker.ietf.org/doc/html/rfc8949#name-tagging-of-items).
+ */
+ @OptIn(ExperimentalUnsignedTypes::class)
+ tags: ULongArray = EMPTY_TAGS
+
+) {
+
+ @OptIn(ExperimentalUnsignedTypes::class)
+ @DelicateCborApi
+ internal var rawTags: ULongArray = tags
+
+ /**
+ * CBOR tags associated with this element.
+ * Tags are optional semantic tagging of other major types (major type 6).
+ * See [RFC 8949 3.4. Tagging of Items](https://datatracker.ietf.org/doc/html/rfc8949#name-tagging-of-items).
+ */
+ public val tags: List by lazy { rawTags.toList() }
+
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is CborElement) return false
+
+ if (!rawTags.contentEquals(other.rawTags)) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ return rawTags.contentHashCode()
+ }
+
+}
+
+/**
+ * Class representing CBOR primitive value.
+ * CBOR primitives include numbers, strings, booleans, byte arrays and special null value [CborNull].
+ */
+@Serializable(with = CborPrimitiveSerializer::class)
+public sealed class CborPrimitive(
+ tags: ULongArray = EMPTY_TAGS
+) : CborElement(tags)
+
+/**
+ * Class representing either:
+ * * signed CBOR integer (major type 1 encompassing `-2^64..-1`)
+ * * unsigned CBOR integer (major type 0 encompassing `0..2^64-1`)
+ *
+ * depending on the value of [isPositive]. Note that [absoluteValue] **must not be** `0` when [isPositive] is set to `false`.
+ */
+@Serializable(with = CborIntSerializer::class)
+public class CborInteger(
+ public val absoluteValue: ULong,
+ public val isPositive: Boolean,
+ vararg tags: ULong
+) : CborPrimitive(tags) {
+ init {
+ if (!isPositive) require(absoluteValue > 0uL) { "Illegal absolute value $absoluteValue for a negative number." }
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is CborInteger) return false
+ if (!super.equals(other)) return false
+
+ if (absoluteValue != other.absoluteValue) return false
+ if (isPositive != other.isPositive) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = super.hashCode()
+ result = 31 * result + absoluteValue.hashCode()
+ result = 31 * result + isPositive.hashCode()
+ return result
+ }
+
+ override fun toString(): String {
+ return "CborInt(tags=${rawTags.joinToString(prefix = "[", postfix = "]")}, " +
+ "absoluteValue=" + when (isPositive) {
+ true -> ""
+ false -> "-"
+ } +
+ absoluteValue +
+ ")"
+ }
+}
+
+/**
+ * Creates:
+ * * signed CBOR integer (major type 1 encompassing `-2^64..-1`)
+ * * unsigned CBOR integer (major type 0 encompassing `0..2^64-1`)
+ *
+ * depending on whether a positive or a negative number was passed.
+ * If you want to create a negative number exceeding [Long.MIN_VALUE], manually specify sign: `CborInt(ULong.MAX_VALUE, isPositive = false)`.
+ */
+@Suppress("FunctionName")
+public fun CborInteger(value: Long, vararg tags: ULong): CborInteger =
+ if (value >= 0L) CborInteger(value.toULong(), isPositive = true, tags = tags)
+ else CborInteger(ULong.MAX_VALUE - value.toULong() + 1uL, isPositive = false, tags = tags)
+
+/**
+ * Creates an unsigned CBOR integer (major type 0).
+ */
+@Suppress("FunctionName")
+public fun CborInteger(value: ULong, vararg tags: ULong): CborInteger =
+ CborInteger(value, isPositive = true, tags = tags)
+
+/**
+ * Converts this integer to [Long], throwing if it cannot be represented as [Long].
+ */
+public val CborInteger.long: Long
+ get() = longOrNull ?: throw ArithmeticException("$this cannot be represented as Long")
+
+/**
+ * Converts this integer to [Long], or returns `null` if it cannot be represented as [Long].
+ */
+public val CborInteger.longOrNull: Long?
+ get() {
+ val max = Long.MAX_VALUE.toULong()
+ return if (isPositive) {
+ if (absoluteValue <= max) absoluteValue.toLong() else null
+ } else {
+ when {
+ absoluteValue <= max -> -absoluteValue.toLong()
+ absoluteValue == max + 1uL -> Long.MIN_VALUE
+ else -> null
+ }
+ }
+ }
+
+/**
+ * Converts this integer to [Int], throwing if it cannot be represented as [Int].
+ */
+public val CborInteger.int: Int
+ get() = intOrNull ?: throw ArithmeticException("$this cannot be represented as Int")
+
+/**
+ * Converts this integer to [Int], or returns `null` if it cannot be represented as [Int].
+ */
+public val CborInteger.intOrNull: Int?
+ get() {
+ val longValue = longOrNull ?: return null
+ if (longValue !in Int.MIN_VALUE.toLong()..Int.MAX_VALUE.toLong()) return null
+ return longValue.toInt()
+ }
+
+/**
+ * Converts this integer to [Short], throwing if it cannot be represented as [Short].
+ */
+public val CborInteger.short: Short
+ get() = shortOrNull ?: throw ArithmeticException("$this cannot be represented as Short")
+
+/**
+ * Converts this integer to [Short], or returns `null` if it cannot be represented as [Short].
+ */
+public val CborInteger.shortOrNull: Short?
+ get() {
+ val longValue = longOrNull ?: return null
+ if (longValue !in Short.MIN_VALUE.toLong()..Short.MAX_VALUE.toLong()) return null
+ return longValue.toShort()
+ }
+
+/**
+ * Converts this integer to [Byte], throwing if it cannot be represented as [Byte].
+ */
+public val CborInteger.byte: Byte
+ get() = byteOrNull ?: throw ArithmeticException("$this cannot be represented as Byte")
+
+/**
+ * Converts this integer to [Byte], or returns `null` if it cannot be represented as [Byte].
+ */
+public val CborInteger.byteOrNull: Byte?
+ get() {
+ val longValue = longOrNull ?: return null
+ if (longValue !in Byte.MIN_VALUE.toLong()..Byte.MAX_VALUE.toLong()) return null
+ return longValue.toByte()
+ }
+
+/**
+ * Class representing CBOR floating point value (major type 7).
+ */
+@Serializable(with = CborFloatSerializer::class)
+public class CborFloat(
+ public val value: Double,
+ vararg tags: ULong
+) : CborPrimitive(tags) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is CborFloat) return false
+ if (!super.equals(other)) return false
+ return value.equals(other.value)
+ }
+
+ override fun hashCode(): Int = 31 * super.hashCode() + value.hashCode()
+
+ override fun toString(): String {
+ return "CborFloat(" +
+ "tags=${rawTags.joinToString(prefix = "[", postfix = "]")}, " +
+ "value=$value" +
+ ")"
+ }
+}
+
+/**
+ * Class representing CBOR string value.
+ */
+@Serializable(with = CborStringSerializer::class)
+public class CborString(
+ public val value: String,
+ vararg tags: ULong
+) : CborPrimitive(tags) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is CborString) return false
+ if (!super.equals(other)) return false
+ return value == other.value
+ }
+
+ override fun hashCode(): Int = 31 * super.hashCode() + value.hashCode()
+
+ override fun toString(): String {
+ return "CborString(" +
+ "tags=${rawTags.joinToString(prefix = "[", postfix = "]")}, " +
+ "value=$value" +
+ ")"
+ }
+}
+
+/**
+ * Class representing CBOR boolean value.
+ */
+@Serializable(with = CborBooleanSerializer::class)
+public class CborBoolean(
+ public val value: Boolean,
+ vararg tags: ULong
+) : CborPrimitive(tags) {
+
+ public constructor(value: Boolean, tags: List) : this(value, *(tags.toULongArray()))
+
+ /**
+ * Creates a [CborBoolean] from the provided [CborBoolean]'s [value], and the specified [tags].
+ *
+ * @param value The [CborBoolean] instance whose boolean value is used to initialize this object.
+ * @param tags A list of tags to be set with the new instance.
+ */
+ public constructor(value: CborBoolean, tags: List) : this(value.value, *(tags.toULongArray()))
+ public constructor(value: CborBoolean, vararg tags: ULong) : this(value.value, *tags)
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is CborBoolean) return false
+ if (!super.equals(other)) return false
+ return value == other.value
+ }
+
+ override fun hashCode(): Int = 31 * super.hashCode() + value.hashCode()
+
+ override fun toString(): String {
+ return "CborBoolean(" +
+ "tags=${rawTags.joinToString(prefix = "[", postfix = "]")}, " +
+ "value=$value" +
+ ")"
+ }
+}
+
+/**
+ * Class representing CBOR byte string value.
+ */
+@Serializable(with = CborByteStringSerializer::class)
+public class CborByteString(
+ bytes: ByteArray,
+ vararg tags: ULong
+) : CborPrimitive(tags) {
+
+ public constructor(bytes: ByteArray, tags: List) : this(bytes, *(tags.toULongArray()))
+
+ @DelicateCborApi
+ public val bytes: ByteArray = bytes
+
+ /**
+ * Returns a deep copy of this CBOR byte string contents.
+ */
+ public fun toByteArray(): ByteArray = bytes.copyOf()
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is CborByteString) return false
+ if (!rawTags.contentEquals(other.rawTags)) return false
+ return bytes.contentEquals(other.bytes)
+ }
+
+ override fun hashCode(): Int {
+ var result = rawTags.contentHashCode()
+ result = 31 * result + (bytes.contentHashCode())
+ return result
+ }
+
+ override fun toString(): String {
+ return "CborByteString(" +
+ "tags=${rawTags.joinToString(prefix = "[", postfix = "]")}, " +
+ "bytes=h'${bytes.toHexString()}" +
+ ")"
+ }
+
+ internal fun getBytes(): ByteArray = bytes
+}
+
+/**
+ * Class representing CBOR `null` value
+ */
+@Serializable(with = CborNullSerializer::class)
+public class CborNull(vararg tags: ULong) : CborPrimitive(tags) {
+
+ public constructor(tags: List) : this(*(tags.toULongArray()))
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is CborNull) return false
+ return super.equals(other)
+ }
+
+ override fun hashCode(): Int = CborNull::class.hashCode() * 31 + super.hashCode()
+
+ override fun toString(): String {
+ return "CborNull(tags=${rawTags.joinToString(prefix = "[", postfix = "]")})"
+ }
+}
+
+/**
+ * Class representing CBOR `undefined` value
+ */
+@Serializable(with = CborUndefinedSerializer::class)
+public class CborUndefined(vararg tags: ULong) : CborPrimitive(tags) {
+
+ public constructor(tags: List) : this(*(tags.toULongArray()))
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is CborUndefined) return false
+ return super.equals(other)
+ }
+
+ override fun hashCode(): Int = CborUndefined::class.hashCode() * 31 + super.hashCode()
+
+ override fun toString(): String {
+ return "CborUndefined(tags=${rawTags.joinToString(prefix = "[", postfix = "]")})"
+ }
+}
+
+/**
+ * Class representing CBOR map, consisting of key-value pairs, where both key and value are arbitrary [CborElement]
+ *
+ * Since this class also implements [Map] interface, you can use
+ * traditional methods like [Map.get] or [Map.getValue] to obtain CBOR elements.
+ */
+@Serializable(with = CborMapSerializer::class)
+public class CborMap(
+ private val content: Map,
+ vararg tags: ULong
+) : CborElement(tags), Map by content {
+
+ public constructor(content: Map, tags: List) : this(
+ content,
+ *(tags.toULongArray())
+ )
+
+ public override fun equals(other: Any?): Boolean =
+ other is CborMap && other.content == content && other.rawTags.contentEquals(rawTags)
+
+ public override fun hashCode(): Int = content.hashCode() * 31 + rawTags.contentHashCode()
+
+ override fun toString(): String {
+ return "CborMap(" +
+ "tags=${rawTags.joinToString(prefix = "[", postfix = "]")}, " +
+ "content=$content" +
+ ")"
+ }
+
+ public operator fun get(key: String): CborElement? = content[CborString(key)]
+ public fun getValue(key: String): CborElement = content.getValue(CborString(key))
+
+ public operator fun get(key: Long): CborElement? = content[CborInteger(key)]
+ public fun getValue(key: Long): CborElement = content.getValue(CborInteger(key))
+
+ public operator fun get(key: Int): CborElement? = content[CborInteger(key.toLong())]
+ public fun getValue(key: Int): CborElement = content.getValue(CborInteger(key.toLong()))
+
+ public companion object {
+ //these are inside the companion to avoid name clashes on the JVM
+
+ @JvmName("invokeString")
+ public operator fun invoke(content: Map, tags: List): CborMap =
+ CborMap(content.mapKeys { (k, _) -> CborString(k) }, *(tags.toULongArray()))
+
+ @JvmName("invokeLong")
+ public operator fun invoke(content: Map, tags: List): CborMap =
+ CborMap(content.mapKeys { (k, _) -> CborInteger(k) }, *(tags.toULongArray()))
+
+ @JvmName("invokeStringVarargs")
+ public operator fun invoke(content: Map, vararg tags: ULong): CborMap =
+ CborMap(content.mapKeys { (k, _) -> CborString(k) }, *tags)
+
+ @JvmName("invokeLongVarargs")
+ public operator fun invoke(content: Map, vararg tags: ULong): CborMap =
+ CborMap(content.mapKeys { (k, _) -> CborInteger(k) }, *tags)
+ }
+
+}
+
+/**
+ * Class representing CBOR array consisting of CBOR elements.
+ *
+ * Since this class also implements [List] interface, you can use
+ * traditional methods like [List.get] or [List.size] to obtain CBOR elements.
+ */
+@Serializable(with = CborArraySerializer::class)
+public class CborArray(
+ private val content: List,
+ vararg tags: ULong
+) : CborElement(tags), List by content {
+
+ public constructor(content: List, tags: List) : this(content, *(tags.toULongArray()))
+ public constructor(content: Array, vararg tags: ULong) : this(content.toList(), *tags)
+ public constructor(content: Array, tags: List) : this(content, *(tags.toULongArray()))
+
+ public override fun equals(other: Any?): Boolean =
+ other is CborArray && other.content == content && other.rawTags.contentEquals(rawTags)
+
+ public override fun hashCode(): Int = content.hashCode() * 31 + rawTags.contentHashCode()
+
+ override fun toString(): String {
+ return "CborArray(" +
+ "tags=${rawTags.joinToString(prefix = "[", postfix = "]")}, " +
+ "content=$content" +
+ ")"
+ }
+
+}
+
+/**
+ * Creates a copy of this [CborPrimitive] with the specified [tags], discarding any existing tags.
+ */
+@OptIn(ExperimentalSerializationApi::class)
+@Suppress("UNCHECKED_CAST")
+public fun T.copy(vararg tags: ULong): T =
+ when (this) {
+ is CborBoolean -> CborBoolean(value, *tags)
+ is CborByteString -> CborByteString(toByteArray(), *tags)
+ is CborFloat -> CborFloat(value, *tags)
+ is CborInteger -> CborInteger(absoluteValue, isPositive, *tags)
+ is CborNull -> CborNull(*tags)
+ is CborString -> CborString(value, *tags)
+ is CborUndefined -> CborUndefined(*tags)
+ is CborArray -> CborArray(toList(), *tags)
+ is CborMap -> CborMap(toMap(), *tags)
+ } as T
+
+/**
+ * Creates a copy of this [CborPrimitive] with the specified [tags], discarding any existing tags.
+ */
+@OptIn(ExperimentalSerializationApi::class)
+public fun T.copy(tags: List): T = copy(*tags.toULongArray())
+
+
+/*START BOOLEAN*/
+/** Creates copy of this [CborBoolean] with the specified [value], copying all tags.*/
+public fun CborBoolean.copy(value: Boolean): CborBoolean = CborBoolean(value, *(rawTags.copyOf()))
+/** Creates copy of this [CborBoolean] with the specified [value] and [tags].*/
+public fun CborBoolean.copy(value: Boolean, vararg tags: ULong): CborBoolean = CborBoolean(value, *tags)
+/** Creates copy of this [CborBoolean] with the specified [value] and [tags].*/
+public fun CborBoolean.copy(value: Boolean, tags: List): CborBoolean = copy(value, *tags.toULongArray())
+/*END BOOLEAN*/
+
+/*START INTEGER*/
+/** Creates copy of this [CborInteger] with the specified [value], copying all tags.*/
+public fun CborInteger.copy(value: Long): CborInteger = CborInteger(value, *(rawTags.copyOf()))
+/** Creates copy of this [CborInteger] with the specified [value] and [tags].*/
+public fun CborInteger.copy(value: Long, vararg tags: ULong): CborInteger = CborInteger(value, *tags)
+/** Creates copy of this [CborInteger] with the specified [value] and [tags].*/
+public fun CborInteger.copy(value: Long, tags: List): CborInteger = copy(value, *tags.toULongArray())
+
+/** Creates copy of this [CborInteger] with the specified [absoluteValue] and [isPositive], copying all tags.*/
+public fun CborInteger.copy(absoluteValue: ULong, isPositive: Boolean): CborInteger =
+ CborInteger(absoluteValue, isPositive, *(rawTags.copyOf()))
+/** Creates copy of this [CborInteger] with the specified [absoluteValue], [isPositive] and [tags].*/
+public fun CborInteger.copy(absoluteValue: ULong, isPositive: Boolean, vararg tags: ULong): CborInteger =
+ CborInteger(absoluteValue, isPositive, *tags)
+/** Creates copy of this [CborInteger] with the specified [absoluteValue], [isPositive] and [tags].*/
+public fun CborInteger.copy(absoluteValue: ULong, isPositive: Boolean, tags: List): CborInteger =
+ copy(absoluteValue, isPositive, *tags.toULongArray())
+/*END INTEGER*/
+
+/*START FLOAT*/
+/** Creates copy of this [CborFloat] with the specified [value], copying all tags.*/
+public fun CborFloat.copy(value: Double): CborFloat = CborFloat(value, *(rawTags.copyOf()))
+/** Creates copy of this [CborFloat] with the specified [value] and [tags].*/
+public fun CborFloat.copy(value: Double, vararg tags: ULong): CborFloat = CborFloat(value, *tags)
+/** Creates copy of this [CborFloat] with the specified [value] and [tags].*/
+public fun CborFloat.copy(value: Double, tags: List): CborFloat = copy(value, *tags.toULongArray())
+/*END FLOAT*/
+
+/*START STRING*/
+/** Creates copy of this [CborString] with the specified [value], copying all tags.*/
+public fun CborString.copy(value: String): CborString = CborString(value, *(rawTags.copyOf()))
+/** Creates copy of this [CborString] with the specified [value] and [tags].*/
+public fun CborString.copy(value: String, vararg tags: ULong): CborString = CborString(value, *tags)
+/** Creates copy of this [CborString] with the specified [value] and [tags].*/
+public fun CborString.copy(value: String, tags: List): CborString = copy(value, *tags.toULongArray())
+/*END STRING*/
+
+/*START BYTE STRING*/
+/** Creates copy of this [CborByteString] with the specified [bytes], copying all tags.*/
+public fun CborByteString.copy(bytes: ByteArray): CborByteString = CborByteString(bytes, *(rawTags.copyOf()))
+/** Creates copy of this [CborByteString] with the specified [bytes] and [tags].*/
+public fun CborByteString.copy(bytes: ByteArray, vararg tags: ULong): CborByteString = CborByteString(bytes, *tags)
+/** Creates copy of this [CborByteString] with the specified [bytes] and [tags].*/
+public fun CborByteString.copy(bytes: ByteArray, tags: List): CborByteString =
+ copy(bytes, *tags.toULongArray())
+/*END BYTE STRING*/
+
+
+/*START MAP*/
+/** Creates copy of this [CborMap] with the specified [content], copying all tags.*/
+public fun CborMap.copy(content: Map): CborMap = CborMap(content, *(rawTags.copyOf()))
+/** Creates copy of this [CborMap] with the specified [content] and [tags].*/
+public fun CborMap.copy(content: Map, vararg tags: ULong): CborMap = CborMap(content, *tags)
+/** Creates copy of this [CborMap] with the specified [content] and [tags].*/
+public fun CborMap.copy(content: Map, tags: List): CborMap =
+ copy(content, *tags.toULongArray())
+
+/** Creates copy of this [CborMap] with the specified [content], copying all tags.*/
+@JvmName("copyStringMap")
+public fun CborMap.copy(content: Map): CborMap =
+ CborMap(content.mapKeys { (k, _) -> CborString(k) }, *(rawTags.copyOf()))
+
+/** Creates copy of this [CborMap] with the specified [content] and [tags].*/
+@JvmName("copyStringMapVarargs")
+public fun CborMap.copy(content: Map, vararg tags: ULong): CborMap =
+ CborMap(content.mapKeys { (k, _) -> CborString(k) }, *tags)
+
+/** Creates copy of this [CborMap] with the specified [content] and [tags].*/
+@JvmName("copyStringMapList")
+public fun CborMap.copy(content: Map, tags: List): CborMap =
+ copy(content, *tags.toULongArray())
+
+/** Creates copy of this [CborMap] with the specified [content], copying all tags.*/
+@JvmName("copyLongMap")
+public fun CborMap.copy(content: Map): CborMap =
+ CborMap(content.mapKeys { (k, _) -> CborInteger(k) }, *(rawTags.copyOf()))
+
+/** Creates copy of this [CborMap] with the specified [content] and [tags].*/
+@JvmName("copyLongMapVarargs")
+public fun CborMap.copy(content: Map, vararg tags: ULong): CborMap =
+ CborMap(content.mapKeys { (k, _) -> CborInteger(k) }, *tags)
+
+/** Creates copy of this [CborMap] with the specified [content] and [tags].*/
+@JvmName("copyLongMapList")
+public fun CborMap.copy(content: Map, tags: List): CborMap =
+ copy(content, *tags.toULongArray())
+/*END MAP*/
+
+
+/*START ARRAY*/
+/** Creates copy of this [CborArray] with the specified [content], copying all tags.*/
+public fun CborArray.copy(content: List): CborArray = CborArray(content, *(rawTags.copyOf()))
+/** Creates copy of this [CborArray] with the specified [content] and [tags].*/
+public fun CborArray.copy(content: List, vararg tags: ULong): CborArray = CborArray(content, *tags)
+/** Creates copy of this [CborArray] with the specified [content] and [tags].*/
+public fun CborArray.copy(content: List, tags: List): CborArray =
+ copy(content, *tags.toULongArray())
+
+/** Creates copy of this [CborArray] with the specified [content], copying all tags.*/
+public fun CborArray.copy(content: Array): CborArray = CborArray(content, *(rawTags.copyOf()))
+/** Creates copy of this [CborArray] with the specified [content] and [tags].*/
+public fun CborArray.copy(content: Array, vararg tags: ULong): CborArray = CborArray(content, *tags)
+/** Creates copy of this [CborArray] with the specified [content] and [tags].*/
+public fun CborArray.copy(content: Array, tags: List): CborArray =
+ copy(content, *tags.toULongArray())
+/*END ARRAY*/
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborEncoder.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborEncoder.kt
index 7cfead426a..c9a5f97172 100644
--- a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborEncoder.kt
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborEncoder.kt
@@ -5,6 +5,7 @@
package kotlinx.serialization.cbor
import kotlinx.serialization.*
+import kotlinx.serialization.cbor.internal.CborElementSerializer
import kotlinx.serialization.encoding.*
/**
@@ -31,4 +32,34 @@ public interface CborEncoder : Encoder {
* Exposes the current [Cbor] instance and all its configuration flags. Useful for low-level custom serializers.
*/
public val cbor: Cbor
+ /**
+ * Appends the given CBOR [element] to the current output.
+ * This method is allowed to invoke only as the part of the whole serialization process of the class,
+ * calling this method after invoking [beginStructure] or any `encode*` method will lead to unspecified behaviour
+ * and may produce an invalid CBOR result.
+ * For example:
+ * ```
+ * class Holder(val value: Int, val list: List())
+ *
+ * // Holder serialize method
+ * fun serialize(encoder: Encoder, value: Holder) {
+ * // Completely okay, the whole Holder object is read
+ * val cborObject = CborMap(...) // build a CborMap from Holder
+ * (encoder as CborEncoder).encodeCborElement(cborObject) // Write it
+ * }
+ *
+ * // Incorrect Holder serialize method
+ * fun serialize(encoder: Encoder, value: Holder) {
+ * val composite = encoder.beginStructure(descriptor)
+ * composite.encodeSerializableElement(descriptor, 0, Int.serializer(), value.value)
+ * val array = CborArray(value.list.map { CborInt(it.toLong()) })
+ * // Incorrect, encoder is already in an intermediate state after encodeSerializableElement
+ * (composite as CborEncoder).encodeCborElement(array)
+ * composite.endStructure(descriptor)
+ * // ...
+ * }
+ * ```
+ */
+ public fun encodeCborElement(element: CborElement): Unit = encodeSerializableValue(CborElementSerializer, element)
+
}
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborArray.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborObjectAsArray.kt
similarity index 93%
rename from formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborArray.kt
rename to formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborObjectAsArray.kt
index 9727b606ba..41d33ac12e 100644
--- a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborArray.kt
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborObjectAsArray.kt
@@ -11,7 +11,7 @@ import kotlinx.serialization.*
* Example usage:
*
* ```
- * @CborArray
+ * @CborObjectAsArray
* @Serializable
* data class DataClass(
* val alg: Int,
@@ -36,4 +36,4 @@ import kotlinx.serialization.*
@SerialInfo
@Target(AnnotationTarget.CLASS)
@ExperimentalSerializationApi
-public annotation class CborArray
+public annotation class CborObjectAsArray
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/DelicateCborApi.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/DelicateCborApi.kt
new file mode 100644
index 0000000000..704aafff86
--- /dev/null
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/DelicateCborApi.kt
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2017-2026 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.cbor
+
+@MustBeDocumented
+@Target(AnnotationTarget.PROPERTY) // no direct targets, only argument to @SubclassOptInRequired
+@RequiresOptIn(message = "Accessing this property exposes mutable state. Read-Only access is fine, but manipulating it can cause undefined behaviour", level = RequiresOptIn.Level.ERROR)
+public annotation class DelicateCborApi
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Tags.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Tags.kt
index 81ee763b49..80a1a5f72c 100644
--- a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Tags.kt
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Tags.kt
@@ -83,7 +83,7 @@ public annotation class KeyTags(@OptIn(ExperimentalUnsignedTypes::class) vararg
/**
* Specifies that an object of a class annotated using `ObjectTags` shall be tagged and serialized as
- * CBOR major type 6: optional semantic tagging of other major types. Can be combined with [CborArray] and [ValueTags].
+ * CBOR major type 6: optional semantic tagging of other major types. Can be combined with [CborObjectAsArray] and [ValueTags].
* Note that `ObjectTags` will always be encoded directly before to the data of the tagged object, i.e. a value-tagged
* property of an object-tagged type will have the value tags preceding the object tags.
*
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborElementSerializers.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborElementSerializers.kt
new file mode 100644
index 0000000000..8bc0513b1b
--- /dev/null
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborElementSerializers.kt
@@ -0,0 +1,305 @@
+@file:OptIn(ExperimentalSerializationApi::class, ExperimentalUnsignedTypes::class, DelicateCborApi::class)
+
+package kotlinx.serialization.cbor.internal
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.cbor.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+
+internal interface CborSerializer
+
+/**
+ * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [CborElement].
+ * It can only be used by with [Cbor] format and its input ([CborDecoder] and [CborEncoder]).
+ */
+internal object CborElementSerializer : KSerializer, CborSerializer {
+ override val descriptor: SerialDescriptor =
+ buildSerialDescriptor("kotlinx.serialization.cbor.CborElement", PolymorphicKind.SEALED) {
+ // Resolve cyclic dependency in descriptors by late binding
+ element("CborPrimitive", defer { CborPrimitiveSerializer.descriptor })
+ element("CborNull", defer { CborNullSerializer.descriptor })
+ element("CborUndefined", defer { CborUndefinedSerializer.descriptor })
+ element("CborString", defer { CborStringSerializer.descriptor })
+ element("CborBoolean", defer { CborBooleanSerializer.descriptor })
+ element("CborByteString", defer { CborByteStringSerializer.descriptor })
+ element("CborMap", defer { CborMapSerializer.descriptor })
+ element("CborArray", defer { CborArraySerializer.descriptor })
+ element("CborDouble", defer { CborFloatSerializer.descriptor })
+ element("CborInt", defer { CborIntSerializer.descriptor })
+ }
+
+ override fun serialize(encoder: Encoder, value: CborElement) {
+ encoder.asCborWriter()
+
+ // Encode the value
+ when (value) {
+ is CborPrimitive -> encoder.encodeSerializableValue(CborPrimitiveSerializer, value)
+ is CborMap -> encoder.encodeSerializableValue(CborMapSerializer, value)
+ is CborArray -> encoder.encodeSerializableValue(CborArraySerializer, value)
+ }
+ }
+
+ override fun deserialize(decoder: Decoder): CborElement {
+ val input = decoder.asCborDecoder()
+ return input.decodeCborElement()
+ }
+}
+
+/**
+ * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [CborPrimitive].
+ * It can only be used by with [Cbor] format an its input ([CborDecoder] and [CborEncoder]).
+ */
+internal object CborPrimitiveSerializer : KSerializer, CborSerializer {
+ override val descriptor: SerialDescriptor =
+ buildSerialDescriptor("kotlinx.serialization.cbor.CborPrimitive", PolymorphicKind.SEALED)
+
+ override fun serialize(encoder: Encoder, value: CborPrimitive) {
+ when (value) {
+ is CborNull -> encoder.encodeSerializableValue(CborNullSerializer, value)
+ is CborUndefined -> encoder.encodeSerializableValue(CborUndefinedSerializer, value)
+ is CborString -> encoder.encodeSerializableValue(CborStringSerializer, value)
+ is CborBoolean -> encoder.encodeSerializableValue(CborBooleanSerializer, value)
+ is CborByteString -> encoder.encodeSerializableValue(CborByteStringSerializer, value)
+ is CborFloat -> encoder.encodeSerializableValue(CborFloatSerializer, value)
+ is CborInteger -> encoder.encodeSerializableValue(CborIntSerializer, value)
+ }
+ }
+
+ override fun deserialize(decoder: Decoder): CborPrimitive {
+ val result = decoder.asCborDecoder().decodeCborElement()
+ if (result !is CborPrimitive) throw CborDecodingException("Unexpected CBOR element, expected CborPrimitive, had ${result::class}")
+ return result
+ }
+}
+
+/**
+ * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [CborNull].
+ * It can only be used by with [Cbor] format an its input ([CborDecoder] and [CborEncoder]).
+ */
+internal object CborNullSerializer : KSerializer, CborSerializer {
+
+ override val descriptor: SerialDescriptor =
+ buildSerialDescriptor("kotlinx.serialization.cbor.CborNull", SerialKind.ENUM)
+
+ override fun serialize(encoder: Encoder, value: CborNull) {
+ val cborWriter = encoder.asCborWriter()
+ cborWriter.encodeElementTags(value.rawTags)
+ encoder.encodeNull()
+ }
+
+ override fun deserialize(decoder: Decoder): CborNull {
+ val element = decoder.asCborDecoder().decodeCborElement()
+ if (element !is CborNull) throw CborDecodingException("Unexpected CBOR element, expected CborNull, had ${element::class}")
+ return element
+ }
+}
+
+internal object CborUndefinedSerializer : KSerializer, CborSerializer {
+ override val descriptor: SerialDescriptor =
+ buildSerialDescriptor("kotlinx.serialization.cbor.CborUndefined", SerialKind.ENUM)
+
+ override fun serialize(encoder: Encoder, value: CborUndefined) {
+ val cborWriter = encoder.asCborWriter()
+ cborWriter.encodeElementTags(value.rawTags)
+ cborWriter.encodeUndefined()
+ }
+
+ override fun deserialize(decoder: Decoder): CborUndefined {
+ val element = decoder.asCborDecoder().decodeCborElement()
+ if (element !is CborUndefined) throw CborDecodingException("Unexpected CBOR element, expected CborUndefined, had ${element::class}")
+ return element
+ }
+}
+
+
+internal object CborIntSerializer : KSerializer, CborSerializer {
+ override val descriptor: SerialDescriptor =
+ PrimitiveSerialDescriptor("kotlinx.serialization.cbor.CborInt", PrimitiveKind.LONG)
+
+ override fun serialize(encoder: Encoder, value: CborInteger) {
+ val cborWriter = encoder.asCborWriter()
+ cborWriter.encodeElementTags(value.rawTags)
+ when (value.isPositive) {
+ //@formatter:off
+ true -> cborWriter.encodePositive(value.absoluteValue)
+ false -> cborWriter.encodeNegative(value.absoluteValue)
+ //@formatter:on
+ }
+ }
+
+ override fun deserialize(decoder: Decoder): CborInteger {
+ val result = decoder.asCborDecoder().decodeCborElement()
+ if (result !is CborInteger) throw CborDecodingException("Unexpected CBOR element, expected CborInt, had ${result::class}")
+ return result
+ }
+}
+
+internal object CborFloatSerializer : KSerializer, CborSerializer {
+ override val descriptor: SerialDescriptor =
+ PrimitiveSerialDescriptor("kotlinx.serialization.cbor.CborDouble", PrimitiveKind.DOUBLE)
+
+ override fun serialize(encoder: Encoder, value: CborFloat) {
+ val cborWriter = encoder.asCborWriter()
+ cborWriter.encodeElementTags(value.rawTags)
+ encoder.encodeDouble(value.value)
+ }
+
+ override fun deserialize(decoder: Decoder): CborFloat {
+ val element = decoder.asCborDecoder().decodeCborElement()
+ if (element !is CborFloat) throw CborDecodingException("Unexpected CBOR element, expected CborFloat, had ${element::class}")
+ return element
+ }
+}
+
+/**
+ * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [CborString].
+ * It can only be used by with [Cbor] format an its input ([CborDecoder] and [CborEncoder]).
+ */
+internal object CborStringSerializer : KSerializer, CborSerializer {
+ override val descriptor: SerialDescriptor =
+ PrimitiveSerialDescriptor("kotlinx.serialization.cbor.CborString", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: CborString) {
+ val cborWriter = encoder.asCborWriter()
+ cborWriter.encodeElementTags(value.rawTags)
+ encoder.encodeString(value.value)
+ }
+
+ override fun deserialize(decoder: Decoder): CborString {
+ val cborDecoder = decoder.asCborDecoder()
+ val element = cborDecoder.decodeCborElement()
+ if (element !is CborString) throw CborDecodingException("Unexpected CBOR element, expected CborString, had ${element::class}")
+ return element
+ }
+}
+
+/**
+ * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [CborBoolean].
+ * It can only be used by with [Cbor] format an its input ([CborDecoder] and [CborEncoder]).
+ */
+internal object CborBooleanSerializer : KSerializer, CborSerializer {
+ override val descriptor: SerialDescriptor =
+ PrimitiveSerialDescriptor("kotlinx.serialization.cbor.CborBoolean", PrimitiveKind.BOOLEAN)
+
+ override fun serialize(encoder: Encoder, value: CborBoolean) {
+ val cborWriter = encoder.asCborWriter()
+ cborWriter.encodeElementTags(value.rawTags)
+ encoder.encodeBoolean(value.value)
+ }
+
+ override fun deserialize(decoder: Decoder): CborBoolean {
+ val cborDecoder = decoder.asCborDecoder()
+ val element = cborDecoder.decodeCborElement()
+ if (element !is CborBoolean) throw CborDecodingException("Unexpected CBOR element, expected CborBoolean, had ${element::class}")
+ return element
+ }
+}
+
+/**
+ * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [CborByteString].
+ * It can only be used by with [Cbor] format and its input ([CborDecoder] and [CborEncoder]).
+ */
+internal object CborByteStringSerializer : KSerializer, CborSerializer {
+ override val descriptor: SerialDescriptor =
+ SerialDescriptor("kotlinx.serialization.cbor.CborByteString", ByteArraySerializer().descriptor)
+
+ override fun serialize(encoder: Encoder, value: CborByteString) {
+ val cborWriter = encoder.asCborWriter()
+ cborWriter.encodeElementTags(value.rawTags)
+ cborWriter.encodeByteString(value.getBytes())
+ }
+
+ override fun deserialize(decoder: Decoder): CborByteString {
+ val cborDecoder = decoder.asCborDecoder()
+ val element = cborDecoder.decodeCborElement()
+ if (element !is CborByteString) throw CborDecodingException("Unexpected CBOR element, expected CborByteString, had ${element::class}")
+ return element
+ }
+}
+
+/**
+ * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [CborMap].
+ * It can only be used by with [Cbor] format and its input ([CborDecoder] and [CborEncoder]).
+ */
+internal object CborMapSerializer : KSerializer, CborSerializer {
+ override val descriptor: SerialDescriptor =
+ SerialDescriptor(
+ serialName = "kotlinx.serialization.cbor.CborMap",
+ original = MapSerializer(CborElementSerializer, CborElementSerializer).descriptor
+ )
+
+ override fun serialize(encoder: Encoder, value: CborMap) {
+ val cborWriter = encoder.asCborWriter()
+ cborWriter.encodeElementTags(value.rawTags)
+ MapSerializer(CborElementSerializer, CborElementSerializer).serialize(encoder, value)
+ }
+
+ override fun deserialize(decoder: Decoder): CborMap {
+ val element = decoder.asCborDecoder().decodeCborElement()
+ if (element !is CborMap) throw CborDecodingException("Unexpected CBOR element, expected CborMap, had ${element::class}")
+ return element
+ }
+}
+
+/**
+ * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [CborArray].
+ * It can only be used by with [Cbor] format an its input ([CborDecoder] and [CborEncoder]).
+ */
+internal object CborArraySerializer : KSerializer, CborSerializer {
+ override val descriptor: SerialDescriptor =
+ SerialDescriptor(
+ serialName = "kotlinx.serialization.cbor.CborArray",
+ original = ListSerializer(CborElementSerializer).descriptor
+ )
+
+ override fun serialize(encoder: Encoder, value: CborArray) {
+ val cborWriter = encoder.asCborWriter()
+ cborWriter.encodeElementTags(value.rawTags)
+ ListSerializer(CborElementSerializer).serialize(encoder, value)
+ }
+
+ override fun deserialize(decoder: Decoder): CborArray {
+ val element = decoder.asCborDecoder().decodeCborElement()
+ if (element !is CborArray) throw CborDecodingException("Unexpected CBOR element, expected CborArray, had ${element::class}")
+ return element
+ }
+}
+
+
+internal fun Decoder.asCborDecoder(): CborDecoder = this as? CborDecoder
+ ?: throw IllegalStateException(
+ "This serializer can be used only with Cbor format. " +
+ "Expected Decoder to be CborDecoder, got ${this::class}"
+ )
+
+/*need to expose writer to access raw CBOR token operations*/
+@IgnorableReturnValue
+internal fun Encoder.asCborWriter() = this as? CborWriter
+ ?: throw IllegalStateException(
+ "This serializer can be used only with Cbor format. " +
+ "Expected Encoder to provide a CborWriterInterface, got ${this::class}"
+ )
+
+/**
+ * Returns serial descriptor that delegates all the calls to descriptor returned by [deferred] block.
+ * Used to resolve cyclic dependencies between recursive serializable structures.
+ */
+@OptIn(ExperimentalSerializationApi::class)
+private fun defer(deferred: () -> SerialDescriptor): SerialDescriptor = object : SerialDescriptor {
+ private val original: SerialDescriptor by lazy(deferred)
+
+ override val serialName: String
+ get() = original.serialName
+ override val kind: SerialKind
+ get() = original.kind
+ override val elementsCount: Int
+ get() = original.elementsCount
+
+ override fun getElementName(index: Int): String = original.getElementName(index)
+ override fun getElementIndex(name: String): Int = original.getElementIndex(name)
+ override fun getElementAnnotations(index: Int): List = original.getElementAnnotations(index)
+ override fun getElementDescriptor(index: Int): SerialDescriptor = original.getElementDescriptor(index)
+ override fun isElementOptional(index: Int): Boolean = original.isElementOptional(index)
+}
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborParser.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborParser.kt
new file mode 100644
index 0000000000..3397b457bd
--- /dev/null
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborParser.kt
@@ -0,0 +1,41 @@
+@file:OptIn(ExperimentalSerializationApi::class, ExperimentalUnsignedTypes::class)
+
+package kotlinx.serialization.cbor.internal
+
+import kotlinx.serialization.*
+
+/**
+ * Common interface for CBOR parsers that can read CBOR data from different sources.
+ */
+internal sealed interface CborParser {
+ // Basic state checks
+ fun isNull(): Boolean
+ fun isEnd(): Boolean
+ fun end()
+
+ // Collection operations
+ fun startArray(tags: ULongArray? = null): Int
+ fun startMap(tags: ULongArray? = null): Int
+
+ // Value reading operations
+ fun nextNull(tags: ULongArray? = null): Nothing?
+ fun nextBoolean(tags: ULongArray? = null): Boolean
+ fun nextNumber(tags: ULongArray? = null): Long
+ fun nextString(tags: ULongArray? = null): String
+ fun nextByteString(tags: ULongArray? = null): ByteArray
+ fun nextDouble(tags: ULongArray? = null): Double
+ fun nextFloat(tags: ULongArray? = null): Float
+
+ // Map key operations
+ fun nextTaggedStringOrNumber(): Triple
+
+ // Skip operations
+ //used only to skip unknown elements
+ fun skipElement(tags: ULongArray?)
+
+ // Tag verification
+ fun verifyTagsAndThrow(expected: ULongArray, actual: ULongArray?)
+
+ @IgnorableReturnValue
+ fun processTags(tags: ULongArray?): ULongArray?
+}
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborTreeReader.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborTreeReader.kt
new file mode 100644
index 0000000000..d06fde8d51
--- /dev/null
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborTreeReader.kt
@@ -0,0 +1,145 @@
+@file:OptIn(ExperimentalSerializationApi::class, ExperimentalUnsignedTypes::class)
+
+package kotlinx.serialization.cbor.internal
+
+import kotlinx.serialization.*
+import kotlinx.serialization.cbor.*
+
+/**
+ * [CborTreeReader] reads CBOR data from [parser] and constructs a [CborElement] tree.
+ */
+internal class CborTreeReader(
+ //no config values make sense here, because we have no "schema".
+ //we cannot validate tags, or disregard nulls, can we?!
+ //still, this needs to go here, in case it evolves to a point where we need to respect certain config values
+ private val configuration: CborConfiguration,
+ private val parser: CborParserImpl
+) {
+ /**
+ * Reads the next CBOR element from the parser.
+ */
+ fun read(): CborElement {
+ // Read any tags before the actual value
+ val tags = readTags()
+
+ val result = when (parser.curByte shr 5) { // Get major type from the first 3 bits
+ 0 -> { // Major type 0: unsigned integer
+ val value = parser.nextULong()
+ CborInteger(value, isPositive = true, tags = tags)
+ }
+
+ 1 -> { // Major type 1: negative integer
+ val value = parser.nextULong() + 1uL
+ CborInteger(value, isPositive = false, tags = tags)
+ }
+
+ 2 -> { // Major type 2: byte string
+ CborByteString(parser.nextByteString(), tags = tags)
+ }
+
+ 3 -> { // Major type 3: text string
+ CborString(parser.nextString(), tags = tags)
+ }
+
+ 4 -> { // Major type 4: array
+ readArray(tags)
+ }
+
+ 5 -> { // Major type 5: map
+ readMap(tags)
+ }
+
+ 7 -> { // Major type 7: simple/float/break
+ when (parser.curByte) {
+ 0xF4 -> {
+ CborBoolean(parser.nextBoolean(null), tags = tags)
+ }
+
+ 0xF5 -> {
+ CborBoolean(parser.nextBoolean(null), tags = tags)
+ }
+
+ 0xF6 -> {
+ parser.nextNull(null)
+ CborNull(tags = tags)
+ }
+
+ 0xF7 -> {
+ parser.skipElement(null)
+ CborUndefined(tags = tags)
+ }
+ // Half/Float32/Float64
+ NEXT_HALF, NEXT_FLOAT, NEXT_DOUBLE -> CborFloat(parser.nextDouble(null), tags = tags)
+ else -> throw CborDecodingException(
+ "Invalid simple value or float type: ${parser.curByte.toString(16).uppercase()}"
+ )
+ }
+ }
+
+ else -> {
+ val errByte = parser.curByte shr 5
+ throw if (errByte == -1) CborDecodingException("Unexpected EOF")
+ else CborDecodingException("Invalid CBOR major type: $errByte")
+ }
+ }
+ return result
+ }
+
+ /**
+ * Reads any tags preceding the current value.
+ * @return An array of tags, possibly empty
+ */
+ private fun readTags(): ULongArray {
+ if ((parser.curByte shr 5) != 6) return EMPTY_TAGS
+
+ val tags = mutableListOf()
+ while ((parser.curByte shr 5) == 6) { // Major type 6: tag
+ tags.add(parser.nextTag())
+ }
+ return tags.toULongArray()
+ }
+
+ private fun readArray(tags: ULongArray): CborArray {
+ val size = parser.startArray(null)
+ val elements = mutableListOf()
+
+ if (size >= 0) {
+ // Definite length array
+ repeat(size) {
+ elements.add(read())
+ }
+ } else {
+ // Indefinite length array
+ while (!parser.isEnd()) {
+ elements.add(read())
+ }
+ parser.end()
+ }
+
+ return CborArray(elements, tags = tags)
+ }
+
+ private fun readMap(tags: ULongArray): CborMap {
+ val size = parser.startMap(null)
+ val elements = mutableMapOf