Skip to content

Commit 89d671c

Browse files
committed
refactor cborint
1 parent 259966f commit 89d671c

File tree

11 files changed

+328
-215
lines changed

11 files changed

+328
-215
lines changed

docs/formats.md

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ The main concept in this part of the library is [CborElement]. Read on to learn
332332
#### Encoding from/to `CborElement`
333333

334334
Bytes can be decoded into an instance of `CborElement` with the [Cbor.decodeFromByteArray] function by either manually
335-
specifying [CborElement.serializer()] or specifying [CborElement] as generic type parameter.
335+
specifying `CborElement.serializer()` or specifying [CborElement] as generic type parameter.
336336
It is also possible to encode arbitrary serializable structures to a `CborElement` through [Cbor.encodeToCborElement].
337337

338338
Since these operations use the same code paths as regular serialization (but with specialized serializers), the config flags
@@ -417,18 +417,16 @@ A [CborElement] class has three direct subtypes, closely following CBOR grammar:
417417
`CborPrimitive` is itself an umbrella type (a sealed class) for the following concrete primitives:
418418
* [CborNull] mapping to a Kotlin `null`
419419
* [CborBoolean] mapping to a Kotlin `Boolean`
420-
* [CborInt] which is an umbrella type (a sealed class) itself for the following concrete types
421-
(it is still possible to instantiate it as the `invoke` operator on its companion is overridden accordingly):
422-
* [CborPositiveInt] represents all `Long` numbers `≥0`
423-
* [CborNegativeInt] represents all `Long` numbers `<0`
420+
* [CborInt] represents signed CBOR integer (major type 1 encompassing `-2^64..-1`) and unsigned CBOR integer (major type 0 encompassing `0..2^64-1`).
421+
Since this exceeds the range of Kotlin's built-in `Long` type, CborInt consists of `sign` (set to `CborInt.Sing.POSITIVE`, `CborInt.Sing.NEGATIVE`, or `CborInt.Sing.ZERO`) and `value` representing the absolute value as an `ULong`. It also features a `toLong()` function, albeit incurring possible truncation for negative values exceeding `Long.MIN_VALUE`.
424422
* [CborString] maps to a Kotlin `String`
425423
* [CborFloat] maps to Kotlin `Double`
426424
* [CborByteString] maps to a Kotlin `ByteArray` and is used to encode them as CBOR byte string (in contrast to a list
427425
of individual bytes)
428426

429-
* [CborList] represents a CBOR array. It is a Kotlin [List] of `CborElement` items.
427+
* [CborList] represents a CBOR array. It is a Kotlin `List` of `CborElement` items.
430428

431-
* [CborMap] represents a CBOR map/object. It is a Kotlin [Map] from `CborElement` keys to `CborElement` values.
429+
* [CborMap] represents a CBOR map/object. It is a Kotlin `Map` from `CborElement` keys to `CborElement` values.
432430
This is typically the result of serializing an arbitrary
433431

434432

