@@ -26,10 +26,9 @@ private fun Stack.peek() = last()
2626// Split implementation to optimize base case
2727internal sealed class CborWriter (
2828 override val cbor : Cbor ,
29- protected val output : ByteArrayOutput ,
3029) : AbstractEncoder(), CborEncoder {
3130
32- internal fun encodeByteString (byteArray : ByteArray ) {
31+ internal open fun encodeByteString (byteArray : ByteArray ) {
3332 getDestination().encodeByteString(byteArray)
3433 }
3534
@@ -155,8 +154,8 @@ internal sealed class CborWriter(
155154
156155
157156// optimized indefinite length encoder
158- internal class IndefiniteLengthCborWriter (cbor : Cbor , output : ByteArrayOutput ) : CborWriter(
159- cbor, output
157+ internal class IndefiniteLengthCborWriter (cbor : Cbor , private val output : ByteArrayOutput ) : CborWriter(
158+ cbor
160159) {
161160
162161 override fun beginStructure (descriptor : SerialDescriptor ): CompositeEncoder {
@@ -187,8 +186,162 @@ internal class IndefiniteLengthCborWriter(cbor: Cbor, output: ByteArrayOutput) :
187186
188187}
189188
189+ // optimized indefinite length encoder
190+ internal class StructuredCborWriter (cbor : Cbor ) : CborWriter(
191+ cbor
192+ ) {
193+
194+ sealed class CborContainer (tags : ULongArray , elements : MutableList <CborElement >) {
195+ var elements = elements
196+ private set
197+
198+ var tags = tags
199+ internal set
200+
201+
202+ fun add (element : CborElement ) = elements.add(element)
203+ class Map (tags : ULongArray , elements : MutableList <CborElement > = mutableListOf()) :
204+ CborContainer (tags, elements) {
205+ }
206+
207+ class List (tags : ULongArray , elements : MutableList <CborElement > = mutableListOf()) :
208+ CborContainer (tags, elements) {
209+ }
210+
211+ class Primitive (tags : ULongArray ) : CborContainer(tags, elements = mutableListOf()) {
212+
213+ }
214+
215+ fun finalize () = when (this ) {
216+ is List -> CborList (content = elements, tags = tags)
217+ is Map -> CborMap (
218+ content = if (elements.isNotEmpty()) IntRange (0 , elements.size / 2 - 1 ).associate {
219+ elements[it * 2 ] to elements[it * 2 + 1 ]
220+ } else mapOf (),
221+ tags = tags
222+ )
223+
224+ is Primitive -> elements.first().also { it.tags = tags }
225+
226+ }
227+ }
228+
229+ private val stack = ArrayDeque <CborContainer >()
230+ private var currentElement: CborContainer ? = null
231+
232+ fun finalize () = currentElement!! .finalize()
233+
234+ override fun beginStructure (descriptor : SerialDescriptor ): CompositeEncoder {
235+ val tags = descriptor.getObjectTags() ? : ulongArrayOf()
236+ val element = if (descriptor.hasArrayTag()) {
237+ CborContainer .List (tags)
238+ } else {
239+ when (descriptor.kind) {
240+ StructureKind .LIST , is PolymorphicKind -> CborContainer .List (tags)
241+ is StructureKind .MAP -> CborContainer .Map (tags)
242+ else -> CborContainer .Map (tags)
243+ }
244+ }
245+ currentElement?.let { stack.add(it) }
246+ currentElement = element
247+ return this
248+ }
249+
250+ override fun endStructure (descriptor : SerialDescriptor ) {
251+ val finalized = currentElement!! .finalize()
252+ if (stack.isNotEmpty()) {
253+ currentElement = stack.removeLast()
254+ currentElement!! .add(finalized)
255+ }
256+ }
257+
258+ override fun getDestination () = TODO ()
259+
260+
261+ override fun incrementChildren () {/* NOOP*/
262+ }
263+
264+
265+ override fun encodeElement (descriptor : SerialDescriptor , index : Int ): Boolean {
266+ // TODO check if cborelement and be done
267+ val name = descriptor.getElementName(index)
268+ if (! descriptor.hasArrayTag()) {
269+ val keyTags = descriptor.getKeyTags(index)
270+
271+ if ((descriptor.kind !is StructureKind .LIST ) && (descriptor.kind !is StructureKind .MAP ) && (descriptor.kind !is PolymorphicKind )) {
272+ // indices are put into the name field. we don't want to write those, as it would result in double writes
273+ val cborLabel = descriptor.getCborLabel(index)
274+ if (cbor.configuration.preferCborLabelsOverNames && cborLabel != null ) {
275+ currentElement!! .add(
276+ CborInt (cborLabel, keyTags ? : ulongArrayOf())
277+ )
278+ } else {
279+ currentElement!! .add(CborString (name, keyTags ? : ulongArrayOf()))
280+ }
281+ }
282+ }
283+
284+ if (cbor.configuration.encodeValueTags) {
285+ descriptor.getValueTags(index)?.let { valueTags ->
286+ currentElement!! .tags + = valueTags
287+ }
288+ }
289+ return true
290+ }
291+
292+
293+ override fun encodeBoolean (value : Boolean ) {
294+ currentElement!! .add(CborBoolean (value))
295+ }
296+
297+ override fun encodeByte (value : Byte ) {
298+ currentElement!! .add(CborInt (value.toLong()))
299+ }
300+
301+ override fun encodeChar (value : Char ) {
302+ currentElement!! .add(CborInt (value.code.toLong()))
303+ }
304+
305+ override fun encodeDouble (value : Double ) {
306+ currentElement!! .add(CborDouble (value))
307+ }
308+
309+ override fun encodeFloat (value : Float ) {
310+ currentElement!! .add(CborDouble (value.toDouble()))
311+ }
312+
313+ override fun encodeInt (value : Int ) {
314+ currentElement!! .add(CborInt (value.toLong()))
315+ }
316+
317+ override fun encodeLong (value : Long ) {
318+ currentElement!! .add(CborInt (value))
319+ }
320+
321+ override fun encodeShort (value : Short ) {
322+ currentElement!! .add(CborInt (value.toLong()))
323+ }
324+
325+ override fun encodeString (value : String ) {
326+ currentElement!! .add(CborString (value))
327+ }
328+
329+ override fun encodeByteString (byteArray : ByteArray ) {
330+ currentElement!! .add(CborByteString (byteArray))
331+ }
332+
333+ override fun encodeNull () {
334+ currentElement!! .add(CborNull ())
335+ }
336+
337+ override fun encodeEnum (enumDescriptor : SerialDescriptor , index : Int ) {
338+ currentElement!! .add(CborString (enumDescriptor.getElementName(index)))
339+ }
340+
341+ }
342+
190343// optimized definite length encoder
191- internal class DefiniteLengthCborWriter (cbor : Cbor , output : ByteArrayOutput ) : CborWriter(cbor, output ) {
344+ internal class DefiniteLengthCborWriter (cbor : Cbor , output : ByteArrayOutput ) : CborWriter(cbor) {
192345
193346 private val structureStack = Stack (Data (output, - 1 ))
194347 override fun getDestination (): ByteArrayOutput =
0 commit comments