@@ -34,35 +34,45 @@ public interface ICborArrayReader<TC>
3434 void ReadArrayItem ( ref CborReader reader , ref TC context ) ;
3535 }
3636
37- public ref struct CborReader
37+ public enum CborReaderState
3838 {
39- private enum State
40- {
41- Start ,
42- Header ,
43- Data
44- }
39+ Start ,
40+ Header ,
41+ Data
42+ }
4543
46- [ StructLayout ( LayoutKind . Explicit , Size = 2 ) ]
47- private struct Header
48- {
49- [ FieldOffset ( 0 ) ]
50- public CborMajorType MajorType ;
44+ [ StructLayout ( LayoutKind . Explicit , Size = 2 ) ]
45+ public struct CborReaderHeader
46+ {
47+ [ FieldOffset ( 0 ) ]
48+ public CborMajorType MajorType ;
5149
52- [ FieldOffset ( 1 ) ]
53- public byte AdditionalValue ;
50+ [ FieldOffset ( 1 ) ]
51+ public byte AdditionalValue ;
5452
55- [ FieldOffset ( 1 ) ]
56- public CborPrimitive Primitive ;
57- }
53+ [ FieldOffset ( 1 ) ]
54+ public CborPrimitive Primitive ;
55+ }
5856
57+ public ref struct CborReaderBookmark
58+ {
59+ public ReadOnlySpan < byte > buffer ;
60+ public int currentPos ;
61+ public CborReaderState state ;
62+ public CborReaderHeader header ;
63+ public int remainingItemCount ;
64+ }
65+
66+ public ref struct CborReader
67+ {
5968 private const int CHUNK_SIZE = 1024 ;
6069 private const byte INDEFINITE_LENGTH = 31 ;
6170
6271 private ReadOnlySpan < byte > _buffer ;
6372 private int _currentPos ;
64- private State _state ;
65- private Header _header ;
73+ private CborReaderState _state ;
74+ private CborReaderHeader _header ;
75+ private int _remainingItemCount ;
6676
6777 public CborOptions Options { get ; }
6878
@@ -71,8 +81,9 @@ public CborReader(ReadOnlySpan<byte> buffer, CborOptions options = null)
7181 _buffer = buffer ;
7282 Options = options ?? CborOptions . Default ;
7383 _currentPos = 0 ;
74- _state = State . Start ;
75- _header = new Header ( ) ;
84+ _state = CborReaderState . Start ;
85+ _header = new CborReaderHeader ( ) ;
86+ _remainingItemCount = 0 ;
7687 }
7788
7889 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -81,7 +92,7 @@ public bool TryReadSemanticTag(out ulong semanticTag)
8192 if ( Accept ( CborMajorType . SemanticTag ) )
8293 {
8394 semanticTag = ReadInteger ( ) ;
84- _state = State . Data ;
95+ _state = CborReaderState . Data ;
8596 return true ;
8697 }
8798
@@ -93,7 +104,7 @@ public bool TryReadSemanticTag(out ulong semanticTag)
93104 public CborDataItemType GetCurrentDataItemType ( )
94105 {
95106 SkipSemanticTag ( ) ;
96- Header header = GetHeader ( ) ;
107+ CborReaderHeader header = GetHeader ( ) ;
97108
98109 switch ( header . MajorType )
99110 {
@@ -149,6 +160,28 @@ public CborDataItemType GetCurrentDataItemType()
149160 }
150161 }
151162
163+ public CborReaderBookmark GetBookmark ( )
164+ {
165+ CborReaderBookmark bookmark ;
166+
167+ bookmark . buffer = _buffer ;
168+ bookmark . currentPos = _currentPos ;
169+ bookmark . state = _state ;
170+ bookmark . header = _header ;
171+ bookmark . remainingItemCount = _remainingItemCount ;
172+
173+ return bookmark ;
174+ }
175+
176+ public void ReturnToBookmark ( CborReaderBookmark bookmark )
177+ {
178+ _buffer = bookmark . buffer ;
179+ _currentPos = bookmark . currentPos ;
180+ _state = bookmark . state ;
181+ _header = bookmark . header ;
182+ _remainingItemCount = bookmark . remainingItemCount ;
183+ }
184+
152185 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
153186 public void ReadBeginArray ( )
154187 {
@@ -316,7 +349,7 @@ public int ReadSize()
316349 {
317350 if ( GetHeader ( ) . AdditionalValue == INDEFINITE_LENGTH )
318351 {
319- _state = State . Data ;
352+ _state = CborReaderState . Data ;
320353 return - 1 ;
321354 }
322355
@@ -328,17 +361,29 @@ public void ReadMap<TC>(ICborMapReader<TC> mapReader, ref TC context)
328361 {
329362 ReadBeginMap ( ) ;
330363
331- int size = ReadSize ( ) ;
364+ int previousRemainingItemCount = _remainingItemCount ;
365+ _remainingItemCount = ReadSize ( ) ;
332366
333- mapReader . ReadBeginMap ( size , ref context ) ;
367+ mapReader . ReadBeginMap ( _remainingItemCount , ref context ) ;
334368
335- while ( size > 0 || size < 0 && GetCurrentDataItemType ( ) != CborDataItemType . Break )
369+ while ( MoveNextMapItem ( ) )
336370 {
337371 mapReader . ReadMapItem ( ref this , ref context ) ;
338- size -- ;
339372 }
340373
341- _state = State . Start ;
374+ _state = CborReaderState . Start ;
375+ _remainingItemCount = previousRemainingItemCount ;
376+ }
377+
378+ public bool MoveNextMapItem ( )
379+ {
380+ if ( _remainingItemCount == 0 || _remainingItemCount < 0 && GetCurrentDataItemType ( ) == CborDataItemType . Break )
381+ {
382+ return false ;
383+ }
384+
385+ _remainingItemCount -- ;
386+ return true ;
342387 }
343388
344389 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -356,13 +401,13 @@ public void ReadArray<TC>(ICborArrayReader<TC> arrayReader, ref TC context)
356401 size -- ;
357402 }
358403
359- _state = State . Start ;
404+ _state = CborReaderState . Start ;
360405 }
361406
362407 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
363408 private ulong ReadUnsigned ( ulong maxValue )
364409 {
365- Header header = GetHeader ( ) ;
410+ CborReaderHeader header = GetHeader ( ) ;
366411
367412 switch ( header . MajorType )
368413 {
@@ -377,7 +422,7 @@ private ulong ReadUnsigned(ulong maxValue)
377422 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
378423 private long ReadSigned ( long maxValue )
379424 {
380- Header header = GetHeader ( ) ;
425+ CborReaderHeader header = GetHeader ( ) ;
381426
382427 switch ( header . MajorType )
383428 {
@@ -395,7 +440,7 @@ private long ReadSigned(long maxValue)
395440 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
396441 private ulong ReadInteger ( ulong maxValue = ulong . MaxValue )
397442 {
398- Header header = GetHeader ( ) ;
443+ CborReaderHeader header = GetHeader ( ) ;
399444
400445 ulong value ;
401446
@@ -429,7 +474,7 @@ private ulong ReadInteger(ulong maxValue = ulong.MaxValue)
429474
430475 default :
431476 value = header . AdditionalValue ;
432- _state = State . Data ;
477+ _state = CborReaderState . Data ;
433478 break ;
434479 }
435480
@@ -517,9 +562,9 @@ private ReadOnlySpan<byte> ReadSizeAndBytes()
517562 }
518563
519564 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
520- private Header GetHeader ( )
565+ private CborReaderHeader GetHeader ( )
521566 {
522- if ( _state == State . Header )
567+ if ( _state == CborReaderState . Header )
523568 {
524569 return _header ;
525570 }
@@ -535,7 +580,7 @@ private Header GetHeader()
535580 }
536581
537582 Advance ( ) ;
538- _state = State . Header ;
583+ _state = CborReaderState . Header ;
539584
540585 return _header ;
541586 }
@@ -570,15 +615,15 @@ private void SkipSemanticTag()
570615 if ( Accept ( CborMajorType . SemanticTag ) )
571616 {
572617 ReadInteger ( ) ;
573- _state = State . Data ;
618+ _state = CborReaderState . Data ;
574619 return ;
575620 }
576621 }
577622
578623 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
579624 public void SkipDataItem ( )
580625 {
581- Header header = GetHeader ( ) ;
626+ CborReaderHeader header = GetHeader ( ) ;
582627
583628 switch ( header . MajorType )
584629 {
@@ -601,7 +646,7 @@ public void SkipDataItem()
601646 break ;
602647
603648 case CborMajorType . SemanticTag :
604- _state = State . Data ;
649+ _state = CborReaderState . Data ;
605650 break ;
606651
607652 case CborMajorType . Primitive :
@@ -613,7 +658,7 @@ public void SkipDataItem()
613658 case CborPrimitive . Undefined :
614659 case CborPrimitive . SimpleValue :
615660 case CborPrimitive . Break :
616- _state = State . Data ;
661+ _state = CborReaderState . Data ;
617662 break ;
618663
619664 case CborPrimitive . HalfFloat :
@@ -643,7 +688,7 @@ private void SkipArray()
643688 size -- ;
644689 }
645690
646- _state = State . Start ;
691+ _state = CborReaderState . Start ;
647692 }
648693
649694 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -658,15 +703,15 @@ private void SkipMap()
658703 size -- ;
659704 }
660705
661- _state = State . Start ;
706+ _state = CborReaderState . Start ;
662707 }
663708
664709 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
665710 private bool Accept ( CborPrimitive primitive )
666711 {
667712 if ( Accept ( CborMajorType . Primitive ) && _header . Primitive == primitive )
668713 {
669- _state = State . Data ;
714+ _state = CborReaderState . Data ;
670715 return true ;
671716 }
672717
@@ -709,9 +754,9 @@ private void ExpectLength(int length)
709754 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
710755 private void Advance ( int length = 1 )
711756 {
712- if ( _state == State . Header )
757+ if ( _state == CborReaderState . Header )
713758 {
714- _state = State . Data ;
759+ _state = CborReaderState . Data ;
715760 }
716761 _buffer = _buffer . Slice ( length ) ;
717762 _currentPos += length ;
0 commit comments