@@ -1797,8 +1795,6 @@ This chapter concludes [Kotlin Serialization Guide](serialization-guide.md).
17971795
[CborNull]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-null/index.html
17981796
[CborBoolean]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-boolean/index.html
17991797
[CborInt]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-int/index.html
1800-
[CborPositiveInt]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-positive-int/index.html
1801-
[CborNegativeInt]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-negative-int/index.html
18021798
[CborString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-string/index.html
18031799
[CborFloat]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-float/index.html
18041800
[CborByteString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-byte-string/index.html

formats/cbor/api/kotlinx-serialization-cbor.api

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,29 @@ public final class kotlinx/serialization/cbor/CborFloat$Companion {
133133
public final fun serializer ()Lkotlinx/serialization/KSerializer;
134134
}
135135

136-
public abstract class kotlinx/serialization/cbor/CborInt : kotlinx/serialization/cbor/CborPrimitive {
136+
public final class kotlinx/serialization/cbor/CborInt : kotlinx/serialization/cbor/CborPrimitive {
137137
public static final field Companion Lkotlinx/serialization/cbor/CborInt$Companion;
138-
public synthetic fun <init> ([JLjava/lang/Object;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
139-
public synthetic fun <init> ([JLjava/lang/Object;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
138+
public synthetic fun <init> (JLkotlinx/serialization/cbor/CborInt$Sign;[JLkotlin/jvm/internal/DefaultConstructorMarker;)V
139+
public fun equals (Ljava/lang/Object;)Z
140+
public final fun getSign ()Lkotlinx/serialization/cbor/CborInt$Sign;
141+
public fun hashCode ()I
142+
public final fun toLong ()J
143+
public fun toString ()Ljava/lang/String;
140144
}
141145

142146
public final class kotlinx/serialization/cbor/CborInt$Companion {
143147
public final fun invoke-SIFponk (J[J)Lkotlinx/serialization/cbor/CborInt;
144148
public final fun invoke-ahITK_k (J[J)Lkotlinx/serialization/cbor/CborInt;
145-
public final fun serializer (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;
149+
public final fun serializer ()Lkotlinx/serialization/KSerializer;
150+
}
151+
152+
public final class kotlinx/serialization/cbor/CborInt$Sign : java/lang/Enum {
153+
public static final field NEGATIVE Lkotlinx/serialization/cbor/CborInt$Sign;
154+
public static final field POSITIVE Lkotlinx/serialization/cbor/CborInt$Sign;
155+
public static final field ZERO Lkotlinx/serialization/cbor/CborInt$Sign;
156+
public static fun getEntries ()Lkotlin/enums/EnumEntries;
157+
public static fun valueOf (Ljava/lang/String;)Lkotlinx/serialization/cbor/CborInt$Sign;
158+
public static fun values ()[Lkotlinx/serialization/cbor/CborInt$Sign;
146159
}
147160

148161
public final class kotlinx/serialization/cbor/CborKt {
@@ -255,15 +268,6 @@ public final class kotlinx/serialization/cbor/CborMap$Companion {
255268
public final fun serializer ()Lkotlinx/serialization/KSerializer;
256269
}
257270

258-
public final class kotlinx/serialization/cbor/CborNegativeInt : kotlinx/serialization/cbor/CborInt {
259-
public static final field Companion Lkotlinx/serialization/cbor/CborNegativeInt$Companion;
260-
public synthetic fun <init> (J[JLkotlin/jvm/internal/DefaultConstructorMarker;)V
261-
}
262-
263-
public final class kotlinx/serialization/cbor/CborNegativeInt$Companion {
264-
public final fun serializer ()Lkotlinx/serialization/KSerializer;
265-
}
266-
267271
public final class kotlinx/serialization/cbor/CborNull : kotlinx/serialization/cbor/CborPrimitive {
268272
public static final field Companion Lkotlinx/serialization/cbor/CborNull$Companion;
269273
public synthetic fun <init> ([JLkotlin/jvm/internal/DefaultConstructorMarker;)V
@@ -273,15 +277,6 @@ public final class kotlinx/serialization/cbor/CborNull$Companion {
273277
public final fun serializer ()Lkotlinx/serialization/KSerializer;
274278
}
275279

276-
public final class kotlinx/serialization/cbor/CborPositiveInt : kotlinx/serialization/cbor/CborInt {
277-
public static final field Companion Lkotlinx/serialization/cbor/CborPositiveInt$Companion;
278-
public synthetic fun <init> (J[JLkotlin/jvm/internal/DefaultConstructorMarker;)V
279-
}
280-
281-
public final class kotlinx/serialization/cbor/CborPositiveInt$Companion {
282-
public final fun serializer ()Lkotlinx/serialization/KSerializer;
283-
}
284-
285280
public abstract class kotlinx/serialization/cbor/CborPrimitive : kotlinx/serialization/cbor/CborElement {
286281
public static final field Companion Lkotlinx/serialization/cbor/CborPrimitive$Companion;
287282
public synthetic fun <init> (Ljava/lang/Object;[JILkotlin/jvm/internal/DefaultConstructorMarker;)V

formats/cbor/api/kotlinx-serialization-cbor.klib.api

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,36 @@ final class kotlinx.serialization.cbor/CborFloat : kotlinx.serialization.cbor/Cb
148148
}
149149
}
150150

151+
final class kotlinx.serialization.cbor/CborInt : kotlinx.serialization.cbor/CborPrimitive<kotlin/ULong> { // kotlinx.serialization.cbor/CborInt|null[0]
152+
constructor <init>(kotlin/ULong, kotlinx.serialization.cbor/CborInt.Sign, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborInt.<init>|<init>(kotlin.ULong;kotlinx.serialization.cbor.CborInt.Sign;kotlin.ULongArray...){}[0]
153+
154+
final val sign // kotlinx.serialization.cbor/CborInt.sign|{}sign[0]
155+
final fun <get-sign>(): kotlinx.serialization.cbor/CborInt.Sign // kotlinx.serialization.cbor/CborInt.sign.<get-sign>|<get-sign>(){}[0]
156+
157+
final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.cbor/CborInt.equals|equals(kotlin.Any?){}[0]
158+
final fun hashCode(): kotlin/Int // kotlinx.serialization.cbor/CborInt.hashCode|hashCode(){}[0]
159+
final fun toLong(): kotlin/Long // kotlinx.serialization.cbor/CborInt.toLong|toLong(){}[0]
160+
final fun toString(): kotlin/String // kotlinx.serialization.cbor/CborInt.toString|toString(){}[0]
161+
162+
final enum class Sign : kotlin/Enum<kotlinx.serialization.cbor/CborInt.Sign> { // kotlinx.serialization.cbor/CborInt.Sign|null[0]
163+
enum entry NEGATIVE // kotlinx.serialization.cbor/CborInt.Sign.NEGATIVE|null[0]
164+
enum entry POSITIVE // kotlinx.serialization.cbor/CborInt.Sign.POSITIVE|null[0]
165+
enum entry ZERO // kotlinx.serialization.cbor/CborInt.Sign.ZERO|null[0]
166+
167+
final val entries // kotlinx.serialization.cbor/CborInt.Sign.entries|#static{}entries[0]
168+
final fun <get-entries>(): kotlin.enums/EnumEntries<kotlinx.serialization.cbor/CborInt.Sign> // kotlinx.serialization.cbor/CborInt.Sign.entries.<get-entries>|<get-entries>#static(){}[0]
169+
170+
final fun valueOf(kotlin/String): kotlinx.serialization.cbor/CborInt.Sign // kotlinx.serialization.cbor/CborInt.Sign.valueOf|valueOf#static(kotlin.String){}[0]
171+
final fun values(): kotlin/Array<kotlinx.serialization.cbor/CborInt.Sign> // kotlinx.serialization.cbor/CborInt.Sign.values|values#static(){}[0]
172+
}
173+
174+
final object Companion { // kotlinx.serialization.cbor/CborInt.Companion|null[0]
175+
final fun invoke(kotlin/Long, kotlin/ULongArray...): kotlinx.serialization.cbor/CborInt // kotlinx.serialization.cbor/CborInt.Companion.invoke|invoke(kotlin.Long;kotlin.ULongArray...){}[0]
176+
final fun invoke(kotlin/ULong, kotlin/ULongArray...): kotlinx.serialization.cbor/CborInt // kotlinx.serialization.cbor/CborInt.Companion.invoke|invoke(kotlin.ULong;kotlin.ULongArray...){}[0]
177+
final fun serializer(): kotlinx.serialization/KSerializer<kotlinx.serialization.cbor/CborInt> // kotlinx.serialization.cbor/CborInt.Companion.serializer|serializer(){}[0]
178+
}
179+
}
180+
151181
final class kotlinx.serialization.cbor/CborList : kotlin.collections/List<kotlinx.serialization.cbor/CborElement>, kotlinx.serialization.cbor/CborElement { // kotlinx.serialization.cbor/CborList|null[0]
152182
constructor <init>(kotlin.collections/List<kotlinx.serialization.cbor/CborElement>, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborList.<init>|<init>(kotlin.collections.List<kotlinx.serialization.cbor.CborElement>;kotlin.ULongArray...){}[0]
153183

@@ -204,14 +234,6 @@ final class kotlinx.serialization.cbor/CborMap : kotlin.collections/Map<kotlinx.
204234
final fun asJsReadonlyMapView(): kotlin.js.collections/JsReadonlyMap<kotlinx.serialization.cbor/CborElement, kotlinx.serialization.cbor/CborElement> // kotlinx.serialization.cbor/CborMap.asJsReadonlyMapView|asJsReadonlyMapView(){}[0]
205235
}
206236

207-
final class kotlinx.serialization.cbor/CborNegativeInt : kotlinx.serialization.cbor/CborInt<kotlin/Long> { // kotlinx.serialization.cbor/CborNegativeInt|null[0]
208-
constructor <init>(kotlin/Long, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborNegativeInt.<init>|<init>(kotlin.Long;kotlin.ULongArray...){}[0]
209-
210-
final object Companion { // kotlinx.serialization.cbor/CborNegativeInt.Companion|null[0]
211-
final fun serializer(): kotlinx.serialization/KSerializer<kotlinx.serialization.cbor/CborNegativeInt> // kotlinx.serialization.cbor/CborNegativeInt.Companion.serializer|serializer(){}[0]
212-
}
213-
}
214-
215237
final class kotlinx.serialization.cbor/CborNull : kotlinx.serialization.cbor/CborPrimitive<kotlin/Unit> { // kotlinx.serialization.cbor/CborNull|null[0]
216238
constructor <init>(kotlin/ULongArray...) // kotlinx.serialization.cbor/CborNull.<init>|<init>(kotlin.ULongArray...){}[0]
217239

@@ -220,14 +242,6 @@ final class kotlinx.serialization.cbor/CborNull : kotlinx.serialization.cbor/Cbo
220242
}
221243
}
222244

223-
final class kotlinx.serialization.cbor/CborPositiveInt : kotlinx.serialization.cbor/CborInt<kotlin/ULong> { // kotlinx.serialization.cbor/CborPositiveInt|null[0]
224-
constructor <init>(kotlin/ULong, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborPositiveInt.<init>|<init>(kotlin.ULong;kotlin.ULongArray...){}[0]
225-
226-
final object Companion { // kotlinx.serialization.cbor/CborPositiveInt.Companion|null[0]
227-
final fun serializer(): kotlinx.serialization/KSerializer<kotlinx.serialization.cbor/CborPositiveInt> // kotlinx.serialization.cbor/CborPositiveInt.Companion.serializer|serializer(){}[0]
228-
}
229-
}
230-
231245
final class kotlinx.serialization.cbor/CborString : kotlinx.serialization.cbor/CborPrimitive<kotlin/String> { // kotlinx.serialization.cbor/CborString|null[0]
232246
constructor <init>(kotlin/String, kotlin/ULongArray...) // kotlinx.serialization.cbor/CborString.<init>|<init>(kotlin.String;kotlin.ULongArray...){}[0]
233247

@@ -236,15 +250,6 @@ final class kotlinx.serialization.cbor/CborString : kotlinx.serialization.cbor/C
236250
}
237251
}
238252

239-
sealed class <#A: kotlin/Any> kotlinx.serialization.cbor/CborInt : kotlinx.serialization.cbor/CborPrimitive<#A> { // kotlinx.serialization.cbor/CborInt|null[0]
240-
final object Companion : kotlinx.serialization.internal/SerializerFactory { // kotlinx.serialization.cbor/CborInt.Companion|null[0]
241-
final fun <#A2: kotlin/Any?> serializer(kotlinx.serialization/KSerializer<#A2>): kotlinx.serialization/KSerializer<kotlinx.serialization.cbor/CborInt<#A2>> // kotlinx.serialization.cbor/CborInt.Companion.serializer|serializer(kotlinx.serialization.KSerializer<0:0>){0§<kotlin.Any?>}[0]
242-
final fun invoke(kotlin/Long, kotlin/ULongArray...): kotlinx.serialization.cbor/CborInt<*> // kotlinx.serialization.cbor/CborInt.Companion.invoke|invoke(kotlin.Long;kotlin.ULongArray...){}[0]
243-
final fun invoke(kotlin/ULong, kotlin/ULongArray...): kotlinx.serialization.cbor/CborInt<kotlin/ULong> // kotlinx.serialization.cbor/CborInt.Companion.invoke|invoke(kotlin.ULong;kotlin.ULongArray...){}[0]
244-
final fun serializer(kotlin/Array<out kotlinx.serialization/KSerializer<*>>...): kotlinx.serialization/KSerializer<*> // kotlinx.serialization.cbor/CborInt.Companion.serializer|serializer(kotlin.Array<out|kotlinx.serialization.KSerializer<*>>...){}[0]
245-
}
246-
}
247-
248253
sealed class <#A: kotlin/Any> kotlinx.serialization.cbor/CborPrimitive : kotlinx.serialization.cbor/CborElement { // kotlinx.serialization.cbor/CborPrimitive|null[0]
249254
final val value // kotlinx.serialization.cbor/CborPrimitive.value|{}value[0]
250255
final fun <get-value>(): #A // kotlinx.serialization.cbor/CborPrimitive.value.<get-value>|<get-value>(){}[0]

formats/cbor/commonMain/src/kotlinx/serialization/cbor/CborElement.kt

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -90,61 +90,90 @@ public sealed class CborPrimitive<T : Any>(
9090

9191
/**
9292
* Class representing either:
93-
* * signed CBOR integer (major type 1)
94-
* * unsigned CBOR integer (major type 0)
93+
* * signed CBOR integer (major type 1 encompassing `-2^64..-1`)
94+
* * unsigned CBOR integer (major type 0 encompassing `0..2^64-1`)
9595
*
96-
* depending on whether a positive or a negative number was passed.
96+
* depending on the value of [sign]. Note that [absoluteValue] **must** be `0` when sign is set to [Sign.ZERO]
9797
*/
9898
@Serializable(with = CborIntSerializer::class)
99-
public sealed class CborInt<T : Any>(
100-
tags: ULongArray = ulongArrayOf(),
101-
value: T,
102-
) : CborPrimitive<T>(value, tags) {
99+
public class CborInt(
100+
absoluteValue: ULong,
101+
public val sign: Sign,
102+
vararg tags: ULong
103+
) : CborPrimitive<ULong>(absoluteValue, tags) {
104+
105+
init {
106+
if (sign == Sign.ZERO) require(absoluteValue == 0uL) { "Illegal absolute value $absoluteValue for Sign.ZERO" }
107+
}
108+
109+
public enum class Sign {
110+
POSITIVE,
111+
NEGATIVE,
112+
ZERO
113+
}
114+
115+
/**
116+
* **WARNING! Possible truncation!** E.g., `-2^64` -> `-1`
117+
*/
118+
public fun toLong(): Long = when (sign) {
119+
Sign.POSITIVE, Sign.ZERO -> value.toLong()
120+
Sign.NEGATIVE -> -value.toLong()
121+
}
122+
123+
103124
public companion object {
104125
/**
105126
* Creates:
106-
* * signed CBOR integer (major type 1)
107-
* * unsigned CBOR integer (major type 0)
127+
* * signed CBOR integer (major type 1 encompassing `-2^64..-1`)
128+
* * unsigned CBOR integer (major type 0 encompassing `0..2^64-1`)
108129
*
109130
* depending on whether a positive or a negative number was passed.
131+
* If you want to create a negative number exceeding [Long.MIN_VALUE], manually specify sign: `CborInt(ULong.MAX_VALUE, CborInt.Sign.NEGATIVE)`
110132
*/
111133
public operator fun invoke(
112134
value: Long,
113135
vararg tags: ULong
114-
): CborInt<*> =
115-
if (value >= 0) CborPositiveInt(value.toULong(), tags = tags) else CborNegativeInt(value, tags = tags)
136+
): CborInt =
137+
if (value == 0L) CborInt(value.toULong(), Sign.ZERO, tags = tags)
138+
else if (value > 0L) CborInt(value.toULong(), Sign.POSITIVE, tags = tags)
139+
else CborInt(ULong.MAX_VALUE - value.toULong() + 1uL, Sign.NEGATIVE, tags = tags)
116140

117141
/**
118142
* Creates an unsigned CBOR integer (major type 0).
119143
*/
120144
public operator fun invoke(
121145
value: ULong,
122146
vararg tags: ULong
123-
): CborInt<ULong> = CborPositiveInt(value, tags = tags)
147+
): CborInt = if (value == 0uL) CborInt(value, Sign.ZERO, tags = tags)
148+
else CborInt(value, Sign.POSITIVE, tags = tags)
124149
}
125-
}
126150

127-
/**
128-
* Class representing signed CBOR integer (major type 1).
129-
*/
130-
@Serializable(with = CborNegativeIntSerializer::class)
131-
public class CborNegativeInt(
132-
value: Long,
133-
vararg tags: ULong
134-
) : CborInt<Long>(tags, value) {
135-
init {
136-
require(value < 0) { "Number must be negative: $value" }
151+
override fun equals(other: Any?): Boolean {
152+
if (this === other) return true
153+
if (other !is CborInt) return false
154+
if (!super.equals(other)) return false
155+
156+
if (sign != other.sign) return false
157+
158+
return true
137159
}
138-
}
139160

140-
/**
141-
* Class representing unsigned CBOR integer (major type 0).
142-
*/
143-
@Serializable(with = CborPositiveIntSerializer::class)
144-
public class CborPositiveInt(
145-
value: ULong,
146-
vararg tags: ULong
147-
) : CborInt<ULong>(tags, value)
161+
override fun hashCode(): Int {
162+
var result = super.hashCode()
163+
result = 31 * result + sign.hashCode()
164+
return result
165+
}
166+
167+
override fun toString(): String {
168+
return "CborInt(tags=${tags.joinToString(prefix = "[", postfix = "]")}, " +
169+
"value=" + when (sign) {
170+
Sign.POSITIVE, Sign.ZERO -> ""
171+
Sign.NEGATIVE -> "-"
172+
} +
173+
value +
174+
")"
175+
}
176+
}
148177

149178
/**
150179
* Class representing CBOR floating point value (major type 7).

0 commit comments

Comments
 (0)