Skip to content

Commit 54c7c4a

Browse files
committed
cleanup after Junie
1 parent a6af196 commit 54c7c4a

File tree

4 files changed

+61
-104
lines changed

4 files changed

+61
-104
lines changed

formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborParserInterface.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import kotlinx.serialization.*
1010
/**
1111
* Common interface for CBOR parsers that can read CBOR data from different sources.
1212
*/
13-
internal interface CborParserInterface {
13+
internal sealed interface CborParserInterface {
1414
// Basic state checks
1515
fun isNull(): Boolean
1616
fun isEnd(): Boolean
@@ -40,8 +40,4 @@ internal interface CborParserInterface {
4040

4141
// Additional methods needed for CborTreeReader
4242
fun nextTag(): ULong
43-
fun readByte(): Int
44-
45-
// Properties needed for CborTreeReader
46-
val curByte: Int
4743
}

formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/CborTreeReader.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal class CborTreeReader(
1616
//we cannot validate tags, or disregard nulls, can we?!
1717
//still, this needs to go here, in case it evolves to a point where we need to respect certain config values
1818
private val configuration: CborConfiguration,
19-
private val parser: CborParserInterface
19+
private val parser: CborParser
2020
) {
2121
/**
2222
* Reads the next CBOR element from the parser.

formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/Decoder.kt

Lines changed: 58 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ import kotlinx.serialization.modules.*
1515
internal open class CborReader(override val cbor: Cbor, protected val parser: CborParserInterface) : AbstractDecoder(),
1616
CborDecoder {
1717

18-
override fun decodeCborElement(): CborElement = CborTreeReader(cbor.configuration, parser).read()
18+
override fun decodeCborElement(): CborElement =
19+
when(parser) {
20+
is CborParser -> CborTreeReader(cbor.configuration, parser).read()
21+
is StructuredCborParser -> parser.element
22+
}
23+
1924

2025
protected var size = -1
2126
private set
@@ -154,13 +159,13 @@ internal open class CborReader(override val cbor: Cbor, protected val parser: Cb
154159
}
155160

156161
internal class CborParser(private val input: ByteArrayInput, private val verifyObjectTags: Boolean) : CborParserInterface {
157-
override var curByte: Int = -1
162+
var curByte: Int = -1
158163

159164
init {
160165
readByte()
161166
}
162167

163-
override fun readByte(): Int {
168+
fun readByte(): Int {
164169
curByte = input.read()
165170
return curByte
166171
}
@@ -549,106 +554,85 @@ private fun Iterable<ByteArray>.flatten(): ByteArray {
549554
return output
550555
}
551556

552-
557+
private typealias ElementHolder = Pair<MutableList<ULong>, CborElement>
558+
private val ElementHolder.tags: MutableList<ULong> get() = first
559+
private val ElementHolder.element: CborElement get() = second
553560
internal class StructuredCborParser(val element: CborElement, private val verifyObjectTags: Boolean) : CborParserInterface {
554-
private var currentElement: CborElement = element
555-
private var mapIterator: Iterator<Map.Entry<CborElement, CborElement>>? = null
556-
private var listIterator: Iterator<CborElement>? = null
557-
private var currentMapEntry: Map.Entry<CborElement, CborElement>? = null
558-
private var currentListElement: CborElement? = null
559-
private var collectedTags: ULongArray? = null
560561

561-
// Implementation of properties needed for CborTreeReader
562-
override val curByte: Int
563-
get() = when (currentElement) {
564-
is CborPositiveInt -> 0 shl 5 // Major type 0: unsigned integer
565-
is CborNegativeInt -> 1 shl 5 // Major type 1: negative integer
566-
is CborByteString -> 2 shl 5 // Major type 2: byte string
567-
is CborString -> 3 shl 5 // Major type 3: text string
568-
is CborList -> 4 shl 5 // Major type 4: array
569-
is CborMap -> 5 shl 5 // Major type 5: map
570-
is CborBoolean -> if ((currentElement as CborBoolean).value) 0xF5 else 0xF4
571-
is CborNull -> 0xF6
572-
is CborDouble -> NEXT_DOUBLE
573-
}
574-
562+
563+
internal var current: ElementHolder = element.tags.toMutableList() to element
564+
private var listIterator: Iterator<CborElement>? = null
565+
575566
// Implementation of methods needed for CborTreeReader
576567
override fun nextTag(): ULong {
577-
// In the structured parser, we don't actually read tags from a stream
578-
// Instead, we return the first tag from the current element's tags
579-
val tags = currentElement.tags
580-
if (tags.isEmpty()) {
568+
if (current.tags.isEmpty()) {
581569
throw CborDecodingException("Expected tag, but no tags found on current element")
582570
}
583-
return tags[0]
571+
return current.tags.removeFirst()
584572
}
585573

586-
override fun readByte(): Int {
587-
// This is a no-op in the structured parser since we're not reading from a byte stream
588-
// We just return the current byte representation
589-
return curByte
574+
override fun isNull() : Boolean {
575+
//TODO this is a bit wonky! if we are inside a map, we want to skip over the key, and check the value,
576+
// so the below call is not what it should be!
577+
processTags(null)
578+
return current.element is CborNull
590579
}
591580

592-
override fun isNull() = currentElement is CborNull
593-
594581
override fun isEnd() = when {
595-
mapIterator != null -> !mapIterator!!.hasNext()
596582
listIterator != null -> !listIterator!!.hasNext()
597583
else -> false
598584
}
599585

600586
override fun end() {
601587
// Reset iterators when ending a structure
602-
mapIterator = null
603588
listIterator = null
604-
currentMapEntry = null
605-
currentListElement = null
606589
}
607-
590+
608591
override fun startArray(tags: ULongArray?): Int {
609592
processTags(tags)
610-
if (currentElement !is CborList) {
611-
throw CborDecodingException("Expected array, got ${currentElement::class.simpleName}")
593+
if (current.element !is CborList) {
594+
throw CborDecodingException("Expected array, got ${current.element::class.simpleName}")
612595
}
613596

614-
val list = currentElement as CborList
597+
val list = current.element as CborList
615598
listIterator = list.iterator()
616599
return list.size
617600
}
618601

619602
override fun startMap(tags: ULongArray?): Int {
620603
processTags(tags)
621-
if (currentElement !is CborMap) {
622-
throw CborDecodingException("Expected map, got ${currentElement::class.simpleName}")
604+
if (current.element !is CborMap) {
605+
throw CborDecodingException("Expected map, got ${current.element::class.simpleName}")
623606
}
624607

625-
val map = currentElement as CborMap
626-
mapIterator = map.entries.iterator()
627-
return map.size
608+
val map = current.element as CborMap
609+
//zip key, value, key, value, ... pairs to mirror byte-layout of CBOR map
610+
listIterator = map.entries.flatMap { listOf(it.key, it.value) }.iterator()
611+
return map.size //cbor map size is the size of the map, not the doubled size of the flattened pairs
628612
}
629613

630614
override fun nextNull(tags: ULongArray?): Nothing? {
631615
processTags(tags)
632-
if (currentElement !is CborNull) {
633-
throw CborDecodingException("Expected null, got ${currentElement::class.simpleName}")
616+
if (current.element !is CborNull) {
617+
throw CborDecodingException("Expected null, got ${current.element::class.simpleName}")
634618
}
635619
return null
636620
}
637621

638622
override fun nextBoolean(tags: ULongArray?): Boolean {
639623
processTags(tags)
640-
if (currentElement !is CborBoolean) {
641-
throw CborDecodingException("Expected boolean, got ${currentElement::class.simpleName}")
624+
if (current.element !is CborBoolean) {
625+
throw CborDecodingException("Expected boolean, got ${current.element::class.simpleName}")
642626
}
643-
return (currentElement as CborBoolean).value
627+
return (current.element as CborBoolean).value
644628
}
645629

646630
override fun nextNumber(tags: ULongArray?): Long {
647631
processTags(tags)
648-
return when (currentElement) {
649-
is CborPositiveInt -> (currentElement as CborPositiveInt).value.toLong()
650-
is CborNegativeInt -> (currentElement as CborNegativeInt).value
651-
else -> throw CborDecodingException("Expected number, got ${currentElement::class.simpleName}")
632+
return when (current.element) {
633+
is CborPositiveInt -> (current.element as CborPositiveInt).value.toLong()
634+
is CborNegativeInt -> (current.element as CborNegativeInt).value
635+
else -> throw CborDecodingException("Expected number, got ${current.element::class.simpleName}")
652636
}
653637
}
654638

@@ -657,34 +641,32 @@ internal class StructuredCborParser(val element: CborElement, private val verify
657641

658642
// Special handling for polymorphic serialization
659643
// If we have a CborList with a string as first element, return that string
660-
if (currentElement is CborList && (currentElement as CborList).isNotEmpty() && (currentElement as CborList)[0] is CborString) {
661-
val stringElement = (currentElement as CborList)[0] as CborString
644+
if (current.element is CborList && (current.element as CborList).isNotEmpty() && (current.element as CborList)[0] is CborString) {
645+
val stringElement = (current.element as CborList)[0] as CborString
662646
// Move to the next element (the map) for subsequent operations
663-
currentElement = (currentElement as CborList)[1]
647+
current = (current.element as CborList)[1].tags.toMutableList() to (current.element as CborList)[1]
664648
return stringElement.value
665649
}
666650

667-
if (currentElement !is CborString) {
668-
throw CborDecodingException("Expected string, got ${currentElement::class.simpleName}")
651+
if (current.element !is CborString) {
652+
throw CborDecodingException("Expected string, got ${current.element::class.simpleName}")
669653
}
670-
return (currentElement as CborString).value
654+
return (current.element as CborString).value
671655
}
672656

673657
override fun nextByteString(tags: ULongArray?): ByteArray {
674658
processTags(tags)
675-
if (currentElement !is CborByteString) {
676-
throw CborDecodingException("Expected byte string, got ${currentElement::class.simpleName}")
659+
if (current.element !is CborByteString) {
660+
throw CborDecodingException("Expected byte string, got ${current.element::class.simpleName}")
677661
}
678-
return (currentElement as CborByteString).value
662+
return (current.element as CborByteString).value
679663
}
680664

681665
override fun nextDouble(tags: ULongArray?): Double {
682666
processTags(tags)
683-
return when (currentElement) {
684-
is CborDouble -> (currentElement as CborDouble).value
685-
is CborPositiveInt -> (currentElement as CborPositiveInt).value.toDouble()
686-
is CborNegativeInt -> (currentElement as CborNegativeInt).value.toDouble()
687-
else -> throw CborDecodingException("Expected double, got ${currentElement::class.simpleName}")
667+
return when (current.element) {
668+
is CborDouble -> (current.element as CborDouble).value
669+
else -> throw CborDecodingException("Expected double, got ${current.element::class.simpleName}")
688670
}
689671
}
690672

@@ -695,7 +677,7 @@ internal class StructuredCborParser(val element: CborElement, private val verify
695677
override fun nextTaggedStringOrNumber(): Triple<String?, Long?, ULongArray?> {
696678
val tags = processTags(null)
697679

698-
return when (val key = currentMapEntry?.key) {
680+
return when (val key = current.element) {
699681
is CborString -> Triple(key.value, null, tags)
700682
is CborPositiveInt -> Triple(null, key.value.toLong(), tags)
701683
is CborNegativeInt -> Triple(null, key.value, tags)
@@ -704,29 +686,14 @@ internal class StructuredCborParser(val element: CborElement, private val verify
704686
}
705687

706688
private fun processTags(tags: ULongArray?): ULongArray? {
707-
val elementTags = currentElement.tags
708-
689+
709690
// If we're in a list, advance to the next element
710-
if (listIterator != null && currentListElement == null && listIterator!!.hasNext()) {
711-
currentListElement = listIterator!!.next()
712-
currentElement = currentListElement!!
713-
}
714-
715-
// If we're in a map, advance to the next entry if we're not processing a value
716-
if (mapIterator != null && currentMapEntry == null && mapIterator!!.hasNext()) {
717-
currentMapEntry = mapIterator!!.next()
718-
// We're now positioned at the key
719-
currentElement = currentMapEntry!!.key
720-
}
721-
722-
// After processing a key in a map, move to the value for the next operation
723-
if (mapIterator != null && currentMapEntry != null && currentElement == currentMapEntry!!.key) {
724-
// We've processed the key, now move to the value
725-
currentElement = currentMapEntry!!.value
691+
if (listIterator != null && listIterator!!.hasNext()) {
692+
listIterator!!.next().let { current = it.tags.toMutableList() to it }
726693
}
727694

728695
// Store collected tags for verification
729-
collectedTags = if (elementTags.isEmpty()) null else elementTags
696+
val collectedTags = if (current.tags.isEmpty()) null else current.tags.toULongArray()
730697

731698
// Verify tags if needed
732699
if (verifyObjectTags) {
@@ -749,12 +716,6 @@ internal class StructuredCborParser(val element: CborElement, private val verify
749716
override fun skipElement(tags: ULongArray?) {
750717
// Process tags but don't do anything with the element
751718
processTags(tags)
752-
753-
// If we're in a map and have processed a key, move to the value
754-
if (mapIterator != null && currentMapEntry != null) {
755-
currentElement = currentMapEntry!!.value
756-
currentMapEntry = null
757-
}
758719
}
759720
}
760721

formats/cbor/commonTest/src/kotlinx/serialization/cbor/CborDecoderTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ class CborDecoderTest {
2424
}
2525

2626
@Test
27-
@Ignore
2827
fun testDecodeComplicatedObject() {
2928
val test = TypesUmbrella(
3029
"Hello, world!",
@@ -356,6 +355,7 @@ class CborDecoderTest {
356355
hex
357356
)
358357
)
358+
val ref = ignoreUnknownKeys.encodeToCbor(expected)
359359
val struct = Cbor.decodeFromHexString<CborElement>(hex)
360360
assertEquals(expected, ignoreUnknownKeys.decodeFromCbor(SealedBox.serializer(), struct))
361361

0 commit comments

Comments
 (0)