Skip to content

Commit d561069

Browse files
committed
proper when for decoding
1 parent 1d3574c commit d561069

File tree

5 files changed

+232
-334
lines changed

5 files changed

+232
-334
lines changed

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

Lines changed: 62 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -28,136 +28,66 @@ public sealed class CborElement
2828
*/
2929
@Serializable(with = CborPrimitiveSerializer::class)
3030
public sealed class CborPrimitive : CborElement() {
31-
/**
32-
* Content of given element as string. For [CborNull], this method returns a "null" string.
33-
* [CborPrimitive.contentOrNull] should be used for [CborNull] to get a `null`.
34-
*/
35-
public abstract val content: String
3631

37-
public override fun toString(): String = content
3832
}
3933

4034
/**
41-
* Sealed class representing CBOR number value.
42-
* Can be either [Signed] or [Unsigned].
35+
* Class representing signed CBOR integer (major type 1).
4336
*/
44-
@Serializable(with = CborNumberSerializer::class)
45-
public sealed class CborNumber : CborPrimitive() {
46-
/**
47-
* Returns the value as a [Byte].
48-
*/
49-
public abstract val byte: Byte
37+
@Serializable(with = CborIntSerializer::class)
38+
public class CborNegativeInt(public val value: Long) : CborPrimitive() {
39+
init {
40+
require(value < 0) { "Number must be negative: $value" }
41+
}
5042

51-
/**
52-
* Returns the value as a [Short].
53-
*/
54-
public abstract val short: Short
43+
override fun equals(other: Any?): Boolean {
44+
if (this === other) return true
45+
if (other == null || this::class != other::class) return false
46+
other as CborNegativeInt
47+
return value == other.value
48+
}
5549

56-
/**
57-
* Returns the value as an [Int].
58-
*/
59-
public abstract val int: Int
50+
override fun hashCode(): Int = value.hashCode()
51+
}
6052

61-
/**
62-
* Returns the value as a [Long].
63-
*/
64-
public abstract val long: Long
53+
/**
54+
* Class representing unsigned CBOR integer (major type 0).
55+
*/
56+
@Serializable(with = CborUIntSerializer::class)
57+
public class CborPositiveInt(public val value: ULong) : CborPrimitive() {
6558

66-
/**
67-
* Returns the value as a [Float].
68-
*/
69-
public abstract val float: Float
59+
override fun equals(other: Any?): Boolean {
60+
if (this === other) return true
61+
if (other == null || this::class != other::class) return false
62+
other as CborPositiveInt
63+
return value == other.value
64+
}
7065

71-
/**
72-
* Returns the value as a [Double].
73-
*/
74-
public abstract val double: Double
66+
override fun hashCode(): Int = value.hashCode()
67+
}
7568

76-
/**
77-
* Class representing a signed CBOR number value.
78-
*/
79-
public class Signed(@Contextual private val value: Number) : CborNumber() {
80-
override val content: String get() = value.toString()
81-
override val byte: Byte get() = value.toByte()
82-
override val short: Short get() = value.toShort()
83-
override val int: Int get() = value.toInt()
84-
override val long: Long get() = value.toLong()
85-
override val float: Float get() = value.toFloat()
86-
override val double: Double get() = value.toDouble()
87-
88-
override fun equals(other: Any?): Boolean {
89-
if (this === other) return true
90-
if (other == null) return false
91-
92-
when (other) {
93-
is Signed -> {
94-
// Compare as double to handle different numeric types
95-
return when {
96-
// For integers, compare as long to avoid precision loss
97-
value is Byte || value is Short || value is Int || value is Long ||
98-
other.value is Byte || other.value is Short || other.value is Int || other.value is Long -> {
99-
value.toLong() == other.value.toLong()
100-
}
101-
// For floating point, compare as double
102-
else -> {
103-
value.toDouble() == other.value.toDouble()
104-
}
105-
}
106-
}
107-
is Unsigned -> {
108-
// Only compare if both are non-negative integers
109-
if (value is Byte || value is Short || value is Int || value is Long) {
110-
val longValue = value.toLong()
111-
return longValue >= 0 && longValue.toULong() == other.long.toULong()
112-
}
113-
return false
114-
}
115-
else -> return false
116-
}
117-
}
118-
119-
override fun hashCode(): Int = value.hashCode()
120-
}
69+
/**
70+
* Class representing CBOR floating point value (major type 7).
71+
*/
72+
@Serializable(with = CborDoubleSerializer::class)
73+
public class CborDouble(public val value: Double) : CborPrimitive() {
12174

122-
/**
123-
* Class representing an unsigned CBOR number value.
124-
*/
125-
public class Unsigned(private val value: ULong) : CborNumber() {
126-
override val content: String get() = value.toString()
127-
override val byte: Byte get() = value.toByte()
128-
override val short: Short get() = value.toShort()
129-
override val int: Int get() = value.toInt()
130-
override val long: Long get() = value.toLong()
131-
override val float: Float get() = value.toFloat()
132-
override val double: Double get() = value.toDouble()
133-
134-
override fun equals(other: Any?): Boolean {
135-
if (this === other) return true
136-
if (other == null) return false
137-
138-
when (other) {
139-
is Unsigned -> {
140-
return value == other.long.toULong()
141-
}
142-
is Signed -> {
143-
// Only compare if the signed value is non-negative
144-
val otherLong = other.long
145-
return otherLong >= 0 && value == otherLong.toULong()
146-
}
147-
else -> return false
148-
}
149-
}
150-
151-
override fun hashCode(): Int = value.hashCode()
75+
override fun equals(other: Any?): Boolean {
76+
if (this === other) return true
77+
if (other == null || this::class != other::class) return false
78+
other as CborDouble
79+
return value == other.value
15280
}
81+
82+
override fun hashCode(): Int = value.hashCode()
15383
}
15484

85+
15586
/**
15687
* Class representing CBOR string value.
15788
*/
15889
@Serializable(with = CborStringSerializer::class)
159-
public class CborString(private val value: String) : CborPrimitive() {
160-
override val content: String get() = value
90+
public class CborString(public val value: String) : CborPrimitive() {
16191

16292
override fun equals(other: Any?): Boolean {
16393
if (this === other) return true
@@ -174,7 +104,6 @@ public class CborString(private val value: String) : CborPrimitive() {
174104
*/
175105
@Serializable(with = CborBooleanSerializer::class)
176106
public class CborBoolean(private val value: Boolean) : CborPrimitive() {
177-
override val content: String get() = value.toString()
178107

179108
/**
180109
* Returns the boolean value.
@@ -196,7 +125,6 @@ public class CborBoolean(private val value: Boolean) : CborPrimitive() {
196125
*/
197126
@Serializable(with = CborByteStringSerializer::class)
198127
public class CborByteString(private val value: ByteArray) : CborPrimitive() {
199-
override val content: String get() = value.contentToString()
200128

201129
/**
202130
* Returns the byte array value.
@@ -218,7 +146,6 @@ public class CborByteString(private val value: ByteArray) : CborPrimitive() {
218146
*/
219147
@Serializable(with = CborNullSerializer::class)
220148
public object CborNull : CborPrimitive() {
221-
override val content: String = "null"
222149
}
223150

224151
/**
@@ -237,6 +164,7 @@ public class CborMap(
237164
other as CborMap
238165
return content == other.content
239166
}
167+
240168
public override fun hashCode(): Int = content.hashCode()
241169
public override fun toString(): String {
242170
return content.entries.joinToString(
@@ -262,6 +190,7 @@ public class CborList(private val content: List<CborElement>) : CborElement(), L
262190
other as CborList
263191
return content == other.content
264192
}
193+
265194
public override fun hashCode(): Int = content.hashCode()
266195
public override fun toString(): String = content.joinToString(prefix = "[", postfix = "]", separator = ", ")
267196
}
@@ -295,11 +224,25 @@ public val CborElement.cborNull: CborNull
295224
get() = this as? CborNull ?: error("CborNull")
296225

297226
/**
298-
* Convenience method to get current element as [CborNumber]
299-
* @throws IllegalArgumentException if current element is not a [CborNumber]
227+
* Convenience method to get current element as [CborNegativeInt]
228+
* @throws IllegalArgumentException if current element is not a [CborNegativeInt]
229+
*/
230+
public val CborElement.cborNegativeInt: CborNegativeInt
231+
get() = this as? CborNegativeInt ?: error("CborNegativeInt")
232+
233+
/**
234+
* Convenience method to get current element as [CborPositiveInt]
235+
* @throws IllegalArgumentException if current element is not a [CborPositiveInt]
236+
*/
237+
public val CborElement.cborPositiveInt: CborPositiveInt
238+
get() = this as? CborPositiveInt ?: error("CborPositiveInt")
239+
240+
/**
241+
* Convenience method to get current element as [CborDouble]
242+
* @throws IllegalArgumentException if current element is not a [CborDouble]
300243
*/
301-
public val CborElement.cborNumber: CborNumber
302-
get() = this as? CborNumber ?: error("CborNumber")
244+
public val CborElement.cborDouble: CborDouble
245+
get() = this as? CborDouble ?: error("CborDouble")
303246

304247
/**
305248
* Convenience method to get current element as [CborString]
@@ -322,11 +265,6 @@ public val CborElement.cborBoolean: CborBoolean
322265
public val CborElement.cborByteString: CborByteString
323266
get() = this as? CborByteString ?: error("CborByteString")
324267

325-
/**
326-
* Content of the given element as string or `null` if current element is [CborNull]
327-
*/
328-
public val CborPrimitive.contentOrNull: String? get() = if (this is CborNull) null else content
329-
330268
/**
331269
* Creates a [CborMap] from the given map entries.
332270
*/
@@ -338,4 +276,4 @@ public fun CborMap(vararg pairs: Pair<CborElement, CborElement>): CborMap = Cbor
338276
public fun CborList(vararg elements: CborElement): CborList = CborList(listOf(*elements))
339277

340278
private fun CborElement.error(element: String): Nothing =
341-
throw IllegalArgumentException("Element ${this::class} is not a $element")
279+
throw IllegalArgumentException("Element ${this::class} is not a $element")

0 commit comments

Comments
 (0)