< Summary

Line coverage
39%
Covered lines: 1569
Uncovered lines: 2428
Coverable lines: 3997
Total lines: 6599
Line coverage: 39.2%
Branch coverage
32%
Covered branches: 579
Total branches: 1759
Branch coverage: 32.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
File 1: .ctor(...)100%22100%
File 1: .ctor(...)100%11100%
File 1: Read()100%1010100%
File 1: Skip()0%220%
File 1: SkipHelper()62.5%8864.7%
File 1: TrySkip()25%4430.76%
File 1: TrySkipPartial(...)0%16160%
File 1: ValueTextEquals(...)0%220%
File 1: ValueTextEquals(...)100%110%
File 1: TextEqualsHelper(...)0%440%
File 1: ValueTextEquals(...)0%10100%
File 1: CompareToSequence(...)0%880%
File 1: UnescapeAndCompare(...)0%660%
File 1: UnescapeSequenceAndCompare(...)0%14140%
File 1: IsTokenTypeString(...)0%220%
File 1: MatchNotPossible(...)0%880%
File 1: MatchNotPossibleSequence(...)0%660%
File 1: StartObject()0%220%
File 1: EndObject()0%880%
File 1: StartArray()50%2290%
File 1: EndArray()0%880%
File 1: UpdateBitStackOnEndToken()100%110%
File 1: ReadSingleSegment()75%242463.38%
File 1: HasMoreData()43.75%161661.11%
File 1: HasMoreData(...)0%440%
File 1: ReadFirstToken(...)78.57%141489.47%
File 1: SkipWhiteSpace()33.33%181853.84%
File 1: ConsumeValue(...)45.83%484856.25%
File 1: ConsumeLiteral(...)83.33%6653.84%
File 1: CheckLiteral(...)33.33%121244%
File 1: ThrowInvalidLiteral(...)75%4472.72%
File 1: ConsumeNumber()50%121285.71%
File 1: ConsumePropertyName()0%10100%
File 1: ConsumeString()83.33%6696%
File 1: ConsumeStringAndValidate(...)65.38%262675.4%
File 1: ValidateHexDigits(...)66.66%6678.57%
File 1: TryGetNumber(...)28.57%424242.5%
File 1: ConsumeNegativeSign(...)50%8865%
File 1: ConsumeZero(...)71.42%141488%
File 1: ConsumeIntegerDigits(...)90%101090.47%
File 1: ConsumeDecimalDigits(...)0%660%
File 1: ConsumeSign(...)0%14140%
File 1: ConsumeNextTokenOrRollback(...)0%4435%
File 1: ConsumeNextToken(...)17.3%525219.51%
File 1: ConsumeNextTokenFromLastNonCommentToken()0%86860%
File 1: SkipAllComments(...)20%101024%
File 1: SkipAllComments(...)0%10100%
File 1: ConsumeNextTokenUntilAfterAllCommentsAreSkipped(...)17.24%585813.04%
File 1: SkipComment()37.5%8850%
File 1: SkipSingleLineComment(...)0%12120%
File 1: FindLineSeparator(...)0%440%
File 1: ThrowOnDangerousLineSeparator(...)0%880%
File 1: SkipMultiLineComment(...)0%10100%
File 1: ConsumeComment()0%880%
File 1: ConsumeSingleLineComment(...)0%440%
File 1: ConsumeMultiLineComment(...)0%440%
File 1: GetUnescapedSpan()75%4462.5%
File 2: .ctor(...)40%101066.66%
File 2: .ctor(...)100%110%
File 2: ReadMultiSegment()75%242461.03%
File 2: ValidateStateAtEndOfData()16.66%121238.46%
File 2: HasMoreDataMultiSegment()71.42%141468.42%
File 2: HasMoreDataMultiSegment(...)0%880%
File 2: GetNextSpan()50%101088.88%
File 2: ReadFirstTokenMultiSegment(...)78.57%141488.88%
File 2: SkipWhiteSpaceMultiSegment()100%44100%
File 2: ConsumeValueMultiSegment(...)36.66%606046.83%
File 2: ConsumeLiteralMultiSegment(...)62.5%8842.85%
File 2: CheckLiteralMultiSegment(...)55.55%181862.12%
File 2: AmountToWrite(System.ReadOnlySpan`1<System.Byte>,System.Int64,System.ReadOnlySpan`1<System.Byte>,System.Int32)100%11100%
File 2: FindMismatch(...)50%22100%
File 2: GetInvalidLiteralMultiSegment(...)75%4475%
File 2: ConsumeNumberMultiSegment()50%121285%
File 2: ConsumePropertyNameMultiSegment()0%10100%
File 2: ConsumeStringMultiSegment()100%66100%
File 2: ConsumeStringNextSegment()31.57%383841.46%
File 2: ConsumeStringAndValidateMultiSegment(...)17.5%404019.46%
File 2: RollBackState(...)50%2266.66%
File 2: TryGetNumberMultiSegment(...)31.81%444443.87%
File 2: ConsumeNegativeSignMultiSegment(...)33.33%121244.11%
File 2: ConsumeZeroMultiSegment(...)68.18%222285%
File 2: ConsumeIntegerDigitsMultiSegment(...)81.81%222286.2%
File 2: ConsumeDecimalDigitsMultiSegment(...)0%10100%
File 2: ConsumeSignMultiSegment(...)0%22220%
File 2: ConsumeNextTokenOrRollbackMultiSegment(...)0%4437.5%
File 2: ConsumeNextTokenMultiSegment(...)16.07%565617.77%
File 2: ConsumeNextTokenFromLastNonCommentTokenMultiSegment()0%90900%
File 2: SkipAllCommentsMultiSegment(...)20%101024%
File 2: SkipAllCommentsMultiSegment(...)0%10100%
File 2: ConsumeNextTokenUntilAfterAllCommentsAreSkippedMultiSegment(...)16.12%626211.81%
File 2: SkipOrConsumeCommentMultiSegmentWithRollback()0%101011.42%
File 2: SkipCommentMultiSegment(...)23.07%262625.92%
File 2: SkipSingleLineCommentMultiSegment(...)0%24240%
File 2: FindLineSeparatorMultiSegment(...)0%16160%
File 2: ThrowOnDangerousLineSeparatorMultiSegment(...)0%16160%
File 2: SkipMultiLineCommentMultiSegment(...)0%22220%
File 2: CaptureState()100%11100%
File 2: .ctor(...)100%11100%
File 2: GetStartPosition(...)100%11100%
File 3: GetString()80%101071.42%
File 3: CopyString(...)50%4466.66%
File 3: CopyValue(...)75%121276.92%
File 3: CopyString(...)50%4466.66%
File 3: CopyValue(...)56.25%161664.86%
File 3: TryCopyEscapedString(...)0%880%
File 3: GetComment()0%440%
File 3: GetBoolean()25%8850%
File 3: GetBytesFromBase64()100%22100%
File 3: GetByte()100%22100%
File 3: GetByteWithQuotes()50%2271.42%
File 3: GetSByte()100%22100%
File 3: GetSByteWithQuotes()50%2271.42%
File 3: GetInt16()50%2266.66%
File 3: GetInt16WithQuotes()50%2271.42%
File 3: GetInt32()50%2266.66%
File 3: GetInt32WithQuotes()50%2271.42%
File 3: GetInt64()50%2266.66%
File 3: GetInt64WithQuotes()50%2271.42%
File 3: GetUInt16()50%2266.66%
File 3: GetUInt16WithQuotes()50%2271.42%
File 3: GetUInt32()50%2266.66%
File 3: GetUInt32WithQuotes()50%2271.42%
File 3: GetUInt64()50%2266.66%
File 3: GetUInt64WithQuotes()50%2271.42%
File 3: GetSingle()50%2266.66%
File 3: GetSingleWithQuotes()62.5%8866.66%
File 3: GetSingleFloatingPointConstant()0%220%
File 3: GetDouble()50%2266.66%
File 3: GetDoubleWithQuotes()62.5%8866.66%
File 3: GetDoubleFloatingPointConstant()0%220%
File 3: GetDecimal()50%2266.66%
File 3: GetDecimalWithQuotes()50%2271.42%
File 3: GetDateTime()50%2266.66%
File 3: GetDateTimeNoValidation()0%220%
File 3: GetDateTimeOffset()50%2266.66%
File 3: GetDateTimeOffsetNoValidation()0%220%
File 3: GetGuid()50%2266.66%
File 3: GetGuidNoValidation()0%220%
File 3: TryGetBytesFromBase64(...)83.33%6681.81%
File 3: TryGetByte(...)100%44100%
File 3: TryGetByteCore(...)100%44100%
File 3: TryGetSByte(...)100%44100%
File 3: TryGetSByteCore(...)100%44100%
File 3: TryGetInt16(...)100%44100%
File 3: TryGetInt16Core(...)100%44100%
File 3: TryGetInt32(...)100%44100%
File 3: TryGetInt32Core(...)100%44100%
File 3: TryGetInt64(...)100%44100%
File 3: TryGetInt64Core(...)100%44100%
File 3: TryGetUInt16(...)100%44100%
File 3: TryGetUInt16Core(...)100%44100%
File 3: TryGetUInt32(...)100%44100%
File 3: TryGetUInt32Core(...)100%44100%
File 3: TryGetUInt64(...)100%44100%
File 3: TryGetUInt64Core(...)100%44100%
File 3: TryGetSingle(...)75%8884.61%
File 3: TryGetDouble(...)75%8884.61%
File 3: TryGetDecimal(...)100%44100%
File 3: TryGetDecimalCore(...)100%44100%
File 3: TryGetDateTime(...)100%22100%
File 3: TryGetDateTimeCore(...)75%4476.47%
File 3: TryGetDateTimeOffset(...)100%22100%
File 3: TryGetDateTimeOffsetCore(...)75%4476.47%
File 3: TryGetGuid(...)100%22100%
File 3: TryGetGuidCore(...)75%4482.35%

File(s)

D:\runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Reader\Utf8JsonReader.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Buffers;
 5using System.Diagnostics;
 6using System.Runtime.CompilerServices;
 7
 8namespace System.Text.Json
 9{
 10    /// <summary>
 11    /// Provides a high-performance API for forward-only, read-only access to the UTF-8 encoded JSON text.
 12    /// It processes the text sequentially with no caching and adheres strictly to the JSON RFC
 13    /// by default (https://tools.ietf.org/html/rfc8259). When it encounters invalid JSON, it throws
 14    /// a JsonException with basic error information like line number and byte position on the line.
 15    /// Since this type is a ref struct, it does not directly support async. However, it does provide
 16    /// support for reentrancy to read incomplete data, and continue reading once more data is presented.
 17    /// To be able to set max depth while reading OR allow skipping comments, create an instance of
 18    /// <see cref="JsonReaderState"/> and pass that in to the reader.
 19    /// </summary>
 20    [DebuggerDisplay("{DebuggerDisplay,nq}")]
 21    public ref partial struct Utf8JsonReader
 22    {
 23        private ReadOnlySpan<byte> _buffer;
 24
 25        private readonly bool _isFinalBlock;
 26        private readonly bool _isInputSequence;
 27
 28        private long _lineNumber;
 29        private long _bytePositionInLine;
 30
 31        // bytes consumed in the current segment (not token)
 32        private int _consumed;
 33        private bool _inObject;
 34        private bool _isNotPrimitive;
 35        private JsonTokenType _tokenType;
 36        private JsonTokenType _previousTokenType;
 37        private JsonReaderOptions _readerOptions;
 38        private BitStack _bitStack;
 39
 40        private long _totalConsumed;
 41        private bool _isLastSegment;
 42        private readonly bool _isMultiSegment;
 43        private bool _trailingCommaBeforeComment;
 44
 45        private SequencePosition _nextPosition;
 46        private SequencePosition _currentPosition;
 47        private readonly ReadOnlySequence<byte> _sequence;
 48
 303849        private readonly bool IsLastSpan => _isFinalBlock && (!_isMultiSegment || _isLastSegment);
 50
 42251        internal readonly ReadOnlySequence<byte> OriginalSequence => _sequence;
 52
 25953        internal readonly ReadOnlySpan<byte> OriginalSpan => _sequence.IsEmpty ? _buffer : default;
 54
 126455        internal readonly int ValueLength => HasValueSequence ? checked((int)ValueSequence.Length) : ValueSpan.Length;
 56
 303057        internal readonly bool AllowMultipleValues => _readerOptions.AllowMultipleValues;
 58
 59        /// <summary>
 60        /// Gets the value of the last processed token as a ReadOnlySpan&lt;byte&gt; slice
 61        /// of the input payload. If the JSON is provided within a ReadOnlySequence&lt;byte&gt;
 62        /// and the slice that represents the token value fits in a single segment, then
 63        /// <see cref="ValueSpan"/> will contain the sliced value since it can be represented as a span.
 64        /// Otherwise, the <see cref="ValueSequence"/> will contain the token value.
 65        /// </summary>
 66        /// <remarks>
 67        /// If <see cref="HasValueSequence"/> is true, <see cref="ValueSpan"/> contains useless data, likely for
 68        /// a previous single-segment token. Therefore, only access <see cref="ValueSpan"/> if <see cref="HasValueSequen
 69        /// Otherwise, the token value must be accessed from <see cref="ValueSequence"/>.
 70        /// </remarks>
 10052271        public ReadOnlySpan<byte> ValueSpan { get; private set; }
 72
 73        /// <summary>
 74        /// Returns the total amount of bytes consumed by the <see cref="Utf8JsonReader"/> so far
 75        /// for the current instance of the <see cref="Utf8JsonReader"/> with the given UTF-8 encoded input text.
 76        /// </summary>
 77        public readonly long BytesConsumed
 78        {
 79            get
 7477780            {
 81#if DEBUG
 7477782                if (!_isInputSequence)
 2811783                {
 2811784                    Debug.Assert(_totalConsumed == 0);
 2811785                }
 86#endif
 7477787                return _totalConsumed + _consumed;
 7477788            }
 89        }
 90
 91        /// <summary>
 92        /// Returns the index that the last processed JSON token starts at
 93        /// within the given UTF-8 encoded input text, skipping any white space.
 94        /// </summary>
 95        /// <remarks>
 96        /// For JSON strings (including property names), this points to before the start quote.
 97        /// For comments, this points to before the first comment delimiter (i.e. '/').
 98        /// </remarks>
 8225099        public long TokenStartIndex { get; private set; }
 100
 101        /// <summary>
 102        /// Tracks the recursive depth of the nested objects / arrays within the JSON text
 103        /// processed so far. This provides the depth of the current token.
 104        /// </summary>
 105        public readonly int CurrentDepth
 106        {
 107            get
 16872108            {
 16872109                int readerDepth = _bitStack.CurrentDepth;
 16872110                if (TokenType is JsonTokenType.StartArray or JsonTokenType.StartObject)
 9756111                {
 9756112                    Debug.Assert(readerDepth >= 1);
 9756113                    readerDepth--;
 9756114                }
 16872115                return readerDepth;
 16872116            }
 117        }
 118
 644119        internal readonly bool IsInArray => !_inObject;
 120
 121        /// <summary>
 122        /// Gets the type of the last processed JSON token in the UTF-8 encoded JSON text.
 123        /// </summary>
 90956124        public readonly JsonTokenType TokenType => _tokenType;
 125
 126        /// <summary>
 127        /// Lets the caller know which of the two 'Value' properties to read to get the
 128        /// token value. For input data within a ReadOnlySpan&lt;byte&gt; this will
 129        /// always return false. For input data within a ReadOnlySequence&lt;byte&gt;, this
 130        /// will only return true if the token value straddles more than a single segment and
 131        /// hence couldn't be represented as a span.
 132        /// </summary>
 67789133        public bool HasValueSequence { get; private set; }
 134
 135        /// <summary>
 136        /// Lets the caller know whether the current <see cref="ValueSpan" /> or <see cref="ValueSequence"/> properties
 137        /// contain escape sequences per RFC 8259 section 7, and therefore require unescaping before being consumed.
 138        /// </summary>
 159065139        public bool ValueIsEscaped { get; private set; }
 140
 141        /// <summary>
 142        /// Returns the mode of this instance of the <see cref="Utf8JsonReader"/>.
 143        /// True when the reader was constructed with the input span containing the entire data to process.
 144        /// False when the reader was constructed knowing that the input span may contain partial data with more data to
 145        /// </summary>
 32888146        public readonly bool IsFinalBlock => _isFinalBlock;
 147
 148        /// <summary>
 149        /// Gets the value of the last processed token as a ReadOnlySpan&lt;byte&gt; slice
 150        /// of the input payload. If the JSON is provided within a ReadOnlySequence&lt;byte&gt;
 151        /// and the slice that represents the token value fits in a single segment, then
 152        /// <see cref="ValueSpan"/> will contain the sliced value since it can be represented as a span.
 153        /// Otherwise, the <see cref="ValueSequence"/> will contain the token value.
 154        /// </summary>
 155        /// <remarks>
 156        /// If <see cref="HasValueSequence"/> is false, <see cref="ValueSequence"/> contains useless data, likely for
 157        /// a previous multi-segment token. Therefore, only access <see cref="ValueSequence"/> if <see cref="HasValueSeq
 158        /// Otherwise, the token value must be accessed from <see cref="ValueSpan"/>.
 159        /// </remarks>
 59215160        public ReadOnlySequence<byte> ValueSequence { get; private set; }
 161
 162        /// <summary>
 163        /// Returns the current <see cref="SequencePosition"/> within the provided UTF-8 encoded
 164        /// input ReadOnlySequence&lt;byte&gt;. If the <see cref="Utf8JsonReader"/> was constructed
 165        /// with a ReadOnlySpan&lt;byte&gt; instead, this will always return a default <see cref="SequencePosition"/>.
 166        /// </summary>
 167        public readonly SequencePosition Position
 168        {
 169            get
 0170            {
 0171                if (_isInputSequence)
 0172                {
 0173                    Debug.Assert(_currentPosition.GetObject() is not null);
 0174                    return _sequence.GetPosition(_consumed, _currentPosition);
 175                }
 0176                return default;
 0177            }
 178        }
 179
 180        /// <summary>
 181        /// Returns the current snapshot of the <see cref="Utf8JsonReader"/> state which must
 182        /// be captured by the caller and passed back in to the <see cref="Utf8JsonReader"/> ctor with more data.
 183        /// Unlike the <see cref="Utf8JsonReader"/>, which is a ref struct, the state can survive
 184        /// across async/await boundaries and hence this type is required to provide support for reading
 185        /// in more data asynchronously before continuing with a new instance of the <see cref="Utf8JsonReader"/>.
 186        /// </summary>
 72334187        public readonly JsonReaderState CurrentState => new JsonReaderState
 72334188        (
 72334189            lineNumber: _lineNumber,
 72334190            bytePositionInLine: _bytePositionInLine,
 72334191            inObject: _inObject,
 72334192            isNotPrimitive: _isNotPrimitive,
 72334193            valueIsEscaped: ValueIsEscaped,
 72334194            trailingCommaBeforeComment: _trailingCommaBeforeComment,
 72334195            tokenType: _tokenType,
 72334196            previousTokenType: _previousTokenType,
 72334197            readerOptions: _readerOptions,
 72334198            bitStack: _bitStack
 72334199        );
 200
 201        /// <summary>
 202        /// Constructs a new <see cref="Utf8JsonReader"/> instance.
 203        /// </summary>
 204        /// <param name="jsonData">The ReadOnlySpan&lt;byte&gt; containing the UTF-8 encoded JSON text to process.</para
 205        /// <param name="isFinalBlock">True when the input span contains the entire data to process.
 206        /// Set to false only if it is known that the input span contains partial data with more data to follow.</param>
 207        /// <param name="state">If this is the first call to the ctor, pass in a default state. Otherwise,
 208        /// capture the state from the previous instance of the <see cref="Utf8JsonReader"/> and pass that back.</param>
 209        /// <remarks>
 210        /// Since this type is a ref struct, it is a stack-only type and all the limitations of ref structs apply to it.
 211        /// This is the reason why the ctor accepts a <see cref="JsonReaderState"/>.
 212        /// </remarks>
 213        public Utf8JsonReader(ReadOnlySpan<byte> jsonData, bool isFinalBlock, JsonReaderState state)
 18560214        {
 18560215            _buffer = jsonData;
 216
 18560217            _isFinalBlock = isFinalBlock;
 18560218            _isInputSequence = false;
 219
 18560220            _lineNumber = state._lineNumber;
 18560221            _bytePositionInLine = state._bytePositionInLine;
 18560222            _inObject = state._inObject;
 18560223            _isNotPrimitive = state._isNotPrimitive;
 18560224            ValueIsEscaped = state._valueIsEscaped;
 18560225            _trailingCommaBeforeComment = state._trailingCommaBeforeComment;
 18560226            _tokenType = state._tokenType;
 18560227            _previousTokenType = state._previousTokenType;
 18560228            _readerOptions = state._readerOptions;
 18560229            if (_readerOptions.MaxDepth == 0)
 532230            {
 532231                _readerOptions.MaxDepth = JsonReaderOptions.DefaultMaxDepth;  // If max depth is not set, revert to the 
 532232            }
 18560233            _bitStack = state._bitStack;
 234
 18560235            _consumed = 0;
 18560236            TokenStartIndex = 0;
 18560237            _totalConsumed = 0;
 18560238            _isLastSegment = _isFinalBlock;
 18560239            _isMultiSegment = false;
 240
 18560241            ValueSpan = ReadOnlySpan<byte>.Empty;
 242
 18560243            _currentPosition = default;
 18560244            _nextPosition = default;
 18560245            _sequence = default;
 18560246            HasValueSequence = false;
 18560247            ValueSequence = ReadOnlySequence<byte>.Empty;
 18560248        }
 249
 250        /// <summary>
 251        /// Constructs a new <see cref="Utf8JsonReader"/> instance.
 252        /// </summary>
 253        /// <param name="jsonData">The ReadOnlySpan&lt;byte&gt; containing the UTF-8 encoded JSON text to process.</para
 254        /// <param name="options">Defines the customized behavior of the <see cref="Utf8JsonReader"/>
 255        /// that is different from the JSON RFC (for example how to handle comments or maximum depth allowed when readin
 256        /// By default, the <see cref="Utf8JsonReader"/> follows the JSON RFC strictly (i.e. comments within the JSON ar
 257        /// <remarks>
 258        ///   <para>
 259        ///     Since this type is a ref struct, it is a stack-only type and all the limitations of ref structs apply to
 260        ///   </para>
 261        ///   <para>
 262        ///     This assumes that the entire JSON payload is passed in (equivalent to <see cref="IsFinalBlock"/> = true)
 263        ///   </para>
 264        /// </remarks>
 265        public Utf8JsonReader(ReadOnlySpan<byte> jsonData, JsonReaderOptions options = default)
 108266            : this(jsonData, isFinalBlock: true, new JsonReaderState(options))
 108267        {
 108268        }
 269
 270        /// <summary>
 271        /// Read the next JSON token from input source.
 272        /// </summary>
 273        /// <returns>True if the token was read successfully, else false.</returns>
 274        /// <exception cref="JsonException">
 275        /// Thrown when an invalid JSON token is encountered according to the JSON RFC
 276        /// or if the current depth exceeds the recursive limit set by the max depth.
 277        /// </exception>
 278        public bool Read()
 41894279        {
 41894280            bool retVal = _isMultiSegment ? ReadMultiSegment() : ReadSingleSegment();
 281
 18924282            if (!retVal)
 1674283            {
 1674284                if (_isFinalBlock && TokenType is JsonTokenType.None && !_readerOptions.AllowMultipleValues)
 336285                {
 336286                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedJsonTokens);
 287                }
 1338288            }
 18588289            return retVal;
 18588290        }
 291
 292        /// <summary>
 293        /// Skips the children of the current JSON token.
 294        /// </summary>
 295        /// <exception cref="InvalidOperationException">
 296        /// Thrown when the reader was given partial data with more data to follow (i.e. <see cref="IsFinalBlock"/> is f
 297        /// </exception>
 298        /// <exception cref="JsonException">
 299        /// Thrown when an invalid JSON token is encountered while skipping, according to the JSON RFC,
 300        /// or if the current depth exceeds the recursive limit set by the max depth.
 301        /// </exception>
 302        /// <remarks>
 303        /// When <see cref="TokenType"/> is <see cref="JsonTokenType.PropertyName" />, the reader first moves to the pro
 304        /// When <see cref="TokenType"/> (originally, or after advancing) is <see cref="JsonTokenType.StartObject" /> or
 305        /// <see cref="JsonTokenType.StartArray" />, the reader advances to the matching
 306        /// <see cref="JsonTokenType.EndObject" /> or <see cref="JsonTokenType.EndArray" />.
 307        ///
 308        /// For all other token types, the reader does not move. After the next call to <see cref="Read"/>, the reader w
 309        /// the next value (when in an array), the next property name (when in an object), or the end array/object token
 310        /// </remarks>
 311        public void Skip()
 0312        {
 0313            if (!_isFinalBlock)
 0314            {
 0315                ThrowHelper.ThrowInvalidOperationException_CannotSkipOnPartial();
 316            }
 317
 0318            SkipHelper();
 0319        }
 320
 321        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 322        private void SkipHelper()
 1212323        {
 1212324            Debug.Assert(_isFinalBlock);
 325
 1212326            if (TokenType is JsonTokenType.PropertyName)
 0327            {
 0328                bool result = Read();
 329                // Since _isFinalBlock == true here, and the JSON token is not a primitive value or comment.
 330                // Read() is guaranteed to return true OR throw for invalid/incomplete data.
 0331                Debug.Assert(result);
 0332            }
 333
 1212334            if (TokenType is JsonTokenType.StartObject or JsonTokenType.StartArray)
 1212335            {
 1212336                int depth = CurrentDepth;
 337                do
 1728338                {
 1728339                    bool result = Read();
 340                    // Since _isFinalBlock == true here, and the JSON token is not a primitive value or comment.
 341                    // Read() is guaranteed to return true OR throw for invalid/incomplete data.
 516342                    Debug.Assert(result);
 516343                }
 516344                while (depth < CurrentDepth);
 0345            }
 0346        }
 347
 348        /// <summary>
 349        /// Tries to skip the children of the current JSON token.
 350        /// </summary>
 351        /// <returns>True if there was enough data for the children to be skipped successfully, else false.</returns>
 352        /// <exception cref="JsonException">
 353        /// Thrown when an invalid JSON token is encountered while skipping, according to the JSON RFC,
 354        /// or if the current depth exceeds the recursive limit set by the max depth.
 355        /// </exception>
 356        /// <remarks>
 357        ///   <para>
 358        ///     If the reader did not have enough data to completely skip the children of the current token,
 359        ///     it will be reset to the state it was in before the method was called.
 360        ///   </para>
 361        ///   <para>
 362        ///     When <see cref="TokenType"/> is <see cref="JsonTokenType.PropertyName" />, the reader first moves to the
 363        ///     When <see cref="TokenType"/> (originally, or after advancing) is <see cref="JsonTokenType.StartObject" /
 364        ///     <see cref="JsonTokenType.StartArray" />, the reader advances to the matching
 365        ///     <see cref="JsonTokenType.EndObject" /> or <see cref="JsonTokenType.EndArray" />.
 366        ///
 367        ///     For all other token types, the reader does not move. After the next call to <see cref="Read"/>, the read
 368        ///     the next value (when in an array), the next property name (when in an object), or the end array/object t
 369        ///   </para>
 370        /// </remarks>
 371        public bool TrySkip()
 1212372        {
 1212373            if (_isFinalBlock)
 1212374            {
 1212375                SkipHelper();
 0376                return true;
 377            }
 378
 0379            Utf8JsonReader restore = this;
 0380            bool success = TrySkipPartial(targetDepth: CurrentDepth);
 0381            if (!success)
 0382            {
 383                // Roll back the reader if it contains partial data.
 0384                this = restore;
 0385            }
 386
 0387            return success;
 0388        }
 389
 390        /// <summary>
 391        /// Tries to skip the children of the current JSON token, advancing the reader even if there is not enough data.
 392        /// The skip operation can be resumed later, provided that the same <paramref name="targetDepth" /> is passed.
 393        /// </summary>
 394        /// <param name="targetDepth">The target depth we want to eventually skip to.</param>
 395        /// <returns>True if the entire JSON value has been skipped.</returns>
 396        internal bool TrySkipPartial(int targetDepth)
 0397        {
 0398            Debug.Assert(0 <= targetDepth && targetDepth <= CurrentDepth);
 399
 0400            if (targetDepth == CurrentDepth)
 0401            {
 402                // This is the first call to TrySkipHelper.
 0403                if (TokenType is JsonTokenType.PropertyName)
 0404                {
 405                    // Skip any property name tokens preceding the value.
 0406                    if (!Read())
 0407                    {
 0408                        return false;
 409                    }
 0410                }
 411
 0412                if (TokenType is not (JsonTokenType.StartObject or JsonTokenType.StartArray))
 0413                {
 414                    // The next value is not an object or array, so there is nothing to skip.
 0415                    return true;
 416                }
 0417            }
 418
 419            // Start or resume iterating through the JSON object or array.
 420            do
 0421            {
 0422                if (!Read())
 0423                {
 0424                    return false;
 425                }
 0426            }
 0427            while (targetDepth < CurrentDepth);
 428
 0429            Debug.Assert(targetDepth == CurrentDepth);
 0430            return true;
 0431        }
 432
 433        /// <summary>
 434        /// Compares the UTF-8 encoded text to the unescaped JSON token value in the source and returns true if they mat
 435        /// </summary>
 436        /// <param name="utf8Text">The UTF-8 encoded text to compare against.</param>
 437        /// <returns>True if the JSON token value in the source matches the UTF-8 encoded look up text.</returns>
 438        /// <exception cref="InvalidOperationException">
 439        /// Thrown if trying to find a text match on a JSON token that is not a string
 440        /// (i.e. other than <see cref="JsonTokenType.String"/> or <see cref="JsonTokenType.PropertyName"/>).
 441        /// <seealso cref="TokenType" />
 442        /// </exception>
 443        /// <remarks>
 444        ///   <para>
 445        ///     If the look up text is invalid UTF-8 text, the method will return false since you cannot have
 446        ///     invalid UTF-8 within the JSON payload.
 447        ///   </para>
 448        ///   <para>
 449        ///     The comparison of the JSON token value in the source and the look up text is done by first unescaping th
 450        ///     if required. The look up text is matched as is, without any modifications to it.
 451        ///   </para>
 452        /// </remarks>
 453        public readonly bool ValueTextEquals(ReadOnlySpan<byte> utf8Text)
 0454        {
 0455            if (!IsTokenTypeString(TokenType))
 0456            {
 0457                ThrowHelper.ThrowInvalidOperationException_ExpectedStringComparison(TokenType);
 458            }
 459
 0460            return TextEqualsHelper(utf8Text);
 0461        }
 462
 463        /// <summary>
 464        /// Compares the string text to the unescaped JSON token value in the source and returns true if they match.
 465        /// </summary>
 466        /// <param name="text">The text to compare against.</param>
 467        /// <returns>True if the JSON token value in the source matches the look up text.</returns>
 468        /// <exception cref="InvalidOperationException">
 469        /// Thrown if trying to find a text match on a JSON token that is not a string
 470        /// (i.e. other than <see cref="JsonTokenType.String"/> or <see cref="JsonTokenType.PropertyName"/>).
 471        /// <seealso cref="TokenType" />
 472        /// </exception>
 473        /// <remarks>
 474        ///   <para>
 475        ///     If the look up text is invalid UTF-8 text, the method will return false since you cannot have
 476        ///     invalid UTF-8 within the JSON payload.
 477        ///   </para>
 478        ///   <para>
 479        ///     The comparison of the JSON token value in the source and the look up text is done by first unescaping th
 480        ///     if required. The look up text is matched as is, without any modifications to it.
 481        ///   </para>
 482        /// </remarks>
 483        public readonly bool ValueTextEquals(string? text)
 0484        {
 0485            return ValueTextEquals(text.AsSpan());
 0486        }
 487
 488        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 489        private readonly bool TextEqualsHelper(ReadOnlySpan<byte> otherUtf8Text)
 0490        {
 0491            if (HasValueSequence)
 0492            {
 0493                return CompareToSequence(otherUtf8Text);
 494            }
 495
 0496            if (ValueIsEscaped)
 0497            {
 0498                return UnescapeAndCompare(otherUtf8Text);
 499            }
 500
 0501            return otherUtf8Text.SequenceEqual(ValueSpan);
 0502        }
 503
 504        /// <summary>
 505        /// Compares the text to the unescaped JSON token value in the source and returns true if they match.
 506        /// </summary>
 507        /// <param name="text">The text to compare against.</param>
 508        /// <returns>True if the JSON token value in the source matches the look up text.</returns>
 509        /// <exception cref="InvalidOperationException">
 510        /// Thrown if trying to find a text match on a JSON token that is not a string
 511        /// (i.e. other than <see cref="JsonTokenType.String"/> or <see cref="JsonTokenType.PropertyName"/>).
 512        /// <seealso cref="TokenType" />
 513        /// </exception>
 514        /// <remarks>
 515        ///   <para>
 516        ///     If the look up text is invalid or incomplete UTF-16 text (i.e. unpaired surrogates), the method will ret
 517        ///     since you cannot have invalid UTF-16 within the JSON payload.
 518        ///   </para>
 519        ///   <para>
 520        ///     The comparison of the JSON token value in the source and the look up text is done by first unescaping th
 521        ///     if required. The look up text is matched as is, without any modifications to it.
 522        ///   </para>
 523        /// </remarks>
 524        public readonly unsafe bool ValueTextEquals(ReadOnlySpan<char> text)
 0525        {
 0526            if (!IsTokenTypeString(TokenType))
 0527            {
 0528                ThrowHelper.ThrowInvalidOperationException_ExpectedStringComparison(TokenType);
 529            }
 530
 0531            if (MatchNotPossible(text.Length))
 0532            {
 0533                return false;
 534            }
 535
 0536            byte[]? otherUtf8TextArray = null;
 537
 538            scoped Span<byte> otherUtf8Text;
 539
 0540            int length = checked(text.Length * JsonConstants.MaxExpansionFactorWhileTranscoding);
 541
 0542            if (length > JsonConstants.StackallocByteThreshold)
 0543            {
 0544                otherUtf8TextArray = ArrayPool<byte>.Shared.Rent(length);
 0545                otherUtf8Text = otherUtf8TextArray;
 0546            }
 547            else
 0548            {
 0549                otherUtf8Text = stackalloc byte[JsonConstants.StackallocByteThreshold];
 0550            }
 551
 0552            OperationStatus status = JsonWriterHelper.ToUtf8(text, otherUtf8Text, out int written);
 0553            Debug.Assert(status != OperationStatus.DestinationTooSmall);
 554            bool result;
 0555            if (status == OperationStatus.InvalidData)
 0556            {
 0557                result = false;
 0558            }
 559            else
 0560            {
 0561                Debug.Assert(status == OperationStatus.Done);
 0562                result = TextEqualsHelper(otherUtf8Text.Slice(0, written));
 0563            }
 564
 0565            if (otherUtf8TextArray is not null)
 0566            {
 0567                otherUtf8Text.Slice(0, written).Clear();
 0568                ArrayPool<byte>.Shared.Return(otherUtf8TextArray);
 0569            }
 570
 0571            return result;
 0572        }
 573
 574        private readonly bool CompareToSequence(ReadOnlySpan<byte> other)
 0575        {
 0576            Debug.Assert(HasValueSequence);
 577
 0578            if (ValueIsEscaped)
 0579            {
 0580                return UnescapeSequenceAndCompare(other);
 581            }
 582
 0583            ReadOnlySequence<byte> localSequence = ValueSequence;
 584
 0585            Debug.Assert(!localSequence.IsSingleSegment);
 586
 0587            if (localSequence.Length != other.Length)
 0588            {
 0589                return false;
 590            }
 591
 0592            int matchedSoFar = 0;
 593
 0594            foreach (ReadOnlyMemory<byte> memory in localSequence)
 0595            {
 0596                ReadOnlySpan<byte> span = memory.Span;
 597
 0598                if (other.Slice(matchedSoFar).StartsWith(span))
 0599                {
 0600                    matchedSoFar += span.Length;
 0601                }
 602                else
 0603                {
 0604                    return false;
 605                }
 0606            }
 0607            return true;
 0608        }
 609
 610        private readonly bool UnescapeAndCompare(ReadOnlySpan<byte> other)
 0611        {
 0612            Debug.Assert(!HasValueSequence);
 0613            ReadOnlySpan<byte> localSpan = ValueSpan;
 614
 0615            if (localSpan.Length < other.Length || localSpan.Length / JsonConstants.MaxExpansionFactorWhileEscaping > ot
 0616            {
 0617                return false;
 618            }
 619
 0620            int idx = localSpan.IndexOf(JsonConstants.BackSlash);
 0621            Debug.Assert(idx != -1);
 622
 0623            if (!other.StartsWith(localSpan.Slice(0, idx)))
 0624            {
 0625                return false;
 626            }
 627
 0628            return JsonReaderHelper.UnescapeAndCompare(localSpan.Slice(idx), other.Slice(idx));
 0629        }
 630
 631        private readonly bool UnescapeSequenceAndCompare(ReadOnlySpan<byte> other)
 0632        {
 0633            Debug.Assert(HasValueSequence);
 0634            Debug.Assert(!ValueSequence.IsSingleSegment);
 635
 0636            ReadOnlySequence<byte> localSequence = ValueSequence;
 0637            long sequenceLength = localSequence.Length;
 638
 639            // The JSON token value will at most shrink by 6 when unescaping.
 640            // If it is still larger than the lookup string, there is no value in unescaping and doing the comparison.
 0641            if (sequenceLength < other.Length || sequenceLength / JsonConstants.MaxExpansionFactorWhileEscaping > other.
 0642            {
 0643                return false;
 644            }
 645
 0646            int matchedSoFar = 0;
 647
 0648            bool result = false;
 649
 0650            foreach (ReadOnlyMemory<byte> memory in localSequence)
 0651            {
 0652                ReadOnlySpan<byte> span = memory.Span;
 653
 0654                int idx = span.IndexOf(JsonConstants.BackSlash);
 655
 0656                if (idx != -1)
 0657                {
 0658                    if (!other.Slice(matchedSoFar).StartsWith(span.Slice(0, idx)))
 0659                    {
 0660                        break;
 661                    }
 0662                    matchedSoFar += idx;
 663
 0664                    other = other.Slice(matchedSoFar);
 0665                    localSequence = localSequence.Slice(matchedSoFar);
 666
 0667                    if (localSequence.IsSingleSegment)
 0668                    {
 0669                        result = JsonReaderHelper.UnescapeAndCompare(localSequence.FirstSpan, other);
 0670                    }
 671                    else
 0672                    {
 0673                        result = JsonReaderHelper.UnescapeAndCompare(localSequence, other);
 0674                    }
 0675                    break;
 676                }
 677
 0678                if (!other.Slice(matchedSoFar).StartsWith(span))
 0679                {
 0680                    break;
 681                }
 0682                matchedSoFar += span.Length;
 0683            }
 684
 0685            return result;
 0686        }
 687
 688        // Returns true if the TokenType is a primitive string "value", i.e. PropertyName or String
 689        // Otherwise, return false.
 690        private static bool IsTokenTypeString(JsonTokenType tokenType)
 0691        {
 0692            return tokenType is JsonTokenType.PropertyName or JsonTokenType.String;
 0693        }
 694
 695        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 696        private readonly bool MatchNotPossible(int charTextLength)
 0697        {
 0698            if (HasValueSequence)
 0699            {
 0700                return MatchNotPossibleSequence(charTextLength);
 701            }
 702
 0703            int sourceLength = ValueSpan.Length;
 704
 705            // Transcoding from UTF-16 to UTF-8 will change the length by somwhere between 1x and 3x.
 706            // Unescaping the token value will at most shrink its length by 6x.
 707            // There is no point incurring the transcoding/unescaping/comparing cost if:
 708            // - The token value is smaller than charTextLength
 709            // - The token value needs to be transcoded AND unescaped and it is more than 6x larger than charTextLength
 710            //      - For an ASCII UTF-16 characters, transcoding = 1x, escaping = 6x => 6x factor
 711            //      - For non-ASCII UTF-16 characters within the BMP, transcoding = 2-3x, but they are represented as a 
 712            //      - For non-ASCII UTF-16 characters outside of the BMP, transcoding = 4x, but the surrogate pair (2 ch
 713            // - The token value needs to be transcoded, but NOT escaped and it is more than 3x larger than charTextLeng
 714            //      - For an ASCII UTF-16 characters, transcoding = 1x,
 715            //      - For non-ASCII UTF-16 characters within the BMP, transcoding = 2-3x,
 716            //      - For non-ASCII UTF-16 characters outside of the BMP, transcoding = 2x, (surrogate pairs - 2 charact
 717
 0718            if (sourceLength < charTextLength
 0719                || sourceLength / (ValueIsEscaped ? JsonConstants.MaxExpansionFactorWhileEscaping : JsonConstants.MaxExp
 0720            {
 0721                return true;
 722            }
 0723            return false;
 0724        }
 725
 726        [MethodImpl(MethodImplOptions.NoInlining)]
 727        private readonly bool MatchNotPossibleSequence(int charTextLength)
 0728        {
 0729            long sourceLength = ValueSequence.Length;
 730
 0731            if (sourceLength < charTextLength
 0732                || sourceLength / (ValueIsEscaped ? JsonConstants.MaxExpansionFactorWhileEscaping : JsonConstants.MaxExp
 0733            {
 0734                return true;
 735            }
 0736            return false;
 0737        }
 738
 739        private void StartObject()
 0740        {
 0741            if (_bitStack.CurrentDepth >= _readerOptions.MaxDepth)
 0742                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ObjectDepthTooLarge);
 743
 0744            _bitStack.PushTrue();
 745
 0746            ValueSpan = _buffer.Slice(_consumed, 1);
 0747            _consumed++;
 0748            _bytePositionInLine++;
 0749            _tokenType = JsonTokenType.StartObject;
 0750            _inObject = true;
 0751        }
 752
 753        private void EndObject()
 0754        {
 0755            if (!_inObject || _bitStack.CurrentDepth <= 0)
 0756                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.MismatchedObjectArray, JsonConstants.Cl
 757
 0758            if (_trailingCommaBeforeComment)
 0759            {
 0760                if (!_readerOptions.AllowTrailingCommas)
 0761                {
 0762                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeObject
 763                }
 0764                _trailingCommaBeforeComment = false;
 0765            }
 766
 0767            _tokenType = JsonTokenType.EndObject;
 0768            ValueSpan = _buffer.Slice(_consumed, 1);
 769
 0770            UpdateBitStackOnEndToken();
 0771        }
 772
 773        private void StartArray()
 528774        {
 528775            if (_bitStack.CurrentDepth >= _readerOptions.MaxDepth)
 0776                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ArrayDepthTooLarge);
 777
 528778            _bitStack.PushFalse();
 779
 528780            ValueSpan = _buffer.Slice(_consumed, 1);
 528781            _consumed++;
 528782            _bytePositionInLine++;
 528783            _tokenType = JsonTokenType.StartArray;
 528784            _inObject = false;
 528785        }
 786
 787        private void EndArray()
 0788        {
 0789            if (_inObject || _bitStack.CurrentDepth <= 0)
 0790                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.MismatchedObjectArray, JsonConstants.Cl
 791
 0792            if (_trailingCommaBeforeComment)
 0793            {
 0794                if (!_readerOptions.AllowTrailingCommas)
 0795                {
 0796                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeArrayE
 797                }
 0798                _trailingCommaBeforeComment = false;
 0799            }
 800
 0801            _tokenType = JsonTokenType.EndArray;
 0802            ValueSpan = _buffer.Slice(_consumed, 1);
 803
 0804            UpdateBitStackOnEndToken();
 0805        }
 806
 807        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 808        private void UpdateBitStackOnEndToken()
 0809        {
 0810            _consumed++;
 0811            _bytePositionInLine++;
 0812            _inObject = _bitStack.Pop();
 0813        }
 814
 815        private bool ReadSingleSegment()
 21645816        {
 21645817            bool retVal = false;
 21645818            ValueSpan = default;
 21645819            ValueIsEscaped = false;
 820
 21645821            if (!HasMoreData())
 670822            {
 670823                goto Done;
 824            }
 825
 20975826            byte first = _buffer[_consumed];
 827
 828            // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 829            // SkipWhiteSpace only skips the whitespace characters as defined by JSON RFC 8259 section 2.
 830            // We do not validate if 'first' is an invalid JSON byte here (such as control characters).
 831            // Those cases are captured in ConsumeNextToken and ConsumeValue.
 20975832            if (first <= JsonConstants.Space)
 11836833            {
 11836834                SkipWhiteSpace();
 11836835                if (!HasMoreData())
 489836                {
 489837                    goto Done;
 838                }
 11294839                first = _buffer[_consumed];
 11294840            }
 841
 20433842            TokenStartIndex = _consumed;
 843
 20433844            if (_tokenType == JsonTokenType.None)
 18392845            {
 18392846                goto ReadFirstToken;
 847            }
 848
 2041849            if (first == JsonConstants.Slash)
 7850            {
 7851                retVal = ConsumeNextTokenOrRollback(first);
 0852                goto Done;
 853            }
 854
 2034855            if (_tokenType == JsonTokenType.StartObject)
 58856            {
 58857                if (first == JsonConstants.CloseBrace)
 0858                {
 0859                    EndObject();
 0860                }
 861                else
 58862                {
 58863                    if (first != JsonConstants.Quote)
 58864                    {
 58865                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 866                    }
 867
 0868                    int prevConsumed = _consumed;
 0869                    long prevPosition = _bytePositionInLine;
 0870                    long prevLineNumber = _lineNumber;
 0871                    retVal = ConsumePropertyName();
 0872                    if (!retVal)
 0873                    {
 874                        // roll back potential changes
 0875                        _consumed = prevConsumed;
 0876                        _tokenType = JsonTokenType.StartObject;
 0877                        _bytePositionInLine = prevPosition;
 0878                        _lineNumber = prevLineNumber;
 0879                    }
 0880                    goto Done;
 881                }
 0882            }
 1976883            else if (_tokenType == JsonTokenType.StartArray)
 951884            {
 951885                if (first == JsonConstants.CloseBracket)
 0886                {
 0887                    EndArray();
 0888                }
 889                else
 951890                {
 951891                    retVal = ConsumeValue(first);
 353892                    goto Done;
 893                }
 0894            }
 1025895            else if (_tokenType == JsonTokenType.PropertyName)
 0896            {
 0897                retVal = ConsumeValue(first);
 0898                goto Done;
 899            }
 900            else
 1025901            {
 1025902                retVal = ConsumeNextTokenOrRollback(first);
 0903                goto Done;
 904            }
 905
 0906            retVal = true;
 907
 10160908        Done:
 10160909            return retVal;
 910
 18392911        ReadFirstToken:
 18392912            retVal = ReadFirstToken(first);
 8648913            goto Done;
 10160914        }
 915
 916        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 917        private bool HasMoreData()
 33481918        {
 33481919            if (_consumed >= (uint)_buffer.Length)
 1212920            {
 1212921                if (_isNotPrimitive && IsLastSpan)
 53922                {
 53923                    if (_bitStack.CurrentDepth != 0)
 53924                    {
 53925                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ZeroDepthAtEnd);
 926                    }
 927
 0928                    if (_readerOptions.CommentHandling == JsonCommentHandling.Allow && _tokenType == JsonTokenType.Comme
 0929                    {
 0930                        return false;
 931                    }
 932
 0933                    if (_tokenType is not JsonTokenType.EndArray and not JsonTokenType.EndObject)
 0934                    {
 0935                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidEndOfJsonNonPrimitive);
 936                    }
 0937                }
 1159938                return false;
 939            }
 32269940            return true;
 33428941        }
 942
 943        // Unlike the parameter-less overload of HasMoreData, if there is no more data when this method is called, we kn
 944        // This is because, this method is only called after a ',' (i.e. we expect a value/property name) or after
 945        // a property name, which means it must be followed by a value.
 946        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 947        private bool HasMoreData(ExceptionResource resource)
 0948        {
 0949            if (_consumed >= (uint)_buffer.Length)
 0950            {
 0951                if (IsLastSpan)
 0952                {
 0953                    ThrowHelper.ThrowJsonReaderException(ref this, resource);
 954                }
 0955                return false;
 956            }
 0957            return true;
 0958        }
 959
 960        private bool ReadFirstToken(byte first)
 18392961        {
 18392962            if (first == JsonConstants.OpenBrace)
 252963            {
 252964                _bitStack.SetFirstBit();
 252965                _tokenType = JsonTokenType.StartObject;
 252966                ValueSpan = _buffer.Slice(_consumed, 1);
 252967                _consumed++;
 252968                _bytePositionInLine++;
 252969                _inObject = true;
 252970                _isNotPrimitive = true;
 252971            }
 18140972            else if (first == JsonConstants.OpenBracket)
 3990973            {
 3990974                _bitStack.ResetFirstBit();
 3990975                _tokenType = JsonTokenType.StartArray;
 3990976                ValueSpan = _buffer.Slice(_consumed, 1);
 3990977                _consumed++;
 3990978                _bytePositionInLine++;
 3990979                _isNotPrimitive = true;
 3990980            }
 981            else
 14150982            {
 983                // Create local copy to avoid bounds checks.
 14150984                ReadOnlySpan<byte> localBuffer = _buffer;
 985
 14150986                if (JsonHelpers.IsDigit(first) || first == '-')
 1998987                {
 1998988                    if (!TryGetNumber(localBuffer.Slice(_consumed), out int numberOfBytes))
 0989                    {
 0990                        return false;
 991                    }
 1662992                    _tokenType = JsonTokenType.Number;
 1662993                    _consumed += numberOfBytes;
 1662994                    _bytePositionInLine += numberOfBytes;
 1662995                }
 12152996                else if (!ConsumeValue(first))
 0997                {
 0998                    return false;
 999                }
 1000
 44061001                _isNotPrimitive = _tokenType is JsonTokenType.StartObject or JsonTokenType.StartArray;
 1002                // Intentionally fall out of the if-block to return true
 44061003            }
 86481004            return true;
 86481005        }
 1006
 1007        private void SkipWhiteSpace()
 299731008        {
 1009            // Create local copy to avoid bounds checks.
 299731010            ReadOnlySpan<byte> localBuffer = _buffer;
 1011#if NET
 1012            // A vectorized SearchValues-based scan to the first non-whitespace byte is fastest on most
 1013            // runtimes, so we go straight to it. On Mono/WASM AOT (browser) the fixed per-call SIMD
 1014            // entry cost is high relative to the short inter-token whitespace runs typical of JSON,
 1015            // and reconstructing the line/byte-position bookkeeping needs up to two more vectorized
 1016            // passes (CountNewLines), so short runs regress there. The browser path therefore uses the
 1017            // plain scalar loop below instead. OperatingSystem.IsBrowser() folds to a constant per
 1018            // target, so only one path survives in codegen and non-browser output is unchanged from a
 1019            // direct vectorized scan.
 299731020            if (!OperatingSystem.IsBrowser())
 299731021            {
 299731022                ReadOnlySpan<byte> remaining = localBuffer.Slice(_consumed);
 299731023                int idx = remaining.IndexOfFirstNonWhiteSpace();
 299731024                if (idx > 0)
 252781025                {
 1026                    // Reproduce the scalar loop's line/byte-position bookkeeping for the skipped run.
 252781027                    (int newLines, int lastLineFeedIndex) = JsonReaderHelper.CountNewLines(remaining.Slice(0, idx));
 252781028                    _lineNumber += newLines;
 252781029                    if (lastLineFeedIndex >= 0)
 6181030                    {
 1031                        // Byte positions on the current line start after the last line feed character.
 6181032                        _bytePositionInLine = idx - lastLineFeedIndex - 1;
 6181033                    }
 1034                    else
 246601035                    {
 246601036                        _bytePositionInLine += idx;
 246601037                    }
 1038
 252781039                    _consumed += idx;
 252781040                }
 1041
 252781042                return;
 1043            }
 1044#endif
 01045            for (; _consumed < localBuffer.Length; _consumed++)
 01046            {
 01047                byte val = localBuffer[_consumed];
 1048
 1049                // JSON RFC 8259 section 2 says only these 4 characters count, not all of the Unicode definitions of whi
 01050                if (val is not JsonConstants.Space and
 01051                           not JsonConstants.CarriageReturn and
 01052                           not JsonConstants.LineFeed and
 01053                           not JsonConstants.Tab)
 01054                {
 01055                    break;
 1056                }
 1057
 01058                if (val == JsonConstants.LineFeed)
 01059                {
 01060                    _lineNumber++;
 01061                    _bytePositionInLine = 0;
 01062                }
 1063                else
 01064                {
 01065                    _bytePositionInLine++;
 01066                }
 01067            }
 299731068        }
 1069
 1070        /// <summary>
 1071        /// This method contains the logic for processing the next value token and determining
 1072        /// what type of data it is.
 1073        /// </summary>
 1074        private bool ConsumeValue(byte marker)
 131031075        {
 131031076            while (true)
 131031077            {
 131031078                Debug.Assert((_trailingCommaBeforeComment && _readerOptions.CommentHandling == JsonCommentHandling.Allow
 131031079                Debug.Assert((_trailingCommaBeforeComment && marker != JsonConstants.Slash) || !_trailingCommaBeforeComm
 131031080                _trailingCommaBeforeComment = false;
 1081
 131031082                if (marker == JsonConstants.Quote)
 32401083                {
 32401084                    return ConsumeString();
 1085                }
 98631086                else if (marker == JsonConstants.OpenBrace)
 01087                {
 01088                    StartObject();
 01089                }
 98631090                else if (marker == JsonConstants.OpenBracket)
 2641091                {
 2641092                    StartArray();
 2641093                }
 95991094                else if (JsonHelpers.IsDigit(marker) || marker == '-')
 1641095                {
 1641096                    return ConsumeNumber();
 1097                }
 94351098                else if (marker == 'f')
 421099                {
 421100                    return ConsumeLiteral(JsonConstants.FalseValue, JsonTokenType.False);
 1101                }
 93931102                else if (marker == 't')
 81103                {
 81104                    return ConsumeLiteral(JsonConstants.TrueValue, JsonTokenType.True);
 1105                }
 93851106                else if (marker == 'n')
 01107                {
 01108                    return ConsumeLiteral(JsonConstants.NullValue, JsonTokenType.Null);
 1109                }
 1110                else
 93851111                {
 93851112                    switch (_readerOptions.CommentHandling)
 1113                    {
 1114                        case JsonCommentHandling.Disallow:
 50731115                            break;
 1116                        case JsonCommentHandling.Allow:
 01117                            if (marker == JsonConstants.Slash)
 01118                            {
 01119                                return ConsumeComment();
 1120                            }
 01121                            break;
 1122                        default:
 43121123                            Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Skip);
 43121124                            if (marker == JsonConstants.Slash)
 821125                            {
 821126                                if (SkipComment())
 01127                                {
 01128                                    if (_consumed >= (uint)_buffer.Length)
 01129                                    {
 01130                                        if (_isNotPrimitive && IsLastSpan && _tokenType != JsonTokenType.EndArray && _to
 01131                                        {
 01132                                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidEndO
 1133                                        }
 01134                                        return false;
 1135                                    }
 1136
 01137                                    marker = _buffer[_consumed];
 1138
 1139                                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not ne
 01140                                    if (marker <= JsonConstants.Space)
 01141                                    {
 01142                                        SkipWhiteSpace();
 01143                                        if (!HasMoreData())
 01144                                        {
 01145                                            return false;
 1146                                        }
 01147                                        marker = _buffer[_consumed];
 01148                                    }
 1149
 01150                                    TokenStartIndex = _consumed;
 1151
 1152                                    // Skip comments and consume the actual JSON value.
 01153                                    continue;
 1154                                }
 01155                                return false;
 1156                            }
 42301157                            break;
 1158                    }
 93031159                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfValueNotFound, marke
 1160                }
 2641161                break;
 1162            }
 2641163            return true;
 30971164        }
 1165
 1166        // Consumes 'null', or 'true', or 'false'
 1167        private bool ConsumeLiteral(ReadOnlySpan<byte> literal, JsonTokenType tokenType)
 501168        {
 501169            ReadOnlySpan<byte> span = _buffer.Slice(_consumed);
 501170            Debug.Assert(span.Length > 0);
 501171            Debug.Assert(span[0] == 'n' || span[0] == 't' || span[0] == 'f');
 1172
 501173            if (!span.StartsWith(literal))
 501174            {
 501175                return CheckLiteral(span, literal);
 1176            }
 1177
 01178            ValueSpan = span.Slice(0, literal.Length);
 01179            _tokenType = tokenType;
 01180            _consumed += literal.Length;
 01181            _bytePositionInLine += literal.Length;
 01182            return true;
 01183        }
 1184
 1185        private bool CheckLiteral(ReadOnlySpan<byte> span, ReadOnlySpan<byte> literal)
 501186        {
 501187            Debug.Assert(span.Length > 0 && span[0] == literal[0]);
 1188
 501189            int indexOfFirstMismatch = 0;
 1190
 1001191            for (int i = 1; i < literal.Length; i++)
 501192            {
 501193                if (span.Length > i)
 501194                {
 501195                    if (span[i] != literal[i])
 501196                    {
 501197                        _bytePositionInLine += i;
 501198                        ThrowInvalidLiteral(span);
 01199                    }
 01200                }
 1201                else
 01202                {
 01203                    indexOfFirstMismatch = i;
 01204                    break;
 1205                }
 01206            }
 1207
 01208            Debug.Assert(indexOfFirstMismatch > 0 && indexOfFirstMismatch < literal.Length);
 1209
 01210            if (IsLastSpan)
 01211            {
 01212                _bytePositionInLine += indexOfFirstMismatch;
 01213                ThrowInvalidLiteral(span);
 01214            }
 01215            return false;
 01216        }
 1217
 1218        private void ThrowInvalidLiteral(ReadOnlySpan<byte> span)
 501219        {
 501220            byte firstByte = span[0];
 1221
 1222            ExceptionResource resource;
 501223            switch (firstByte)
 1224            {
 1225                case (byte)'t':
 81226                    resource = ExceptionResource.ExpectedTrue;
 81227                    break;
 1228                case (byte)'f':
 421229                    resource = ExceptionResource.ExpectedFalse;
 421230                    break;
 1231                default:
 01232                    Debug.Assert(firstByte == 'n');
 01233                    resource = ExceptionResource.ExpectedNull;
 01234                    break;
 1235            }
 501236            ThrowHelper.ThrowJsonReaderException(ref this, resource, bytes: span);
 1237        }
 1238
 1239        private bool ConsumeNumber()
 1641240        {
 1641241            if (!TryGetNumber(_buffer.Slice(_consumed), out int consumed))
 01242            {
 01243                return false;
 1244            }
 1245
 1051246            _tokenType = JsonTokenType.Number;
 1051247            _consumed += consumed;
 1051248            _bytePositionInLine += consumed;
 1249
 1051250            if (_consumed >= (uint)_buffer.Length)
 161251            {
 161252                Debug.Assert(IsLastSpan);
 1253
 1254                // If there is no more data, and the JSON is not a single value, throw.
 161255                if (_isNotPrimitive)
 161256                {
 161257                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, _buffer
 1258                }
 01259            }
 1260
 1261            // If there is more data and the JSON is not a single value, assert that there is an end of number delimiter
 1262            // Else, if either the JSON is a single value XOR if there is no more data, don't assert anything since ther
 891263            Debug.Assert(
 891264                ((_consumed < _buffer.Length) &&
 891265                !_isNotPrimitive &&
 891266                JsonConstants.Delimiters.Contains(_buffer[_consumed]))
 891267                || (_isNotPrimitive ^ (_consumed >= (uint)_buffer.Length)));
 1268
 891269            return true;
 891270        }
 1271
 1272        private bool ConsumePropertyName()
 01273        {
 01274            _trailingCommaBeforeComment = false;
 1275
 01276            if (!ConsumeString())
 01277            {
 01278                return false;
 1279            }
 1280
 01281            if (!HasMoreData(ExceptionResource.ExpectedValueAfterPropertyNameNotFound))
 01282            {
 01283                return false;
 1284            }
 1285
 01286            byte first = _buffer[_consumed];
 1287
 1288            // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 1289            // We do not validate if 'first' is an invalid JSON byte here (such as control characters).
 1290            // Those cases are captured below where we only accept ':'.
 01291            if (first <= JsonConstants.Space)
 01292            {
 01293                SkipWhiteSpace();
 01294                if (!HasMoreData(ExceptionResource.ExpectedValueAfterPropertyNameNotFound))
 01295                {
 01296                    return false;
 1297                }
 01298                first = _buffer[_consumed];
 01299            }
 1300
 1301            // The next character must be a key / value separator. Validate and skip.
 01302            if (first != JsonConstants.KeyValueSeparator)
 01303            {
 01304                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedSeparatorAfterPropertyNameNotFo
 1305            }
 1306
 01307            _consumed++;
 01308            _bytePositionInLine++;
 01309            _tokenType = JsonTokenType.PropertyName;
 01310            return true;
 01311        }
 1312
 1313        private bool ConsumeString()
 32401314        {
 32401315            Debug.Assert(_buffer.Length >= _consumed + 1);
 32401316            Debug.Assert(_buffer[_consumed] == JsonConstants.Quote);
 1317
 1318            // Create local copy to avoid bounds checks.
 32401319            ReadOnlySpan<byte> localBuffer = _buffer.Slice(_consumed + 1);
 1320
 1321            // Vectorized search for either quote, backslash, or any control character.
 1322            // If the first found byte is a quote, we have reached an end of string, and
 1323            // can avoid validation.
 1324            // Otherwise, in the uncommon case, iterate one character at a time and validate.
 32401325            int idx = localBuffer.IndexOfQuoteOrAnyControlOrBackSlash();
 1326
 32401327            if (idx >= 0)
 30221328            {
 30221329                byte foundByte = localBuffer[idx];
 30221330                if (foundByte == JsonConstants.Quote)
 26961331                {
 26961332                    _bytePositionInLine += idx + 2; // Add 2 for the start and end quotes.
 26961333                    ValueSpan = localBuffer.Slice(0, idx);
 26961334                    ValueIsEscaped = false;
 26961335                    _tokenType = JsonTokenType.String;
 26961336                    _consumed += idx + 2;
 26961337                    return true;
 1338                }
 1339                else
 3261340                {
 3261341                    return ConsumeStringAndValidate(localBuffer, idx);
 1342                }
 1343            }
 1344            else
 2181345            {
 2181346                if (IsLastSpan)
 2181347                {
 2181348                    _bytePositionInLine += localBuffer.Length + 1;  // Account for the start quote
 2181349                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound);
 1350                }
 01351                return false;
 1352            }
 27441353        }
 1354
 1355        // Found a backslash or control characters which are considered invalid within a string.
 1356        // Search through the rest of the string one byte at a time.
 1357        // https://tools.ietf.org/html/rfc8259#section-7
 1358        private bool ConsumeStringAndValidate(ReadOnlySpan<byte> data, int idx)
 3261359        {
 3261360            Debug.Assert(idx >= 0 && idx < data.Length);
 3261361            Debug.Assert(data[idx] != JsonConstants.Quote);
 3261362            Debug.Assert(data[idx] == JsonConstants.BackSlash || data[idx] < JsonConstants.Space);
 1363
 3261364            long prevLineBytePosition = _bytePositionInLine;
 3261365            long prevLineNumber = _lineNumber;
 1366
 3261367            _bytePositionInLine += idx + 1; // Add 1 for the first quote
 1368
 3261369            bool nextCharEscaped = false;
 10141370            for (; idx < data.Length; idx++)
 6701371            {
 6701372                byte currentByte = data[idx];
 6701373                if (currentByte == JsonConstants.Quote)
 481374                {
 481375                    if (!nextCharEscaped)
 481376                    {
 481377                        goto Done;
 1378                    }
 01379                    nextCharEscaped = false;
 01380                }
 6221381                else if (currentByte == JsonConstants.BackSlash)
 561382                {
 561383                    nextCharEscaped = !nextCharEscaped;
 561384                }
 5661385                else if (nextCharEscaped)
 561386                {
 561387                    if (!JsonConstants.EscapableChars.Contains(currentByte))
 01388                    {
 01389                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterAfterEscapeWith
 1390                    }
 1391
 561392                    if (currentByte == 'u')
 561393                    {
 1394                        // Expecting 4 hex digits to follow the escaped 'u'
 561395                        _bytePositionInLine++;  // move past the 'u'
 561396                        if (ValidateHexDigits(data, idx + 1))
 561397                        {
 561398                            idx += 4;   // Skip the 4 hex digits, the for loop accounts for idx incrementing past the 'u
 561399                        }
 1400                        else
 01401                        {
 1402                            // We found less than 4 hex digits. Check if there is more data to follow, otherwise throw.
 01403                            idx = data.Length;
 01404                            break;
 1405                        }
 1406
 561407                    }
 561408                    nextCharEscaped = false;
 561409                }
 5101410                else if (currentByte < JsonConstants.Space)
 2781411                {
 2781412                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterWithinString, curre
 1413                }
 1414
 3441415                _bytePositionInLine++;
 3441416            }
 1417
 01418            if (idx >= data.Length)
 01419            {
 01420                if (IsLastSpan)
 01421                {
 01422                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound);
 1423                }
 01424                _lineNumber = prevLineNumber;
 01425                _bytePositionInLine = prevLineBytePosition;
 01426                return false;
 1427            }
 1428
 481429        Done:
 481430            _bytePositionInLine++;  // Add 1 for the end quote
 481431            ValueSpan = data.Slice(0, idx);
 481432            ValueIsEscaped = true;
 481433            _tokenType = JsonTokenType.String;
 481434            _consumed += idx + 2;
 481435            return true;
 481436        }
 1437
 1438        private bool ValidateHexDigits(ReadOnlySpan<byte> data, int idx)
 561439        {
 4481440            for (int j = idx; j < data.Length; j++)
 2241441            {
 2241442                byte nextByte = data[j];
 2241443                if (!JsonReaderHelper.IsHexDigit(nextByte))
 01444                {
 01445                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidHexCharacterWithinString, ne
 1446                }
 2241447                if (j - idx >= 3)
 561448                {
 561449                    return true;
 1450                }
 1681451                _bytePositionInLine++;
 1681452            }
 1453
 01454            return false;
 561455        }
 1456
 1457        // https://tools.ietf.org/html/rfc7159#section-6
 1458        private bool TryGetNumber(ReadOnlySpan<byte> data, out int consumed)
 21621459        {
 1460            // TODO: https://github.com/dotnet/runtime/issues/27837
 21621461            Debug.Assert(data.Length > 0);
 1462
 21621463            consumed = 0;
 21621464            int i = 0;
 1465
 21621466            ConsumeNumberResult signResult = ConsumeNegativeSign(ref data, ref i);
 21121467            if (signResult == ConsumeNumberResult.NeedMoreData)
 01468            {
 01469                return false;
 1470            }
 1471
 21121472            Debug.Assert(signResult == ConsumeNumberResult.OperationIncomplete);
 1473
 21121474            byte nextByte = data[i];
 21121475            Debug.Assert(nextByte is >= (byte)'0' and <= (byte)'9');
 1476
 21121477            if (nextByte == '0')
 10811478            {
 10811479                ConsumeNumberResult result = ConsumeZero(ref data, ref i);
 8861480                if (result == ConsumeNumberResult.NeedMoreData)
 01481                {
 01482                    return false;
 1483                }
 8861484                if (result == ConsumeNumberResult.Success)
 8861485                {
 8861486                    goto Done;
 1487                }
 1488
 01489                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 01490                nextByte = data[i];
 01491            }
 1492            else
 10311493            {
 10311494                i++;
 10311495                ConsumeNumberResult result = ConsumeIntegerDigits(ref data, ref i);
 10311496                if (result == ConsumeNumberResult.NeedMoreData)
 01497                {
 01498                    return false;
 1499                }
 10311500                if (result == ConsumeNumberResult.Success)
 8811501                {
 8811502                    goto Done;
 1503                }
 1504
 1501505                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 1501506                nextByte = data[i];
 1501507                if (nextByte is not ((byte)'.' or (byte)'E' or (byte)'e'))
 1501508                {
 1501509                    _bytePositionInLine += i;
 1501510                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, nextByt
 1511                }
 01512            }
 1513
 01514            Debug.Assert(nextByte is (byte)'.' or (byte)'E' or (byte)'e');
 1515
 01516            if (nextByte == '.')
 01517            {
 01518                i++;
 01519                ConsumeNumberResult result = ConsumeDecimalDigits(ref data, ref i);
 01520                if (result == ConsumeNumberResult.NeedMoreData)
 01521                {
 01522                    return false;
 1523                }
 01524                if (result == ConsumeNumberResult.Success)
 01525                {
 01526                    goto Done;
 1527                }
 1528
 01529                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 01530                nextByte = data[i];
 01531                if (nextByte is not ((byte)'E' or (byte)'e'))
 01532                {
 01533                    _bytePositionInLine += i;
 01534                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedNextDigitEValueNotFound, ne
 1535                }
 01536            }
 1537
 01538            Debug.Assert(nextByte is (byte)'E' or (byte)'e');
 01539            i++;
 1540
 01541            signResult = ConsumeSign(ref data, ref i);
 01542            if (signResult == ConsumeNumberResult.NeedMoreData)
 01543            {
 01544                return false;
 1545            }
 1546
 01547            Debug.Assert(signResult == ConsumeNumberResult.OperationIncomplete);
 1548
 01549            i++;
 01550            ConsumeNumberResult resultExponent = ConsumeIntegerDigits(ref data, ref i);
 01551            if (resultExponent == ConsumeNumberResult.NeedMoreData)
 01552            {
 01553                return false;
 1554            }
 01555            if (resultExponent == ConsumeNumberResult.Success)
 01556            {
 01557                goto Done;
 1558            }
 1559
 01560            Debug.Assert(resultExponent == ConsumeNumberResult.OperationIncomplete);
 1561
 01562            _bytePositionInLine += i;
 01563            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, data[i]);
 1564
 17671565        Done:
 17671566            ValueSpan = data.Slice(0, i);
 17671567            consumed = i;
 17671568            return true;
 17671569        }
 1570
 1571        private ConsumeNumberResult ConsumeNegativeSign(ref ReadOnlySpan<byte> data, scoped ref int i)
 21621572        {
 21621573            byte nextByte = data[i];
 1574
 21621575            if (nextByte == '-')
 501576            {
 501577                i++;
 501578                if (i >= data.Length)
 01579                {
 01580                    if (IsLastSpan)
 01581                    {
 01582                        _bytePositionInLine += i;
 01583                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1584                    }
 01585                    return ConsumeNumberResult.NeedMoreData;
 1586                }
 1587
 501588                nextByte = data[i];
 501589                if (!JsonHelpers.IsDigit(nextByte))
 501590                {
 501591                    _bytePositionInLine += i;
 501592                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nex
 1593                }
 01594            }
 21121595            return ConsumeNumberResult.OperationIncomplete;
 21121596        }
 1597
 1598        private ConsumeNumberResult ConsumeZero(ref ReadOnlySpan<byte> data, scoped ref int i)
 10811599        {
 10811600            Debug.Assert(data[i] == (byte)'0');
 10811601            i++;
 1602            byte nextByte;
 10811603            if (i < data.Length)
 9491604            {
 9491605                nextByte = data[i];
 9491606                if (JsonConstants.Delimiters.Contains(nextByte))
 7541607                {
 7541608                    return ConsumeNumberResult.Success;
 1609                }
 1951610            }
 1611            else
 1321612            {
 1321613                if (IsLastSpan)
 1321614                {
 1615                    // A payload containing a single value: "0" is valid
 1616                    // If we are dealing with multi-value JSON,
 1617                    // ConsumeNumber will validate that we have a delimiter following the "0".
 1321618                    return ConsumeNumberResult.Success;
 1619                }
 1620                else
 01621                {
 01622                    return ConsumeNumberResult.NeedMoreData;
 1623                }
 1624            }
 1951625            nextByte = data[i];
 1951626            if (nextByte is not ((byte)'.' or (byte)'E' or (byte)'e'))
 1951627            {
 1951628                _bytePositionInLine += i;
 1951629                ThrowHelper.ThrowJsonReaderException(ref this,
 1951630                    JsonHelpers.IsInRangeInclusive(nextByte, '0', '9') ? ExceptionResource.InvalidLeadingZeroInNumber : 
 1951631                    nextByte);
 1632            }
 1633
 01634            return ConsumeNumberResult.OperationIncomplete;
 8861635        }
 1636
 1637        private ConsumeNumberResult ConsumeIntegerDigits(ref ReadOnlySpan<byte> data, scoped ref int i)
 10311638        {
 10311639            byte nextByte = default;
 18951640            for (; i < data.Length; i++)
 13451641            {
 13451642                nextByte = data[i];
 13451643                if (!JsonHelpers.IsDigit(nextByte))
 9131644                {
 9131645                    break;
 1646                }
 4321647            }
 10311648            if (i >= data.Length)
 1181649            {
 1181650                if (IsLastSpan)
 1181651                {
 1652                    // A payload containing a single value of integers (e.g. "12") is valid
 1653                    // If we are dealing with multi-value JSON,
 1654                    // ConsumeNumber will validate that we have a delimiter following the integer.
 1181655                    return ConsumeNumberResult.Success;
 1656                }
 1657                else
 01658                {
 01659                    return ConsumeNumberResult.NeedMoreData;
 1660                }
 1661            }
 9131662            if (JsonConstants.Delimiters.Contains(nextByte))
 7631663            {
 7631664                return ConsumeNumberResult.Success;
 1665            }
 1666
 1501667            return ConsumeNumberResult.OperationIncomplete;
 10311668        }
 1669
 1670        private ConsumeNumberResult ConsumeDecimalDigits(ref ReadOnlySpan<byte> data, scoped ref int i)
 01671        {
 01672            if (i >= data.Length)
 01673            {
 01674                if (IsLastSpan)
 01675                {
 01676                    _bytePositionInLine += i;
 01677                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData);
 1678                }
 01679                return ConsumeNumberResult.NeedMoreData;
 1680            }
 01681            byte nextByte = data[i];
 01682            if (!JsonHelpers.IsDigit(nextByte))
 01683            {
 01684                _bytePositionInLine += i;
 01685                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterDecimal, next
 1686            }
 01687            i++;
 1688
 01689            return ConsumeIntegerDigits(ref data, ref i);
 01690        }
 1691
 1692        private ConsumeNumberResult ConsumeSign(ref ReadOnlySpan<byte> data, scoped ref int i)
 01693        {
 01694            if (i >= data.Length)
 01695            {
 01696                if (IsLastSpan)
 01697                {
 01698                    _bytePositionInLine += i;
 01699                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData);
 1700                }
 01701                return ConsumeNumberResult.NeedMoreData;
 1702            }
 1703
 01704            byte nextByte = data[i];
 01705            if (nextByte is (byte)'+' or (byte)'-')
 01706            {
 01707                i++;
 01708                if (i >= data.Length)
 01709                {
 01710                    if (IsLastSpan)
 01711                    {
 01712                        _bytePositionInLine += i;
 01713                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1714                    }
 01715                    return ConsumeNumberResult.NeedMoreData;
 1716                }
 01717                nextByte = data[i];
 01718            }
 1719
 01720            if (!JsonHelpers.IsDigit(nextByte))
 01721            {
 01722                _bytePositionInLine += i;
 01723                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nextByt
 1724            }
 1725
 01726            return ConsumeNumberResult.OperationIncomplete;
 01727        }
 1728
 1729        private bool ConsumeNextTokenOrRollback(byte marker)
 10321730        {
 10321731            int prevConsumed = _consumed;
 10321732            long prevPosition = _bytePositionInLine;
 10321733            long prevLineNumber = _lineNumber;
 10321734            JsonTokenType prevTokenType = _tokenType;
 10321735            bool prevTrailingCommaBeforeComment = _trailingCommaBeforeComment;
 10321736            ConsumeTokenResult result = ConsumeNextToken(marker);
 01737            if (result == ConsumeTokenResult.Success)
 01738            {
 01739                return true;
 1740            }
 01741            if (result == ConsumeTokenResult.NotEnoughDataRollBackState)
 01742            {
 01743                _consumed = prevConsumed;
 01744                _tokenType = prevTokenType;
 01745                _bytePositionInLine = prevPosition;
 01746                _lineNumber = prevLineNumber;
 01747                _trailingCommaBeforeComment = prevTrailingCommaBeforeComment;
 01748            }
 01749            return false;
 01750        }
 1751
 1752        /// <summary>
 1753        /// This method consumes the next token regardless of whether we are inside an object or an array.
 1754        /// For an object, it reads the next property name token. For an array, it just reads the next value.
 1755        /// </summary>
 1756        private ConsumeTokenResult ConsumeNextToken(byte marker)
 10321757        {
 10321758            if (_readerOptions.CommentHandling != JsonCommentHandling.Disallow)
 1401759            {
 1401760                if (_readerOptions.CommentHandling == JsonCommentHandling.Allow)
 01761                {
 01762                    if (marker == JsonConstants.Slash)
 01763                    {
 01764                        return ConsumeComment() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBackS
 1765                    }
 01766                    if (_tokenType == JsonTokenType.Comment)
 01767                    {
 01768                        return ConsumeNextTokenFromLastNonCommentToken();
 1769                    }
 01770                }
 1771                else
 1401772                {
 1401773                    Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Skip);
 1401774                    return ConsumeNextTokenUntilAfterAllCommentsAreSkipped(marker);
 1775                }
 01776            }
 1777
 8921778            if (_bitStack.CurrentDepth == 0)
 8221779            {
 8221780                if (_readerOptions.AllowMultipleValues)
 01781                {
 01782                    return ReadFirstToken(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBac
 1783                }
 1784
 8221785                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, marker);
 1786            }
 1787
 701788            if (marker == JsonConstants.ListSeparator)
 01789            {
 01790                _consumed++;
 01791                _bytePositionInLine++;
 1792
 01793                if (_consumed >= (uint)_buffer.Length)
 01794                {
 01795                    if (IsLastSpan)
 01796                    {
 01797                        _consumed--;
 01798                        _bytePositionInLine--;
 01799                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 1800                    }
 01801                    return ConsumeTokenResult.NotEnoughDataRollBackState;
 1802                }
 01803                byte first = _buffer[_consumed];
 1804
 1805                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01806                if (first <= JsonConstants.Space)
 01807                {
 01808                    SkipWhiteSpace();
 1809                    // The next character must be a start of a property name or value.
 01810                    if (!HasMoreData(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 01811                    {
 01812                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 1813                    }
 01814                    first = _buffer[_consumed];
 01815                }
 1816
 01817                TokenStartIndex = _consumed;
 1818
 01819                if (_readerOptions.CommentHandling == JsonCommentHandling.Allow && first == JsonConstants.Slash)
 01820                {
 01821                    _trailingCommaBeforeComment = true;
 01822                    return ConsumeComment() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBackState
 1823                }
 1824
 01825                if (_inObject)
 01826                {
 01827                    if (first != JsonConstants.Quote)
 01828                    {
 01829                        if (first == JsonConstants.CloseBrace)
 01830                        {
 01831                            if (_readerOptions.AllowTrailingCommas)
 01832                            {
 01833                                EndObject();
 01834                                return ConsumeTokenResult.Success;
 1835                            }
 01836                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 1837                        }
 01838                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 1839                    }
 01840                    return ConsumePropertyName() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBack
 1841                }
 1842                else
 01843                {
 01844                    if (first == JsonConstants.CloseBracket)
 01845                    {
 01846                        if (_readerOptions.AllowTrailingCommas)
 01847                        {
 01848                            EndArray();
 01849                            return ConsumeTokenResult.Success;
 1850                        }
 01851                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 1852                    }
 01853                    return ConsumeValue(first) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBackSt
 1854                }
 1855            }
 701856            else if (marker == JsonConstants.CloseBrace)
 01857            {
 01858                EndObject();
 01859            }
 701860            else if (marker == JsonConstants.CloseBracket)
 01861            {
 01862                EndArray();
 01863            }
 1864            else
 701865            {
 701866                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.FoundInvalidCharacter, marker);
 1867            }
 01868            return ConsumeTokenResult.Success;
 01869        }
 1870
 1871        private ConsumeTokenResult ConsumeNextTokenFromLastNonCommentToken()
 01872        {
 01873            Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Allow);
 01874            Debug.Assert(_tokenType == JsonTokenType.Comment);
 1875
 01876            if (JsonReaderHelper.IsTokenTypePrimitive(_previousTokenType))
 01877            {
 01878                _tokenType = _inObject ? JsonTokenType.StartObject : JsonTokenType.StartArray;
 01879            }
 1880            else
 01881            {
 01882                _tokenType = _previousTokenType;
 01883            }
 1884
 01885            Debug.Assert(_tokenType != JsonTokenType.Comment);
 1886
 01887            if (!HasMoreData())
 01888            {
 01889                goto RollBack;
 1890            }
 1891
 01892            byte first = _buffer[_consumed];
 1893
 1894            // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01895            if (first <= JsonConstants.Space)
 01896            {
 01897                SkipWhiteSpace();
 01898                if (!HasMoreData())
 01899                {
 01900                    goto RollBack;
 1901                }
 01902                first = _buffer[_consumed];
 01903            }
 1904
 01905            if (_bitStack.CurrentDepth == 0 && _tokenType != JsonTokenType.None)
 01906            {
 01907                if (_readerOptions.AllowMultipleValues)
 01908                {
 01909                    return ReadFirstToken(first) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBack
 1910                }
 1911
 01912                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, first);
 1913            }
 1914
 01915            Debug.Assert(first != JsonConstants.Slash);
 1916
 01917            TokenStartIndex = _consumed;
 1918
 01919            if (first == JsonConstants.ListSeparator)
 01920            {
 1921                // A comma without some JSON value preceding it is invalid
 01922                if (_previousTokenType <= JsonTokenType.StartObject || _previousTokenType == JsonTokenType.StartArray ||
 01923                {
 01924                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueAfter
 1925                }
 1926
 01927                _consumed++;
 01928                _bytePositionInLine++;
 1929
 01930                if (_consumed >= (uint)_buffer.Length)
 01931                {
 01932                    if (IsLastSpan)
 01933                    {
 01934                        _consumed--;
 01935                        _bytePositionInLine--;
 01936                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 1937                    }
 01938                    goto RollBack;
 1939                }
 01940                first = _buffer[_consumed];
 1941
 1942                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01943                if (first <= JsonConstants.Space)
 01944                {
 01945                    SkipWhiteSpace();
 1946                    // The next character must be a start of a property name or value.
 01947                    if (!HasMoreData(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 01948                    {
 01949                        goto RollBack;
 1950                    }
 01951                    first = _buffer[_consumed];
 01952                }
 1953
 01954                TokenStartIndex = _consumed;
 1955
 01956                if (first == JsonConstants.Slash)
 01957                {
 01958                    _trailingCommaBeforeComment = true;
 01959                    if (ConsumeComment())
 01960                    {
 01961                        goto Done;
 1962                    }
 1963                    else
 01964                    {
 01965                        goto RollBack;
 1966                    }
 1967                }
 1968
 01969                if (_inObject)
 01970                {
 01971                    if (first != JsonConstants.Quote)
 01972                    {
 01973                        if (first == JsonConstants.CloseBrace)
 01974                        {
 01975                            if (_readerOptions.AllowTrailingCommas)
 01976                            {
 01977                                EndObject();
 01978                                goto Done;
 1979                            }
 01980                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 1981                        }
 1982
 01983                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 1984                    }
 01985                    if (ConsumePropertyName())
 01986                    {
 01987                        goto Done;
 1988                    }
 1989                    else
 01990                    {
 01991                        goto RollBack;
 1992                    }
 1993                }
 1994                else
 01995                {
 01996                    if (first == JsonConstants.CloseBracket)
 01997                    {
 01998                        if (_readerOptions.AllowTrailingCommas)
 01999                        {
 02000                            EndArray();
 02001                            goto Done;
 2002                        }
 02003                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 2004                    }
 2005
 02006                    if (ConsumeValue(first))
 02007                    {
 02008                        goto Done;
 2009                    }
 2010                    else
 02011                    {
 02012                        goto RollBack;
 2013                    }
 2014                }
 2015            }
 02016            else if (first == JsonConstants.CloseBrace)
 02017            {
 02018                EndObject();
 02019            }
 02020            else if (first == JsonConstants.CloseBracket)
 02021            {
 02022                EndArray();
 02023            }
 02024            else if (_tokenType == JsonTokenType.None)
 02025            {
 02026                if (ReadFirstToken(first))
 02027                {
 02028                    goto Done;
 2029                }
 2030                else
 02031                {
 02032                    goto RollBack;
 2033                }
 2034            }
 02035            else if (_tokenType == JsonTokenType.StartObject)
 02036            {
 02037                Debug.Assert(first != JsonConstants.CloseBrace);
 02038                if (first != JsonConstants.Quote)
 02039                {
 02040                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound, fi
 2041                }
 2042
 02043                int prevConsumed = _consumed;
 02044                long prevPosition = _bytePositionInLine;
 02045                long prevLineNumber = _lineNumber;
 02046                if (!ConsumePropertyName())
 02047                {
 2048                    // roll back potential changes
 02049                    _consumed = prevConsumed;
 02050                    _tokenType = JsonTokenType.StartObject;
 02051                    _bytePositionInLine = prevPosition;
 02052                    _lineNumber = prevLineNumber;
 02053                    goto RollBack;
 2054                }
 02055                goto Done;
 2056            }
 02057            else if (_tokenType == JsonTokenType.StartArray)
 02058            {
 02059                Debug.Assert(first != JsonConstants.CloseBracket);
 02060                if (!ConsumeValue(first))
 02061                {
 02062                    goto RollBack;
 2063                }
 02064                goto Done;
 2065            }
 02066            else if (_tokenType == JsonTokenType.PropertyName)
 02067            {
 02068                if (!ConsumeValue(first))
 02069                {
 02070                    goto RollBack;
 2071                }
 02072                goto Done;
 2073            }
 2074            else
 02075            {
 02076                Debug.Assert(_tokenType is JsonTokenType.EndArray or JsonTokenType.EndObject);
 02077                if (_inObject)
 02078                {
 02079                    Debug.Assert(first != JsonConstants.CloseBrace);
 02080                    if (first != JsonConstants.Quote)
 02081                    {
 02082                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 2083                    }
 2084
 02085                    if (ConsumePropertyName())
 02086                    {
 02087                        goto Done;
 2088                    }
 2089                    else
 02090                    {
 02091                        goto RollBack;
 2092                    }
 2093                }
 2094                else
 02095                {
 02096                    Debug.Assert(first != JsonConstants.CloseBracket);
 2097
 02098                    if (ConsumeValue(first))
 02099                    {
 02100                        goto Done;
 2101                    }
 2102                    else
 02103                    {
 02104                        goto RollBack;
 2105                    }
 2106                }
 2107            }
 2108
 02109        Done:
 02110            return ConsumeTokenResult.Success;
 2111
 02112        RollBack:
 02113            return ConsumeTokenResult.NotEnoughDataRollBackState;
 02114        }
 2115
 2116        private bool SkipAllComments(scoped ref byte marker)
 1402117        {
 1402118            while (marker == JsonConstants.Slash)
 62119            {
 62120                if (SkipComment())
 02121                {
 02122                    if (!HasMoreData())
 02123                    {
 02124                        goto IncompleteNoRollback;
 2125                    }
 2126
 02127                    marker = _buffer[_consumed];
 2128
 2129                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 02130                    if (marker <= JsonConstants.Space)
 02131                    {
 02132                        SkipWhiteSpace();
 02133                        if (!HasMoreData())
 02134                        {
 02135                            goto IncompleteNoRollback;
 2136                        }
 02137                        marker = _buffer[_consumed];
 02138                    }
 02139                }
 2140                else
 02141                {
 02142                    goto IncompleteNoRollback;
 2143                }
 02144            }
 1342145            return true;
 2146
 02147        IncompleteNoRollback:
 02148            return false;
 1342149        }
 2150
 2151        private bool SkipAllComments(scoped ref byte marker, ExceptionResource resource)
 02152        {
 02153            while (marker == JsonConstants.Slash)
 02154            {
 02155                if (SkipComment())
 02156                {
 2157                    // The next character must be a start of a property name or value.
 02158                    if (!HasMoreData(resource))
 02159                    {
 02160                        goto IncompleteRollback;
 2161                    }
 2162
 02163                    marker = _buffer[_consumed];
 2164
 2165                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 02166                    if (marker <= JsonConstants.Space)
 02167                    {
 02168                        SkipWhiteSpace();
 2169                        // The next character must be a start of a property name or value.
 02170                        if (!HasMoreData(resource))
 02171                        {
 02172                            goto IncompleteRollback;
 2173                        }
 02174                        marker = _buffer[_consumed];
 02175                    }
 02176                }
 2177                else
 02178                {
 02179                    goto IncompleteRollback;
 2180                }
 02181            }
 02182            return true;
 2183
 02184        IncompleteRollback:
 02185            return false;
 02186        }
 2187
 2188        private ConsumeTokenResult ConsumeNextTokenUntilAfterAllCommentsAreSkipped(byte marker)
 1402189        {
 1402190            if (!SkipAllComments(ref marker))
 02191            {
 02192                goto IncompleteNoRollback;
 2193            }
 2194
 1342195            TokenStartIndex = _consumed;
 2196
 1342197            if (_tokenType == JsonTokenType.StartObject)
 02198            {
 02199                if (marker == JsonConstants.CloseBrace)
 02200                {
 02201                    EndObject();
 02202                }
 2203                else
 02204                {
 02205                    if (marker != JsonConstants.Quote)
 02206                    {
 02207                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 2208                    }
 2209
 02210                    int prevConsumed = _consumed;
 02211                    long prevPosition = _bytePositionInLine;
 02212                    long prevLineNumber = _lineNumber;
 02213                    if (!ConsumePropertyName())
 02214                    {
 2215                        // roll back potential changes
 02216                        _consumed = prevConsumed;
 02217                        _tokenType = JsonTokenType.StartObject;
 02218                        _bytePositionInLine = prevPosition;
 02219                        _lineNumber = prevLineNumber;
 02220                        goto IncompleteNoRollback;
 2221                    }
 02222                    goto Done;
 2223                }
 02224            }
 1342225            else if (_tokenType == JsonTokenType.StartArray)
 02226            {
 02227                if (marker == JsonConstants.CloseBracket)
 02228                {
 02229                    EndArray();
 02230                }
 2231                else
 02232                {
 02233                    if (!ConsumeValue(marker))
 02234                    {
 02235                        goto IncompleteNoRollback;
 2236                    }
 02237                    goto Done;
 2238                }
 02239            }
 1342240            else if (_tokenType == JsonTokenType.PropertyName)
 02241            {
 02242                if (!ConsumeValue(marker))
 02243                {
 02244                    goto IncompleteNoRollback;
 2245                }
 02246                goto Done;
 2247            }
 1342248            else if (_bitStack.CurrentDepth == 0)
 1162249            {
 1162250                if (_readerOptions.AllowMultipleValues)
 02251                {
 02252                    return ReadFirstToken(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBac
 2253                }
 2254
 1162255                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, marker);
 2256            }
 182257            else if (marker == JsonConstants.ListSeparator)
 02258            {
 02259                _consumed++;
 02260                _bytePositionInLine++;
 2261
 02262                if (_consumed >= (uint)_buffer.Length)
 02263                {
 02264                    if (IsLastSpan)
 02265                    {
 02266                        _consumed--;
 02267                        _bytePositionInLine--;
 02268                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 2269                    }
 02270                    return ConsumeTokenResult.NotEnoughDataRollBackState;
 2271                }
 02272                marker = _buffer[_consumed];
 2273
 2274                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 02275                if (marker <= JsonConstants.Space)
 02276                {
 02277                    SkipWhiteSpace();
 2278                    // The next character must be a start of a property name or value.
 02279                    if (!HasMoreData(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 02280                    {
 02281                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 2282                    }
 02283                    marker = _buffer[_consumed];
 02284                }
 2285
 02286                if (!SkipAllComments(ref marker, ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 02287                {
 02288                    goto IncompleteRollback;
 2289                }
 2290
 02291                TokenStartIndex = _consumed;
 2292
 02293                if (_inObject)
 02294                {
 02295                    if (marker != JsonConstants.Quote)
 02296                    {
 02297                        if (marker == JsonConstants.CloseBrace)
 02298                        {
 02299                            if (_readerOptions.AllowTrailingCommas)
 02300                            {
 02301                                EndObject();
 02302                                goto Done;
 2303                            }
 02304                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 2305                        }
 2306
 02307                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 2308                    }
 02309                    return ConsumePropertyName() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBack
 2310                }
 2311                else
 02312                {
 02313                    if (marker == JsonConstants.CloseBracket)
 02314                    {
 02315                        if (_readerOptions.AllowTrailingCommas)
 02316                        {
 02317                            EndArray();
 02318                            goto Done;
 2319                        }
 02320                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 2321                    }
 2322
 02323                    return ConsumeValue(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBackS
 2324                }
 2325            }
 182326            else if (marker == JsonConstants.CloseBrace)
 02327            {
 02328                EndObject();
 02329            }
 182330            else if (marker == JsonConstants.CloseBracket)
 02331            {
 02332                EndArray();
 02333            }
 2334            else
 182335            {
 182336                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.FoundInvalidCharacter, marker);
 2337            }
 2338
 02339        Done:
 02340            return ConsumeTokenResult.Success;
 02341        IncompleteNoRollback:
 02342            return ConsumeTokenResult.IncompleteNoRollBackNecessary;
 02343        IncompleteRollback:
 02344            return ConsumeTokenResult.NotEnoughDataRollBackState;
 02345        }
 2346
 2347        private bool SkipComment()
 882348        {
 2349            // Create local copy to avoid bounds checks.
 882350            ReadOnlySpan<byte> localBuffer = _buffer.Slice(_consumed + 1);
 2351
 882352            if (localBuffer.Length > 0)
 882353            {
 882354                byte marker = localBuffer[0];
 882355                if (marker == JsonConstants.Slash)
 02356                {
 02357                    return SkipSingleLineComment(localBuffer.Slice(1), out _);
 2358                }
 882359                else if (marker == JsonConstants.Asterisk)
 02360                {
 02361                    return SkipMultiLineComment(localBuffer.Slice(1), out _);
 2362                }
 2363                else
 882364                {
 882365                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfValueNotFound, JsonC
 2366                }
 2367            }
 2368
 02369            if (IsLastSpan)
 02370            {
 02371                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfValueNotFound, JsonConst
 2372            }
 02373            return false;
 02374        }
 2375
 2376        private bool SkipSingleLineComment(ReadOnlySpan<byte> localBuffer, out int idx)
 02377        {
 02378            idx = FindLineSeparator(localBuffer);
 2379            int toConsume;
 02380            if (idx != -1)
 02381            {
 02382                toConsume = idx;
 02383                if (localBuffer[idx] == JsonConstants.LineFeed)
 02384                {
 02385                    goto EndOfComment;
 2386                }
 2387
 2388                // If we are here, we have definintely found a \r. So now to check if \n follows.
 02389                Debug.Assert(localBuffer[idx] == JsonConstants.CarriageReturn);
 2390
 02391                if (idx < localBuffer.Length - 1)
 02392                {
 02393                    if (localBuffer[idx + 1] == JsonConstants.LineFeed)
 02394                    {
 02395                        toConsume++;
 02396                    }
 2397
 02398                    goto EndOfComment;
 2399                }
 2400
 02401                if (IsLastSpan)
 02402                {
 02403                    goto EndOfComment;
 2404                }
 2405                else
 02406                {
 2407                    // there might be LF in the next segment
 02408                    return false;
 2409                }
 2410            }
 2411
 02412            if (IsLastSpan)
 02413            {
 02414                idx = localBuffer.Length;
 02415                toConsume = idx;
 2416                // Assume everything on this line is a comment and there is no more data.
 02417                _bytePositionInLine += 2 + localBuffer.Length;
 02418                goto Done;
 2419            }
 2420            else
 02421            {
 02422                return false;
 2423            }
 2424
 02425        EndOfComment:
 02426            toConsume++;
 02427            _bytePositionInLine = 0;
 02428            _lineNumber++;
 2429
 02430        Done:
 02431            _consumed += 2 + toConsume;
 02432            return true;
 02433        }
 2434
 2435        private int FindLineSeparator(ReadOnlySpan<byte> localBuffer)
 02436        {
 02437            int totalIdx = 0;
 02438            while (true)
 02439            {
 02440                int idx = localBuffer.IndexOfAny(JsonConstants.LineFeed, JsonConstants.CarriageReturn, JsonConstants.Sta
 2441
 02442                if (idx == -1)
 02443                {
 02444                    return -1;
 2445                }
 2446
 02447                totalIdx += idx;
 2448
 02449                if (localBuffer[idx] != JsonConstants.StartingByteOfNonStandardSeparator)
 02450                {
 02451                    return totalIdx;
 2452                }
 2453
 02454                totalIdx++;
 02455                localBuffer = localBuffer.Slice(idx + 1);
 2456
 02457                ThrowOnDangerousLineSeparator(localBuffer);
 02458            }
 02459        }
 2460
 2461        // assumes first byte (JsonConstants.StartingByteOfNonStandardSeparator) is already read
 2462        private void ThrowOnDangerousLineSeparator(ReadOnlySpan<byte> localBuffer)
 02463        {
 2464            // \u2028 and \u2029 are considered respectively line and paragraph separators
 2465            // UTF-8 representation for them is E2, 80, A8/A9
 2466            // we have already read E2, we need to check for remaining 2 bytes
 2467
 02468            if (localBuffer.Length < 2)
 02469            {
 02470                return;
 2471            }
 2472
 02473            byte next = localBuffer[1];
 02474            if (localBuffer[0] == 0x80 && (next is 0xA8 or 0xA9))
 02475            {
 02476                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfLineSeparator);
 2477            }
 02478        }
 2479
 2480        private bool SkipMultiLineComment(ReadOnlySpan<byte> localBuffer, out int idx)
 02481        {
 02482            idx = 0;
 02483            while (true)
 02484            {
 02485                int foundIdx = localBuffer.Slice(idx).IndexOf(JsonConstants.Slash);
 02486                if (foundIdx == -1)
 02487                {
 02488                    if (IsLastSpan)
 02489                    {
 02490                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfCommentNotFound);
 2491                    }
 02492                    return false;
 2493                }
 02494                if (foundIdx != 0 && localBuffer[foundIdx + idx - 1] == JsonConstants.Asterisk)
 02495                {
 2496                    // foundIdx points just after '*' in the end-of-comment delimiter. Hence increment idx by one
 2497                    // position less to make it point right before beginning of end-of-comment delimiter i.e. */
 02498                    idx += foundIdx - 1;
 02499                    break;
 2500                }
 02501                idx += foundIdx + 1;
 02502            }
 2503
 2504            // Consume the /* and */ characters that are part of the multi-line comment.
 2505            // idx points right before the final '*' (which is right before the last '/'). Hence increment _consumed
 2506            // by 4 to exclude the start/end-of-comment delimiters.
 02507            _consumed += 4 + idx;
 2508
 02509            (int newLines, int newLineIndex) = JsonReaderHelper.CountNewLines(localBuffer.Slice(0, idx));
 02510            _lineNumber += newLines;
 02511            if (newLineIndex != -1)
 02512            {
 2513                // newLineIndex points at last newline character and byte positions in the new line start
 2514                // after that. Hence add 1 to skip the newline character.
 02515                _bytePositionInLine = idx - newLineIndex + 1;
 02516            }
 2517            else
 02518            {
 02519                _bytePositionInLine += 4 + idx;
 02520            }
 02521            return true;
 02522        }
 2523
 2524        private bool ConsumeComment()
 02525        {
 2526            // Create local copy to avoid bounds checks.
 02527            ReadOnlySpan<byte> localBuffer = _buffer.Slice(_consumed + 1);
 2528
 02529            if (localBuffer.Length > 0)
 02530            {
 02531                byte marker = localBuffer[0];
 02532                if (marker == JsonConstants.Slash)
 02533                {
 02534                    return ConsumeSingleLineComment(localBuffer.Slice(1), _consumed);
 2535                }
 02536                else if (marker == JsonConstants.Asterisk)
 02537                {
 02538                    return ConsumeMultiLineComment(localBuffer.Slice(1), _consumed);
 2539                }
 2540                else
 02541                {
 02542                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterAtStartOfComment, m
 2543                }
 2544            }
 2545
 02546            if (IsLastSpan)
 02547            {
 02548                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileReadingComment)
 2549            }
 02550            return false;
 02551        }
 2552
 2553        private bool ConsumeSingleLineComment(ReadOnlySpan<byte> localBuffer, int previousConsumed)
 02554        {
 02555            if (!SkipSingleLineComment(localBuffer, out int idx))
 02556            {
 02557                return false;
 2558            }
 2559
 2560            // Exclude the // at start of the comment. idx points right before the line separator
 2561            // at the end of the comment.
 02562            ValueSpan = _buffer.Slice(previousConsumed + 2, idx);
 02563            if (_tokenType != JsonTokenType.Comment)
 02564            {
 02565                _previousTokenType = _tokenType;
 02566            }
 02567            _tokenType = JsonTokenType.Comment;
 02568            return true;
 02569        }
 2570
 2571        private bool ConsumeMultiLineComment(ReadOnlySpan<byte> localBuffer, int previousConsumed)
 02572        {
 02573            if (!SkipMultiLineComment(localBuffer, out int idx))
 02574            {
 02575                return false;
 2576            }
 2577
 2578            // Exclude the /* at start of the comment. idx already points right before the terminal '*/'
 2579            // for the end of multiline comment.
 02580            ValueSpan = _buffer.Slice(previousConsumed + 2, idx);
 02581            if (_tokenType != JsonTokenType.Comment)
 02582            {
 02583                _previousTokenType = _tokenType;
 02584            }
 02585            _tokenType = JsonTokenType.Comment;
 02586            return true;
 02587        }
 2588
 2589        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 02590        private string DebuggerDisplay => $"TokenType = {DebugTokenType}, TokenStartIndex = {TokenStartIndex}, Consumed 
 2591
 2592        // Using TokenType.ToString() (or {TokenType}) fails to render in the debug window. The
 2593        // message "The runtime refused to evaluate the expression at this time." is shown. This
 2594        // is a workaround until we root cause and fix the issue.
 2595        private string DebugTokenType
 02596            => TokenType switch
 02597            {
 02598                JsonTokenType.Comment => nameof(JsonTokenType.Comment),
 02599                JsonTokenType.EndArray => nameof(JsonTokenType.EndArray),
 02600                JsonTokenType.EndObject => nameof(JsonTokenType.EndObject),
 02601                JsonTokenType.False => nameof(JsonTokenType.False),
 02602                JsonTokenType.None => nameof(JsonTokenType.None),
 02603                JsonTokenType.Null => nameof(JsonTokenType.Null),
 02604                JsonTokenType.Number => nameof(JsonTokenType.Number),
 02605                JsonTokenType.PropertyName => nameof(JsonTokenType.PropertyName),
 02606                JsonTokenType.StartArray => nameof(JsonTokenType.StartArray),
 02607                JsonTokenType.StartObject => nameof(JsonTokenType.StartObject),
 02608                JsonTokenType.String => nameof(JsonTokenType.String),
 02609                JsonTokenType.True => nameof(JsonTokenType.True),
 02610                _ => ((byte)TokenType).ToString()
 02611            };
 2612
 2613        private ReadOnlySpan<byte> GetUnescapedSpan()
 6062614        {
 6062615            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 6062616            if (ValueIsEscaped)
 02617            {
 02618                span = JsonReaderHelper.GetUnescaped(span);
 02619            }
 2620
 6062621            return span;
 6062622        }
 2623    }
 2624}

D:\runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Reader\Utf8JsonReader.MultiSegment.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Buffers;
 5using System.Diagnostics;
 6using System.Runtime.CompilerServices;
 7
 8namespace System.Text.Json
 9{
 10    public ref partial struct Utf8JsonReader
 11    {
 12        /// <summary>
 13        /// Constructs a new <see cref="Utf8JsonReader"/> instance.
 14        /// </summary>
 15        /// <param name="jsonData">The ReadOnlySequence&lt;byte&gt; containing the UTF-8 encoded JSON text to process.</
 16        /// <param name="isFinalBlock">True when the input span contains the entire data to process.
 17        /// Set to false only if it is known that the input span contains partial data with more data to follow.</param>
 18        /// <param name="state">If this is the first call to the ctor, pass in a default state. Otherwise,
 19        /// capture the state from the previous instance of the <see cref="Utf8JsonReader"/> and pass that back.</param>
 20        /// <remarks>
 21        /// Since this type is a ref struct, it is a stack-only type and all the limitations of ref structs apply to it.
 22        /// This is the reason why the ctor accepts a <see cref="JsonReaderState"/>.
 23        /// </remarks>
 24        public Utf8JsonReader(ReadOnlySequence<byte> jsonData, bool isFinalBlock, JsonReaderState state)
 1780825        {
 1780826            _buffer = jsonData.FirstSpan;
 27
 1780828            _isFinalBlock = isFinalBlock;
 1780829            _isInputSequence = true;
 30
 1780831            _lineNumber = state._lineNumber;
 1780832            _bytePositionInLine = state._bytePositionInLine;
 1780833            _inObject = state._inObject;
 1780834            _isNotPrimitive = state._isNotPrimitive;
 1780835            ValueIsEscaped = state._valueIsEscaped;
 1780836            _trailingCommaBeforeComment = state._trailingCommaBeforeComment;
 1780837            _tokenType = state._tokenType;
 1780838            _previousTokenType = state._previousTokenType;
 1780839            _readerOptions = state._readerOptions;
 1780840            if (_readerOptions.MaxDepth == 0)
 42441            {
 42442                _readerOptions.MaxDepth = JsonReaderOptions.DefaultMaxDepth;  // If max depth is not set, revert to the 
 42443            }
 1780844            _bitStack = state._bitStack;
 45
 1780846            _consumed = 0;
 1780847            TokenStartIndex = 0;
 1780848            _totalConsumed = 0;
 49
 1780850            ValueSpan = ReadOnlySpan<byte>.Empty;
 51
 1780852            _sequence = jsonData;
 1780853            HasValueSequence = false;
 1780854            ValueSequence = ReadOnlySequence<byte>.Empty;
 55
 1780856            if (jsonData.IsSingleSegment)
 057            {
 058                _nextPosition = default;
 059                _currentPosition = jsonData.Start;
 060                _isLastSegment = isFinalBlock;
 061                _isMultiSegment = false;
 062            }
 63            else
 1780864            {
 1780865                _currentPosition = jsonData.Start;
 1780866                _nextPosition = _currentPosition;
 67
 1780868                bool firstSegmentIsEmpty = _buffer.Length == 0;
 1780869                if (firstSegmentIsEmpty)
 070                {
 71                    // Once we find a non-empty segment, we need to set current position to it.
 72                    // Therefore, track the next position in a copy before it gets advanced to the next segment.
 073                    SequencePosition previousNextPosition = _nextPosition;
 074                    while (jsonData.TryGet(ref _nextPosition, out ReadOnlyMemory<byte> memory, advance: true))
 075                    {
 76                        // _currentPosition should point to the segment right befor the segment that _nextPosition point
 077                        _currentPosition = previousNextPosition;
 078                        if (memory.Length != 0)
 079                        {
 080                            _buffer = memory.Span;
 081                            break;
 82                        }
 083                        previousNextPosition = _nextPosition;
 084                    }
 085                }
 86
 87                // If firstSegmentIsEmpty is true,
 88                //    only check if we have reached the last segment but do not advance _nextPosition. The while loop ab
 89                //    Otherwise, we would end up skipping a segment (i.e. advance = false).
 90                // If firstSegmentIsEmpty is false,
 91                //    make sure to advance _nextPosition so that it is no longer the same as _currentPosition (i.e. adva
 1780892                _isLastSegment = !jsonData.TryGet(ref _nextPosition, out _, advance: !firstSegmentIsEmpty) && isFinalBlo
 93
 1780894                Debug.Assert(!_nextPosition.Equals(_currentPosition));
 95
 1780896                _isMultiSegment = true;
 1780897            }
 1780898        }
 99
 100        /// <summary>
 101        /// Constructs a new <see cref="Utf8JsonReader"/> instance.
 102        /// </summary>
 103        /// <param name="jsonData">The ReadOnlySequence&lt;byte&gt; containing the UTF-8 encoded JSON text to process.</
 104        /// <param name="options">Defines the customized behavior of the <see cref="Utf8JsonReader"/>
 105        /// that is different from the JSON RFC (for example how to handle comments or maximum depth allowed when readin
 106        /// By default, the <see cref="Utf8JsonReader"/> follows the JSON RFC strictly (i.e. comments within the JSON ar
 107        /// <remarks>
 108        ///   <para>
 109        ///     Since this type is a ref struct, it is a stack-only type and all the limitations of ref structs apply to
 110        ///   </para>
 111        ///   <para>
 112        ///     This assumes that the entire JSON payload is passed in (equivalent to <see cref="IsFinalBlock"/> = true)
 113        ///   </para>
 114        /// </remarks>
 115        public Utf8JsonReader(ReadOnlySequence<byte> jsonData, JsonReaderOptions options = default)
 0116            : this(jsonData, isFinalBlock: true, new JsonReaderState(options))
 0117        {
 0118        }
 119
 120        private bool ReadMultiSegment()
 20249121        {
 20249122            bool retVal = false;
 20249123            HasValueSequence = false;
 20249124            ValueIsEscaped = false;
 20249125            ValueSpan = default;
 20249126            ValueSequence = default;
 127
 20249128            if (!HasMoreDataMultiSegment())
 26129            {
 26130                goto Done;
 131            }
 132
 20223133            byte first = _buffer[_consumed];
 134
 135            // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 136            // SkipWhiteSpace only skips the whitespace characters as defined by JSON RFC 8259 section 2.
 137            // We do not validate if 'first' is an invalid JSON byte here (such as control characters).
 138            // Those cases are captured in ConsumeNextToken and ConsumeValue.
 20223139            if (first <= JsonConstants.Space)
 11836140            {
 11836141                SkipWhiteSpaceMultiSegment();
 11836142                if (!HasMoreDataMultiSegment())
 489143                {
 489144                    goto Done;
 145                }
 11294146                first = _buffer[_consumed];
 11294147            }
 148
 19681149            TokenStartIndex = BytesConsumed;
 150
 19681151            if (_tokenType == JsonTokenType.None)
 17640152            {
 17640153                goto ReadFirstToken;
 154            }
 155
 2041156            if (first == JsonConstants.Slash)
 7157            {
 7158                retVal = ConsumeNextTokenOrRollbackMultiSegment(first);
 0159                goto Done;
 160            }
 161
 2034162            if (_tokenType == JsonTokenType.StartObject)
 58163            {
 58164                if (first == JsonConstants.CloseBrace)
 0165                {
 0166                    EndObject();
 0167                }
 168                else
 58169                {
 58170                    if (first != JsonConstants.Quote)
 58171                    {
 58172                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 173                    }
 174
 0175                    long prevTotalConsumed = _totalConsumed;
 0176                    int prevConsumed = _consumed;
 0177                    long prevPosition = _bytePositionInLine;
 0178                    long prevLineNumber = _lineNumber;
 0179                    SequencePosition copy = _currentPosition;
 0180                    retVal = ConsumePropertyNameMultiSegment();
 0181                    if (!retVal)
 0182                    {
 183                        // roll back potential changes
 0184                        _consumed = prevConsumed;
 0185                        _tokenType = JsonTokenType.StartObject;
 0186                        _bytePositionInLine = prevPosition;
 0187                        _lineNumber = prevLineNumber;
 0188                        _totalConsumed = prevTotalConsumed;
 0189                        _currentPosition = copy;
 0190                    }
 0191                    goto Done;
 192                }
 0193            }
 1976194            else if (_tokenType == JsonTokenType.StartArray)
 951195            {
 951196                if (first == JsonConstants.CloseBracket)
 0197                {
 0198                    EndArray();
 0199                }
 200                else
 951201                {
 951202                    retVal = ConsumeValueMultiSegment(first);
 353203                    goto Done;
 204                }
 0205            }
 1025206            else if (_tokenType == JsonTokenType.PropertyName)
 0207            {
 0208                retVal = ConsumeValueMultiSegment(first);
 0209                goto Done;
 210            }
 211            else
 1025212            {
 1025213                retVal = ConsumeNextTokenOrRollbackMultiSegment(first);
 0214                goto Done;
 215            }
 216
 0217            retVal = true;
 218
 8764219        Done:
 8764220            return retVal;
 221
 17640222        ReadFirstToken:
 17640223            retVal = ReadFirstTokenMultiSegment(first);
 7896224            goto Done;
 8764225        }
 226
 227        private bool ValidateStateAtEndOfData()
 53228        {
 53229            Debug.Assert(_isNotPrimitive && IsLastSpan);
 230
 53231            if (_bitStack.CurrentDepth != 0)
 53232            {
 53233                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ZeroDepthAtEnd);
 234            }
 235
 0236            if (_readerOptions.CommentHandling == JsonCommentHandling.Allow && _tokenType == JsonTokenType.Comment)
 0237            {
 0238                return false;
 239            }
 240
 0241            if (_tokenType != JsonTokenType.EndArray && _tokenType != JsonTokenType.EndObject)
 0242            {
 0243                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidEndOfJsonNonPrimitive);
 244            }
 245
 0246            return true;
 0247        }
 248
 249        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 250        private bool HasMoreDataMultiSegment()
 32085251        {
 32085252            if (_consumed >= (uint)_buffer.Length)
 749253            {
 749254                if (_isNotPrimitive && IsLastSpan)
 53255                {
 53256                    if (!ValidateStateAtEndOfData())
 0257                    {
 0258                        return false;
 259                    }
 0260                }
 261
 696262                if (!GetNextSpan())
 515263                {
 515264                    if (_isNotPrimitive && IsLastSpan)
 0265                    {
 0266                        ValidateStateAtEndOfData();
 0267                    }
 515268                    return false;
 269                }
 181270            }
 31517271            return true;
 32032272        }
 273
 274        // Unlike the parameter-less overload of HasMoreData, if there is no more data when this method is called, we kn
 275        // This is because, this method is only called after a ',' (i.e. we expect a value/property name) or after
 276        // a property name, which means it must be followed by a value.
 277        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 278        private bool HasMoreDataMultiSegment(ExceptionResource resource)
 0279        {
 0280            if (_consumed >= (uint)_buffer.Length)
 0281            {
 0282                if (IsLastSpan)
 0283                {
 0284                    ThrowHelper.ThrowJsonReaderException(ref this, resource);
 285                }
 0286                if (!GetNextSpan())
 0287                {
 0288                    if (IsLastSpan)
 0289                    {
 0290                        ThrowHelper.ThrowJsonReaderException(ref this, resource);
 291                    }
 0292                    return false;
 293                }
 0294            }
 0295            return true;
 0296        }
 297
 298        private bool GetNextSpan()
 10408299        {
 300            ReadOnlyMemory<byte> memory;
 10408301            while (true)
 10408302            {
 10408303                Debug.Assert(!_isMultiSegment || _currentPosition.GetObject() is not null);
 10408304                SequencePosition copy = _currentPosition;
 10408305                _currentPosition = _nextPosition;
 10408306                bool noMoreData = !_sequence.TryGet(ref _nextPosition, out memory, advance: true);
 10408307                if (noMoreData)
 1233308                {
 1233309                    _currentPosition = copy;
 1233310                    _isLastSegment = true;
 1233311                    return false;
 312                }
 9175313                if (memory.Length != 0)
 9175314                {
 9175315                    break;
 316                }
 317                // _currentPosition needs to point to last non-empty segment
 318                // Since memory.Length == 0, we need to revert back to previous.
 0319                _currentPosition = copy;
 0320                Debug.Assert(!_isMultiSegment || _currentPosition.GetObject() is not null);
 0321            }
 322
 9175323            if (_isFinalBlock)
 9175324            {
 9175325                _isLastSegment = !_sequence.TryGet(ref _nextPosition, out _, advance: false);
 9175326            }
 327
 9175328            _buffer = memory.Span;
 9175329            _totalConsumed += _consumed;
 9175330            _consumed = 0;
 331
 9175332            return true;
 10408333        }
 334
 335        private bool ReadFirstTokenMultiSegment(byte first)
 17640336        {
 17640337            if (first == JsonConstants.OpenBrace)
 252338            {
 252339                _bitStack.SetFirstBit();
 252340                _tokenType = JsonTokenType.StartObject;
 252341                ValueSpan = _buffer.Slice(_consumed, 1);
 252342                _consumed++;
 252343                _bytePositionInLine++;
 252344                _inObject = true;
 252345                _isNotPrimitive = true;
 252346            }
 17388347            else if (first == JsonConstants.OpenBracket)
 3990348            {
 3990349                _bitStack.ResetFirstBit();
 3990350                _tokenType = JsonTokenType.StartArray;
 3990351                ValueSpan = _buffer.Slice(_consumed, 1);
 3990352                _consumed++;
 3990353                _bytePositionInLine++;
 3990354                _isNotPrimitive = true;
 3990355            }
 356            else
 13398357            {
 13398358                if (JsonHelpers.IsDigit(first) || first == '-')
 1764359                {
 1764360                    if (!TryGetNumberMultiSegment(_buffer.Slice(_consumed), out int numberOfBytes))
 0361                    {
 0362                        return false;
 363                    }
 1428364                    _tokenType = JsonTokenType.Number;
 1428365                    _consumed += numberOfBytes;
 1428366                }
 11634367                else if (!ConsumeValueMultiSegment(first))
 0368                {
 0369                    return false;
 370                }
 371
 3654372                _isNotPrimitive = _tokenType is JsonTokenType.StartObject or JsonTokenType.StartArray;
 373                // Intentionally fall out of the if-block to return true
 3654374            }
 7896375            return true;
 7896376        }
 377
 378        private void SkipWhiteSpaceMultiSegment()
 11836379        {
 18137380            while (true)
 18137381            {
 18137382                SkipWhiteSpace();
 383
 18137384                if (_consumed < _buffer.Length)
 11294385                {
 11294386                    break;
 387                }
 388
 6843389                if (!GetNextSpan())
 542390                {
 542391                    break;
 392                }
 6301393            }
 11836394        }
 395
 396        /// <summary>
 397        /// This method contains the logic for processing the next value token and determining
 398        /// what type of data it is.
 399        /// </summary>
 400        private bool ConsumeValueMultiSegment(byte marker)
 12585401        {
 12585402            while (true)
 12585403            {
 12585404                Debug.Assert((_trailingCommaBeforeComment && _readerOptions.CommentHandling == JsonCommentHandling.Allow
 12585405                Debug.Assert((_trailingCommaBeforeComment && marker != JsonConstants.Slash) || !_trailingCommaBeforeComm
 12585406                _trailingCommaBeforeComment = false;
 407
 12585408                if (marker == JsonConstants.Quote)
 2722409                {
 2722410                    return ConsumeStringMultiSegment();
 411                }
 9863412                else if (marker == JsonConstants.OpenBrace)
 0413                {
 0414                    StartObject();
 0415                }
 9863416                else if (marker == JsonConstants.OpenBracket)
 264417                {
 264418                    StartArray();
 264419                }
 9599420                else if (JsonHelpers.IsDigit(marker) || marker == '-')
 164421                {
 164422                    return ConsumeNumberMultiSegment();
 423                }
 9435424                else if (marker == 'f')
 42425                {
 42426                    return ConsumeLiteralMultiSegment(JsonConstants.FalseValue, JsonTokenType.False);
 427                }
 9393428                else if (marker == 't')
 8429                {
 8430                    return ConsumeLiteralMultiSegment(JsonConstants.TrueValue, JsonTokenType.True);
 431                }
 9385432                else if (marker == 'n')
 0433                {
 0434                    return ConsumeLiteralMultiSegment(JsonConstants.NullValue, JsonTokenType.Null);
 435                }
 436                else
 9385437                {
 9385438                    switch (_readerOptions.CommentHandling)
 439                    {
 440                        case JsonCommentHandling.Disallow:
 5073441                            break;
 442                        case JsonCommentHandling.Allow:
 0443                            if (marker == JsonConstants.Slash)
 0444                            {
 0445                                SequencePosition copy = _currentPosition;
 0446                                if (!SkipOrConsumeCommentMultiSegmentWithRollback())
 0447                                {
 0448                                    _currentPosition = copy;
 0449                                    return false;
 450                                }
 0451                                return true;
 452                            }
 0453                            break;
 454                        default:
 4312455                            Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Skip);
 4312456                            if (marker == JsonConstants.Slash)
 82457                            {
 82458                                SequencePosition copy = _currentPosition;
 82459                                if (SkipCommentMultiSegment(out _))
 0460                                {
 0461                                    if (_consumed >= (uint)_buffer.Length)
 0462                                    {
 0463                                        if (_isNotPrimitive && IsLastSpan && _tokenType != JsonTokenType.EndArray && _to
 0464                                        {
 0465                                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidEndO
 466                                        }
 0467                                        if (!GetNextSpan())
 0468                                        {
 0469                                            if (_isNotPrimitive && IsLastSpan && _tokenType != JsonTokenType.EndArray &&
 0470                                            {
 0471                                                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.Invalid
 472                                            }
 0473                                            _currentPosition = copy;
 0474                                            return false;
 475                                        }
 0476                                    }
 477
 0478                                    marker = _buffer[_consumed];
 479
 480                                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not ne
 0481                                    if (marker <= JsonConstants.Space)
 0482                                    {
 0483                                        SkipWhiteSpaceMultiSegment();
 0484                                        if (!HasMoreDataMultiSegment())
 0485                                        {
 0486                                            _currentPosition = copy;
 0487                                            return false;
 488                                        }
 0489                                        marker = _buffer[_consumed];
 0490                                    }
 491
 0492                                    TokenStartIndex = BytesConsumed;
 493
 494                                    // Skip comments and consume the actual JSON value.
 0495                                    continue;
 496                                }
 0497                                _currentPosition = copy;
 0498                                return false;
 499                            }
 4230500                            break;
 501                    }
 9303502                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfValueNotFound, marke
 503                }
 264504                break;
 505            }
 264506            return true;
 2579507        }
 508
 509        // Consumes 'null', or 'true', or 'false'
 510        private bool ConsumeLiteralMultiSegment(ReadOnlySpan<byte> literal, JsonTokenType tokenType)
 50511        {
 50512            ReadOnlySpan<byte> span = _buffer.Slice(_consumed);
 50513            Debug.Assert(span.Length > 0);
 50514            Debug.Assert(span[0] == 'n' || span[0] == 't' || span[0] == 'f');
 515
 50516            int consumed = literal.Length;
 517
 50518            if (!span.StartsWith(literal))
 50519            {
 50520                int prevConsumed = _consumed;
 50521                if (CheckLiteralMultiSegment(span, literal, out consumed))
 0522                {
 0523                    goto Done;
 524                }
 0525                _consumed = prevConsumed;
 0526                return false;
 527            }
 528
 0529            ValueSpan = span.Slice(0, literal.Length);
 0530            HasValueSequence = false;
 0531        Done:
 0532            _tokenType = tokenType;
 0533            _consumed += consumed;
 0534            _bytePositionInLine += consumed;
 0535            return true;
 0536        }
 537
 538        private unsafe bool CheckLiteralMultiSegment(ReadOnlySpan<byte> span, ReadOnlySpan<byte> literal, out int consum
 50539        {
 50540            Debug.Assert(span.Length > 0 && span[0] == literal[0] && literal.Length <= JsonConstants.MaximumLiteralLengt
 541
 50542            Span<byte> readSoFar = stackalloc byte[JsonConstants.MaximumLiteralLength];
 50543            int written = 0;
 544
 50545            long prevTotalConsumed = _totalConsumed;
 50546            SequencePosition copy = _currentPosition;
 50547            if (span.Length >= literal.Length || IsLastSpan)
 8548            {
 8549                _bytePositionInLine += FindMismatch(span, literal);
 550
 8551                int amountToWrite = AmountToWrite(span, _bytePositionInLine, readSoFar, written);
 8552                span.Slice(0, amountToWrite).CopyTo(readSoFar);
 8553                written += amountToWrite;
 8554                goto Throw;
 555            }
 556            else
 42557            {
 42558                if (!literal.StartsWith(span))
 0559                {
 0560                    _bytePositionInLine += FindMismatch(span, literal);
 0561                    int amountToWrite = AmountToWrite(span, _bytePositionInLine, readSoFar, written);
 0562                    span.Slice(0, amountToWrite).CopyTo(readSoFar);
 0563                    written += amountToWrite;
 0564                    goto Throw;
 565                }
 566
 42567                ReadOnlySpan<byte> leftToMatch = literal.Slice(span.Length);
 568
 42569                SequencePosition startPosition = _currentPosition;
 42570                int startConsumed = _consumed;
 42571                int alreadyMatched = literal.Length - leftToMatch.Length;
 42572                while (true)
 42573                {
 42574                    _totalConsumed += alreadyMatched;
 42575                    _bytePositionInLine += alreadyMatched;
 42576                    if (!GetNextSpan())
 0577                    {
 0578                        _totalConsumed = prevTotalConsumed;
 0579                        consumed = default;
 0580                        _currentPosition = copy;
 0581                        if (IsLastSpan)
 0582                        {
 0583                            goto Throw;
 584                        }
 0585                        return false;
 586                    }
 587
 42588                    int amountToWrite = Math.Min(span.Length, readSoFar.Length - written);
 42589                    span.Slice(0, amountToWrite).CopyTo(readSoFar.Slice(written));
 42590                    written += amountToWrite;
 591
 42592                    span = _buffer;
 593
 42594                    if (span.StartsWith(leftToMatch))
 0595                    {
 0596                        HasValueSequence = true;
 0597                        SequencePosition start = new SequencePosition(startPosition.GetObject(), startPosition.GetIntege
 0598                        SequencePosition end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetIn
 0599                        ValueSequence = _sequence.Slice(start, end);
 0600                        consumed = leftToMatch.Length;
 0601                        return true;
 602                    }
 603
 42604                    if (!leftToMatch.StartsWith(span))
 42605                    {
 42606                        _bytePositionInLine += FindMismatch(span, leftToMatch);
 607
 42608                        amountToWrite = AmountToWrite(span, _bytePositionInLine, readSoFar, written);
 42609                        span.Slice(0, amountToWrite).CopyTo(readSoFar.Slice(written));
 42610                        written += amountToWrite;
 611
 42612                        goto Throw;
 613                    }
 614
 0615                    leftToMatch = leftToMatch.Slice(span.Length);
 0616                    alreadyMatched = span.Length;
 0617                }
 618            }
 619
 620            static int AmountToWrite(ReadOnlySpan<byte> span, long bytePositionInLine, ReadOnlySpan<byte> readSoFar, int
 50621            {
 50622                return Math.Min(
 50623                    readSoFar.Length - written,
 50624                    Math.Min(span.Length, (int)bytePositionInLine + 1));
 50625            }
 50626        Throw:
 50627            _totalConsumed = prevTotalConsumed;
 50628            consumed = default;
 50629            _currentPosition = copy;
 50630            throw GetInvalidLiteralMultiSegment(readSoFar.Slice(0, written).ToArray());
 0631        }
 632
 633        private static int FindMismatch(ReadOnlySpan<byte> span, ReadOnlySpan<byte> literal)
 50634        {
 50635            Debug.Assert(span.Length > 0);
 636
 50637            int indexOfFirstMismatch = span.CommonPrefixLength(literal);
 638
 50639            Debug.Assert(indexOfFirstMismatch >= 0 && indexOfFirstMismatch < literal.Length);
 640
 50641            return indexOfFirstMismatch;
 50642        }
 643
 644        private JsonException GetInvalidLiteralMultiSegment(ReadOnlySpan<byte> span)
 50645        {
 50646            byte firstByte = span[0];
 647
 648            ExceptionResource resource;
 50649            switch (firstByte)
 650            {
 651                case (byte)'t':
 8652                    resource = ExceptionResource.ExpectedTrue;
 8653                    break;
 654                case (byte)'f':
 42655                    resource = ExceptionResource.ExpectedFalse;
 42656                    break;
 657                default:
 0658                    Debug.Assert(firstByte == 'n');
 0659                    resource = ExceptionResource.ExpectedNull;
 0660                    break;
 661            }
 50662            return ThrowHelper.GetJsonReaderException(ref this, resource, nextByte: default, bytes: span);
 50663        }
 664
 665        private bool ConsumeNumberMultiSegment()
 164666        {
 164667            if (!TryGetNumberMultiSegment(_buffer.Slice(_consumed), out int consumed))
 0668            {
 0669                return false;
 670            }
 671
 105672            _tokenType = JsonTokenType.Number;
 105673            _consumed += consumed;
 674
 105675            if (_consumed >= (uint)_buffer.Length)
 16676            {
 16677                Debug.Assert(IsLastSpan);
 678
 679                // If there is no more data, and the JSON is not a single value, throw.
 16680                if (_isNotPrimitive)
 16681                {
 16682                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, _buffer
 683                }
 0684            }
 685
 686            // If there is more data and the JSON is not a single value, assert that there is an end of number delimiter
 687            // Else, if either the JSON is a single value XOR if there is no more data, don't assert anything since ther
 89688            Debug.Assert(
 89689                ((_consumed < _buffer.Length) &&
 89690                !_isNotPrimitive &&
 89691                JsonConstants.Delimiters.Contains(_buffer[_consumed]))
 89692                || (_isNotPrimitive ^ (_consumed >= (uint)_buffer.Length)));
 693
 89694            return true;
 89695        }
 696
 697        private bool ConsumePropertyNameMultiSegment()
 0698        {
 0699            _trailingCommaBeforeComment = false;
 700
 0701            if (!ConsumeStringMultiSegment())
 0702            {
 0703                return false;
 704            }
 705
 0706            if (!HasMoreDataMultiSegment(ExceptionResource.ExpectedValueAfterPropertyNameNotFound))
 0707            {
 0708                return false;
 709            }
 710
 0711            byte first = _buffer[_consumed];
 712
 713            // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 714            // We do not validate if 'first' is an invalid JSON byte here (such as control characters).
 715            // Those cases are captured below where we only accept ':'.
 0716            if (first <= JsonConstants.Space)
 0717            {
 0718                SkipWhiteSpaceMultiSegment();
 0719                if (!HasMoreDataMultiSegment(ExceptionResource.ExpectedValueAfterPropertyNameNotFound))
 0720                {
 0721                    return false;
 722                }
 0723                first = _buffer[_consumed];
 0724            }
 725
 726            // The next character must be a key / value separator. Validate and skip.
 0727            if (first != JsonConstants.KeyValueSeparator)
 0728            {
 0729                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedSeparatorAfterPropertyNameNotFo
 730            }
 731
 0732            _consumed++;
 0733            _bytePositionInLine++;
 0734            _tokenType = JsonTokenType.PropertyName;
 0735            return true;
 0736        }
 737
 738        private bool ConsumeStringMultiSegment()
 2722739        {
 2722740            Debug.Assert(_buffer.Length >= _consumed + 1);
 2722741            Debug.Assert(_buffer[_consumed] == JsonConstants.Quote);
 742
 743            // Create local copy to avoid bounds checks.
 2722744            ReadOnlySpan<byte> localBuffer = _buffer.Slice(_consumed + 1);
 745
 746            // Vectorized search for either quote, backslash, or any control character.
 747            // If the first found byte is a quote, we have reached an end of string, and
 748            // can avoid validation.
 749            // Otherwise, in the uncommon case, iterate one character at a time and validate.
 2722750            int idx = localBuffer.IndexOfQuoteOrAnyControlOrBackSlash();
 751
 2722752            if (idx >= 0)
 1283753            {
 1283754                byte foundByte = localBuffer[idx];
 1283755                if (foundByte == JsonConstants.Quote)
 1176756                {
 1176757                    _bytePositionInLine += idx + 2; // Add 2 for the start and end quotes.
 1176758                    ValueSpan = localBuffer.Slice(0, idx);
 1176759                    HasValueSequence = false;
 1176760                    ValueIsEscaped = false;
 1176761                    _tokenType = JsonTokenType.String;
 1176762                    _consumed += idx + 2;
 1176763                    return true;
 764                }
 765                else
 107766                {
 107767                    return ConsumeStringAndValidateMultiSegment(localBuffer, idx);
 768                }
 769            }
 770            else
 1439771            {
 1439772                if (IsLastSpan)
 42773                {
 42774                    _bytePositionInLine += localBuffer.Length + 1;  // Account for the start quote
 42775                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound);
 776                }
 1397777                return ConsumeStringNextSegment();
 778            }
 2226779        }
 780
 781        private bool ConsumeStringNextSegment()
 1397782        {
 1397783            PartialStateForRollback rollBackState = CaptureState();
 784
 785            SequencePosition end;
 1397786            HasValueSequence = true;
 1397787            int leftOver = _buffer.Length - _consumed;
 788
 2290789            while (true)
 2290790            {
 2290791                if (!GetNextSpan())
 176792                {
 176793                    if (IsLastSpan)
 176794                    {
 176795                        _bytePositionInLine += leftOver;
 176796                        RollBackState(rollBackState, isError: true);
 176797                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound);
 798                    }
 0799                    RollBackState(rollBackState);
 0800                    return false;
 801                }
 802
 803                //Create local copy to avoid bounds checks.
 2114804                ReadOnlySpan<byte> localBuffer = _buffer;
 2114805                int idx = localBuffer.IndexOfQuoteOrAnyControlOrBackSlash();
 806
 2114807                if (idx >= 0)
 1221808                {
 1221809                    byte foundByte = localBuffer[idx];
 1221810                    if (foundByte == JsonConstants.Quote)
 1050811                    {
 1050812                        end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetInteger() + idx);
 1050813                        _bytePositionInLine += leftOver + idx + 1;  // Add 1 for the end quote of the string.
 1050814                        _totalConsumed += leftOver;
 1050815                        _consumed = idx + 1;    // Add 1 for the end quote of the string.
 1050816                        ValueIsEscaped = false;
 1050817                        break;
 818                    }
 819                    else
 171820                    {
 171821                        _bytePositionInLine += leftOver + idx;
 171822                        ValueIsEscaped = true;
 823
 171824                        bool nextCharEscaped = false;
 171825                        while (true)
 171826                        {
 171827                        StartOfLoop:
 171828                            for (; idx < localBuffer.Length; idx++)
 171829                            {
 171830                                byte currentByte = localBuffer[idx];
 171831                                if (currentByte == JsonConstants.Quote)
 0832                                {
 0833                                    if (!nextCharEscaped)
 0834                                    {
 0835                                        goto Done;
 836                                    }
 0837                                    nextCharEscaped = false;
 0838                                }
 171839                                else if (currentByte == JsonConstants.BackSlash)
 0840                                {
 0841                                    nextCharEscaped = !nextCharEscaped;
 0842                                }
 171843                                else if (nextCharEscaped)
 0844                                {
 0845                                    if (!JsonConstants.EscapableChars.Contains(currentByte))
 0846                                    {
 0847                                        RollBackState(rollBackState, isError: true);
 0848                                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacte
 849                                    }
 850
 0851                                    if (currentByte == 'u')
 0852                                    {
 853                                        // Expecting 4 hex digits to follow the escaped 'u'
 0854                                        _bytePositionInLine++;  // move past the 'u'
 855
 0856                                        int numberOfHexDigits = 0;
 0857                                        int j = idx + 1;
 0858                                        while (true)
 0859                                        {
 0860                                            for (; j < localBuffer.Length; j++)
 0861                                            {
 0862                                                byte nextByte = localBuffer[j];
 0863                                                if (!JsonReaderHelper.IsHexDigit(nextByte))
 0864                                                {
 0865                                                    RollBackState(rollBackState, isError: true);
 0866                                                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.Inv
 867                                                }
 0868                                                numberOfHexDigits++;
 0869                                                _bytePositionInLine++;
 0870                                                if (numberOfHexDigits >= 4)
 0871                                                {
 0872                                                    nextCharEscaped = false;
 0873                                                    idx = j + 1; // Skip the 4 hex digits, the for loop accounts for idx
 0874                                                    goto StartOfLoop;
 875                                                }
 0876                                            }
 877
 0878                                            if (!GetNextSpan())
 0879                                            {
 0880                                                if (IsLastSpan)
 0881                                                {
 0882                                                    RollBackState(rollBackState, isError: true);
 0883                                                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.End
 884                                                }
 885
 886                                                // We found less than 4 hex digits.
 0887                                                RollBackState(rollBackState);
 0888                                                return false;
 889                                            }
 890
 0891                                            _totalConsumed += localBuffer.Length;
 892
 0893                                            localBuffer = _buffer;
 0894                                            j = 0;
 0895                                        }
 896                                    }
 0897                                    nextCharEscaped = false;
 0898                                }
 171899                                else if (currentByte < JsonConstants.Space)
 171900                                {
 171901                                    RollBackState(rollBackState, isError: true);
 171902                                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterWit
 903                                }
 904
 0905                                _bytePositionInLine++;
 0906                            }
 907
 0908                            if (!GetNextSpan())
 0909                            {
 0910                                if (IsLastSpan)
 0911                                {
 0912                                    RollBackState(rollBackState, isError: true);
 0913                                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound
 914                                }
 0915                                RollBackState(rollBackState);
 0916                                return false;
 917                            }
 918
 0919                            _totalConsumed += localBuffer.Length;
 0920                            localBuffer = _buffer;
 0921                            idx = 0;
 0922                        }
 923
 0924                    Done:
 0925                        _bytePositionInLine++;  // Add 1 for the end quote of the string.
 0926                        _consumed = idx + 1;    // Add 1 for the end quote of the string.
 0927                        _totalConsumed += leftOver;
 0928                        end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetInteger() + idx);
 0929                        break;
 930                    }
 931                }
 932
 893933                _totalConsumed += localBuffer.Length;
 893934                _bytePositionInLine += localBuffer.Length;
 893935            }
 936
 1050937            SequencePosition start = rollBackState.GetStartPosition(offset: 1); // Offset for the starting quote
 1050938            ValueSequence = _sequence.Slice(start, end);
 1050939            _tokenType = JsonTokenType.String;
 1050940            return true;
 1050941        }
 942
 943        // Found a backslash or control characters which are considered invalid within a string.
 944        // Search through the rest of the string one byte at a time.
 945        // https://tools.ietf.org/html/rfc8259#section-7
 946        private bool ConsumeStringAndValidateMultiSegment(ReadOnlySpan<byte> data, int idx)
 107947        {
 107948            Debug.Assert(idx >= 0 && idx < data.Length);
 107949            Debug.Assert(data[idx] != JsonConstants.Quote);
 107950            Debug.Assert(data[idx] == JsonConstants.BackSlash || data[idx] < JsonConstants.Space);
 951
 107952            PartialStateForRollback rollBackState = CaptureState();
 953
 954            SequencePosition end;
 107955            HasValueSequence = false;
 107956            int leftOverFromConsumed = _buffer.Length - _consumed;
 957
 107958            _bytePositionInLine += idx + 1; // Add 1 for the first quote
 959
 107960            bool nextCharEscaped = false;
 107961            while (true)
 107962            {
 107963            StartOfLoop:
 107964                for (; idx < data.Length; idx++)
 107965                {
 107966                    byte currentByte = data[idx];
 107967                    if (currentByte == JsonConstants.Quote)
 0968                    {
 0969                        if (!nextCharEscaped)
 0970                        {
 0971                            goto Done;
 972                        }
 0973                        nextCharEscaped = false;
 0974                    }
 107975                    else if (currentByte == JsonConstants.BackSlash)
 0976                    {
 0977                        nextCharEscaped = !nextCharEscaped;
 0978                    }
 107979                    else if (nextCharEscaped)
 0980                    {
 0981                        if (!JsonConstants.EscapableChars.Contains(currentByte))
 0982                        {
 0983                            RollBackState(rollBackState, isError: true);
 0984                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterAfterEscape
 985                        }
 986
 0987                        if (currentByte == 'u')
 0988                        {
 989                            // Expecting 4 hex digits to follow the escaped 'u'
 0990                            _bytePositionInLine++;  // move past the 'u'
 991
 0992                            int numberOfHexDigits = 0;
 0993                            int j = idx + 1;
 0994                            while (true)
 0995                            {
 0996                                for (; j < data.Length; j++)
 0997                                {
 0998                                    byte nextByte = data[j];
 0999                                    if (!JsonReaderHelper.IsHexDigit(nextByte))
 01000                                    {
 01001                                        RollBackState(rollBackState, isError: true);
 01002                                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidHexChara
 1003                                    }
 01004                                    numberOfHexDigits++;
 01005                                    _bytePositionInLine++;
 01006                                    if (numberOfHexDigits >= 4)
 01007                                    {
 01008                                        nextCharEscaped = false;
 01009                                        idx = j + 1; // Skip the 4 hex digits, the for loop accounts for idx incrementin
 01010                                        goto StartOfLoop;
 1011                                    }
 01012                                }
 1013
 01014                                if (!GetNextSpan())
 01015                                {
 01016                                    if (IsLastSpan)
 01017                                    {
 01018                                        RollBackState(rollBackState, isError: true);
 01019                                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotF
 1020                                    }
 1021
 1022                                    // We found less than 4 hex digits.
 01023                                    RollBackState(rollBackState);
 01024                                    return false;
 1025                                }
 1026
 1027                                // Do not add the left over for the first segment to total consumed
 01028                                if (HasValueSequence)
 01029                                {
 01030                                    _totalConsumed += data.Length;
 01031                                }
 1032
 01033                                data = _buffer;
 01034                                j = 0;
 01035                                HasValueSequence = true;
 01036                            }
 1037                        }
 01038                        nextCharEscaped = false;
 01039                    }
 1071040                    else if (currentByte < JsonConstants.Space)
 1071041                    {
 1071042                        RollBackState(rollBackState, isError: true);
 1071043                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterWithinString, c
 1044                    }
 1045
 01046                    _bytePositionInLine++;
 01047                }
 1048
 01049                if (!GetNextSpan())
 01050                {
 01051                    if (IsLastSpan)
 01052                    {
 01053                        RollBackState(rollBackState, isError: true);
 01054                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound);
 1055                    }
 01056                    RollBackState(rollBackState);
 01057                    return false;
 1058                }
 1059
 1060                // Do not add the left over for the first segment to total consumed
 01061                if (HasValueSequence)
 01062                {
 01063                    _totalConsumed += data.Length;
 01064                }
 1065
 01066                data = _buffer;
 01067                idx = 0;
 01068                HasValueSequence = true;
 01069            }
 1070
 01071        Done:
 01072            if (HasValueSequence)
 01073            {
 01074                _bytePositionInLine++;  // Add 1 for the end quote of the string.
 01075                _consumed = idx + 1;    // Add 1 for the end quote of the string.
 01076                _totalConsumed += leftOverFromConsumed;
 01077                end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetInteger() + idx);
 01078                SequencePosition start = rollBackState.GetStartPosition(offset: 1); // Offset for the starting quote
 01079                ValueSequence = _sequence.Slice(start, end);
 01080            }
 1081            else
 01082            {
 01083                _bytePositionInLine++;  // Add 1 for the end quote
 01084                _consumed += idx + 2;
 01085                ValueSpan = data.Slice(0, idx);
 01086            }
 1087
 01088            ValueIsEscaped = true;
 01089            _tokenType = JsonTokenType.String;
 01090            return true;
 01091        }
 1092
 1093        private void RollBackState(scoped in PartialStateForRollback state, bool isError = false)
 8491094        {
 8491095            _totalConsumed = state._prevTotalConsumed;
 1096
 1097            // Don't roll back byte position in line for invalid JSON since that is provided
 1098            // to the user within the exception.
 8491099            if (!isError)
 01100            {
 01101                _bytePositionInLine = state._prevBytePositionInLine;
 01102            }
 1103
 8491104            _consumed = state._prevConsumed;
 8491105            _currentPosition = state._prevCurrentPosition;
 8491106        }
 1107
 1108        // https://tools.ietf.org/html/rfc7159#section-6
 1109        private bool TryGetNumberMultiSegment(ReadOnlySpan<byte> data, out int consumed)
 19281110        {
 1111            // TODO: https://github.com/dotnet/runtime/issues/27837
 19281112            Debug.Assert(data.Length > 0);
 1113
 19281114            PartialStateForRollback rollBackState = CaptureState();
 1115
 19281116            consumed = 0;
 19281117            int i = 0;
 1118
 19281119            ConsumeNumberResult signResult = ConsumeNegativeSignMultiSegment(ref data, ref i, rollBackState);
 18781120            if (signResult == ConsumeNumberResult.NeedMoreData)
 01121            {
 01122                RollBackState(rollBackState);
 01123                return false;
 1124            }
 1125
 18781126            Debug.Assert(signResult == ConsumeNumberResult.OperationIncomplete);
 1127
 18781128            byte nextByte = data[i];
 18781129            Debug.Assert(nextByte is >= (byte)'0' and <= (byte)'9');
 1130
 18781131            if (nextByte == '0')
 9571132            {
 9571133                ConsumeNumberResult result = ConsumeZeroMultiSegment(ref data, ref i, rollBackState);
 7621134                if (result == ConsumeNumberResult.NeedMoreData)
 01135                {
 01136                    RollBackState(rollBackState);
 01137                    return false;
 1138                }
 7621139                if (result == ConsumeNumberResult.Success)
 7621140                {
 7621141                    goto Done;
 1142                }
 1143
 01144                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 01145                nextByte = data[i];
 01146            }
 1147            else
 9211148            {
 9211149                ConsumeNumberResult result = ConsumeIntegerDigitsMultiSegment(ref data, ref i);
 9211150                if (result == ConsumeNumberResult.NeedMoreData)
 01151                {
 01152                    RollBackState(rollBackState);
 01153                    return false;
 1154                }
 9211155                if (result == ConsumeNumberResult.Success)
 7711156                {
 7711157                    goto Done;
 1158                }
 1159
 1501160                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 1501161                nextByte = data[i];
 1501162                if (nextByte is not ((byte)'.' or (byte)'E' or (byte)'e'))
 1501163                {
 1501164                    RollBackState(rollBackState, isError: true);
 1501165                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, nextByt
 1166                }
 01167            }
 1168
 01169            Debug.Assert(nextByte is (byte)'.' or (byte)'E' or (byte)'e');
 1170
 01171            if (nextByte == '.')
 01172            {
 01173                i++;
 01174                _bytePositionInLine++;
 01175                ConsumeNumberResult result = ConsumeDecimalDigitsMultiSegment(ref data, ref i, rollBackState);
 01176                if (result == ConsumeNumberResult.NeedMoreData)
 01177                {
 01178                    RollBackState(rollBackState);
 01179                    return false;
 1180                }
 01181                if (result == ConsumeNumberResult.Success)
 01182                {
 01183                    goto Done;
 1184                }
 1185
 01186                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 01187                nextByte = data[i];
 01188                if (nextByte is not ((byte)'E' or (byte)'e'))
 01189                {
 01190                    RollBackState(rollBackState, isError: true);
 01191                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedNextDigitEValueNotFound, ne
 1192                }
 01193            }
 1194
 01195            Debug.Assert(nextByte is (byte)'E' or (byte)'e');
 01196            i++;
 01197            _bytePositionInLine++;
 1198
 01199            signResult = ConsumeSignMultiSegment(ref data, ref i, rollBackState);
 01200            if (signResult == ConsumeNumberResult.NeedMoreData)
 01201            {
 01202                RollBackState(rollBackState);
 01203                return false;
 1204            }
 1205
 01206            Debug.Assert(signResult == ConsumeNumberResult.OperationIncomplete);
 1207
 01208            i++;
 01209            _bytePositionInLine++;
 01210            ConsumeNumberResult resultExponent = ConsumeIntegerDigitsMultiSegment(ref data, ref i);
 01211            if (resultExponent == ConsumeNumberResult.NeedMoreData)
 01212            {
 01213                RollBackState(rollBackState);
 01214                return false;
 1215            }
 01216            if (resultExponent == ConsumeNumberResult.Success)
 01217            {
 01218                goto Done;
 1219            }
 1220
 01221            Debug.Assert(resultExponent == ConsumeNumberResult.OperationIncomplete);
 1222
 01223            RollBackState(rollBackState, isError: true);
 01224            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, data[i]);
 1225
 15331226        Done:
 15331227            if (HasValueSequence)
 3021228            {
 3021229                SequencePosition start = rollBackState.GetStartPosition();
 3021230                SequencePosition end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetInteger() 
 3021231                ValueSequence = _sequence.Slice(start, end);
 3021232                consumed = i;
 3021233            }
 1234            else
 12311235            {
 12311236                ValueSpan = data.Slice(0, i);
 12311237                consumed = i;
 12311238            }
 15331239            return true;
 15331240        }
 1241
 1242        private ConsumeNumberResult ConsumeNegativeSignMultiSegment(ref ReadOnlySpan<byte> data, scoped ref int i, scope
 19281243        {
 19281244            Debug.Assert(i == 0);
 19281245            byte nextByte = data[i];
 1246
 19281247            if (nextByte == '-')
 501248            {
 501249                i++;
 501250                _bytePositionInLine++;
 501251                if (i >= data.Length)
 01252                {
 01253                    if (IsLastSpan)
 01254                    {
 01255                        RollBackState(rollBackState, isError: true);
 01256                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1257                    }
 01258                    if (!GetNextSpan())
 01259                    {
 01260                        if (IsLastSpan)
 01261                        {
 01262                            RollBackState(rollBackState, isError: true);
 01263                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfD
 1264                        }
 01265                        return ConsumeNumberResult.NeedMoreData;
 1266                    }
 01267                    Debug.Assert(i == 1);
 01268                    _totalConsumed += i;
 01269                    HasValueSequence = true;
 01270                    i = 0;
 01271                    data = _buffer;
 01272                }
 1273
 501274                nextByte = data[i];
 501275                if (!JsonHelpers.IsDigit(nextByte))
 501276                {
 501277                    RollBackState(rollBackState, isError: true);
 501278                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nex
 1279                }
 01280            }
 18781281            return ConsumeNumberResult.OperationIncomplete;
 18781282        }
 1283
 1284        private ConsumeNumberResult ConsumeZeroMultiSegment(ref ReadOnlySpan<byte> data, scoped ref int i, scoped in Par
 9571285        {
 9571286            Debug.Assert(data[i] == (byte)'0');
 9571287            Debug.Assert(i == 0 || i == 1);
 9571288            i++;
 9571289            _bytePositionInLine++;
 1290            byte nextByte;
 9571291            if (i < data.Length)
 7551292            {
 7551293                nextByte = data[i];
 7551294                if (JsonConstants.Delimiters.Contains(nextByte))
 6201295                {
 6201296                    return ConsumeNumberResult.Success;
 1297                }
 1351298            }
 1299            else
 2021300            {
 2021301                if (IsLastSpan)
 81302                {
 1303                    // A payload containing a single value: "0" is valid
 1304                    // If we are dealing with multi-value JSON,
 1305                    // ConsumeNumber will validate that we have a delimiter following the "0".
 81306                    return ConsumeNumberResult.Success;
 1307                }
 1308
 1941309                if (!GetNextSpan())
 01310                {
 01311                    if (IsLastSpan)
 01312                    {
 01313                        return ConsumeNumberResult.Success;
 1314                    }
 01315                    return ConsumeNumberResult.NeedMoreData;
 1316                }
 1317
 1941318                _totalConsumed += i;
 1941319                HasValueSequence = true;
 1941320                i = 0;
 1941321                data = _buffer;
 1941322                nextByte = data[i];
 1941323                if (JsonConstants.Delimiters.Contains(nextByte))
 1341324                {
 1341325                    return ConsumeNumberResult.Success;
 1326                }
 601327            }
 1951328            nextByte = data[i];
 1951329            if (nextByte is not ((byte)'.' or (byte)'E' or (byte)'e'))
 1951330            {
 1951331                RollBackState(rollBackState, isError: true);
 1951332                ThrowHelper.ThrowJsonReaderException(ref this,
 1951333                    JsonHelpers.IsInRangeInclusive(nextByte, '0', '9') ? ExceptionResource.InvalidLeadingZeroInNumber : 
 1951334                    nextByte);
 1335            }
 1336
 01337            return ConsumeNumberResult.OperationIncomplete;
 7621338        }
 1339
 1340        private ConsumeNumberResult ConsumeIntegerDigitsMultiSegment(ref ReadOnlySpan<byte> data, scoped ref int i)
 9211341        {
 9211342            byte nextByte = default;
 9211343            int counter = 0;
 31831344            for (; i < data.Length; i++)
 18681345            {
 18681346                nextByte = data[i];
 18681347                if (!JsonHelpers.IsDigit(nextByte))
 7371348                {
 7371349                    break;
 1350                }
 11311351                counter++;
 11311352            }
 9211353            if (i >= data.Length)
 1841354            {
 1841355                if (IsLastSpan)
 81356                {
 1357                    // A payload containing a single value of integers (e.g. "12") is valid
 1358                    // If we are dealing with multi-value JSON,
 1359                    // ConsumeNumber will validate that we have a delimiter following the integer.
 81360                    _bytePositionInLine += counter;
 81361                    return ConsumeNumberResult.Success;
 1362                }
 1363
 3021364                while (true)
 3021365                {
 3021366                    if (!GetNextSpan())
 01367                    {
 01368                        if (IsLastSpan)
 01369                        {
 01370                            _bytePositionInLine += counter;
 01371                            return ConsumeNumberResult.Success;
 1372                        }
 01373                        return ConsumeNumberResult.NeedMoreData;
 1374                    }
 1375
 3021376                    _totalConsumed += i;
 3021377                    _bytePositionInLine += counter;
 3021378                    counter = 0;
 3021379                    HasValueSequence = true;
 3021380                    i = 0;
 3021381                    data = _buffer;
 6381382                    for (; i < data.Length; i++)
 3441383                    {
 3441384                        nextByte = data[i];
 3441385                        if (!JsonHelpers.IsDigit(nextByte))
 1761386                        {
 1761387                            break;
 1388                        }
 1681389                    }
 3021390                    _bytePositionInLine += i;
 3021391                    if (i >= data.Length)
 1261392                    {
 1261393                        if (IsLastSpan)
 01394                        {
 01395                            return ConsumeNumberResult.Success;
 1396                        }
 1261397                    }
 1398                    else
 1761399                    {
 1761400                        break;
 1401                    }
 1261402                }
 1403
 1761404            }
 1405            else
 7371406            {
 7371407                _bytePositionInLine += counter;
 7371408            }
 1409
 9131410            if (JsonConstants.Delimiters.Contains(nextByte))
 7631411            {
 7631412                return ConsumeNumberResult.Success;
 1413            }
 1414
 1501415            return ConsumeNumberResult.OperationIncomplete;
 9211416        }
 1417
 1418        private ConsumeNumberResult ConsumeDecimalDigitsMultiSegment(ref ReadOnlySpan<byte> data, scoped ref int i, scop
 01419        {
 01420            if (i >= data.Length)
 01421            {
 01422                if (IsLastSpan)
 01423                {
 01424                    RollBackState(rollBackState, isError: true);
 01425                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData);
 1426                }
 01427                if (!GetNextSpan())
 01428                {
 01429                    if (IsLastSpan)
 01430                    {
 01431                        RollBackState(rollBackState, isError: true);
 01432                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1433                    }
 01434                    return ConsumeNumberResult.NeedMoreData;
 1435                }
 01436                _totalConsumed += i;
 01437                HasValueSequence = true;
 01438                i = 0;
 01439                data = _buffer;
 01440            }
 01441            byte nextByte = data[i];
 01442            if (!JsonHelpers.IsDigit(nextByte))
 01443            {
 01444                RollBackState(rollBackState, isError: true);
 01445                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterDecimal, next
 1446            }
 01447            i++;
 01448            _bytePositionInLine++;
 01449            return ConsumeIntegerDigitsMultiSegment(ref data, ref i);
 01450        }
 1451
 1452        private ConsumeNumberResult ConsumeSignMultiSegment(ref ReadOnlySpan<byte> data, scoped ref int i, scoped in Par
 01453        {
 01454            if (i >= data.Length)
 01455            {
 01456                if (IsLastSpan)
 01457                {
 01458                    RollBackState(rollBackState, isError: true);
 01459                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData);
 1460                }
 1461
 01462                if (!GetNextSpan())
 01463                {
 01464                    if (IsLastSpan)
 01465                    {
 01466                        RollBackState(rollBackState, isError: true);
 01467                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1468                    }
 01469                    return ConsumeNumberResult.NeedMoreData;
 1470                }
 01471                _totalConsumed += i;
 01472                HasValueSequence = true;
 01473                i = 0;
 01474                data = _buffer;
 01475            }
 1476
 01477            byte nextByte = data[i];
 01478            if (nextByte is (byte)'+' or (byte)'-')
 01479            {
 01480                i++;
 01481                _bytePositionInLine++;
 01482                if (i >= data.Length)
 01483                {
 01484                    if (IsLastSpan)
 01485                    {
 01486                        RollBackState(rollBackState, isError: true);
 01487                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1488                    }
 1489
 01490                    if (!GetNextSpan())
 01491                    {
 01492                        if (IsLastSpan)
 01493                        {
 01494                            RollBackState(rollBackState, isError: true);
 01495                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfD
 1496                        }
 01497                        return ConsumeNumberResult.NeedMoreData;
 1498                    }
 01499                    _totalConsumed += i;
 01500                    HasValueSequence = true;
 01501                    i = 0;
 01502                    data = _buffer;
 01503                }
 01504                nextByte = data[i];
 01505            }
 1506
 01507            if (!JsonHelpers.IsDigit(nextByte))
 01508            {
 01509                RollBackState(rollBackState, isError: true);
 01510                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nextByt
 1511            }
 1512
 01513            return ConsumeNumberResult.OperationIncomplete;
 01514        }
 1515
 1516        private bool ConsumeNextTokenOrRollbackMultiSegment(byte marker)
 10321517        {
 10321518            long prevTotalConsumed = _totalConsumed;
 10321519            int prevConsumed = _consumed;
 10321520            long prevPosition = _bytePositionInLine;
 10321521            long prevLineNumber = _lineNumber;
 10321522            JsonTokenType prevTokenType = _tokenType;
 10321523            SequencePosition prevSequencePosition = _currentPosition;
 10321524            bool prevTrailingCommaBeforeComment = _trailingCommaBeforeComment;
 10321525            ConsumeTokenResult result = ConsumeNextTokenMultiSegment(marker);
 01526            if (result == ConsumeTokenResult.Success)
 01527            {
 01528                return true;
 1529            }
 01530            if (result == ConsumeTokenResult.NotEnoughDataRollBackState)
 01531            {
 01532                _consumed = prevConsumed;
 01533                _tokenType = prevTokenType;
 01534                _bytePositionInLine = prevPosition;
 01535                _lineNumber = prevLineNumber;
 01536                _totalConsumed = prevTotalConsumed;
 01537                _currentPosition = prevSequencePosition;
 01538                _trailingCommaBeforeComment = prevTrailingCommaBeforeComment;
 01539            }
 01540            return false;
 01541        }
 1542
 1543        /// <summary>
 1544        /// This method consumes the next token regardless of whether we are inside an object or an array.
 1545        /// For an object, it reads the next property name token. For an array, it just reads the next value.
 1546        /// </summary>
 1547        private ConsumeTokenResult ConsumeNextTokenMultiSegment(byte marker)
 10321548        {
 10321549            if (_readerOptions.CommentHandling != JsonCommentHandling.Disallow)
 1401550            {
 1401551                if (_readerOptions.CommentHandling == JsonCommentHandling.Allow)
 01552                {
 01553                    if (marker == JsonConstants.Slash)
 01554                    {
 01555                        return SkipOrConsumeCommentMultiSegmentWithRollback() ? ConsumeTokenResult.Success : ConsumeToke
 1556                    }
 01557                    if (_tokenType == JsonTokenType.Comment)
 01558                    {
 01559                        return ConsumeNextTokenFromLastNonCommentTokenMultiSegment();
 1560                    }
 01561                }
 1562                else
 1401563                {
 1401564                    Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Skip);
 1401565                    return ConsumeNextTokenUntilAfterAllCommentsAreSkippedMultiSegment(marker);
 1566                }
 01567            }
 1568
 8921569            if (_bitStack.CurrentDepth == 0)
 8221570            {
 8221571                if (_readerOptions.AllowMultipleValues)
 01572                {
 01573                    return ReadFirstTokenMultiSegment(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoug
 1574                }
 1575
 8221576                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, marker);
 1577            }
 1578
 701579            if (marker == JsonConstants.ListSeparator)
 01580            {
 01581                _consumed++;
 01582                _bytePositionInLine++;
 1583
 01584                if (_consumed >= (uint)_buffer.Length)
 01585                {
 01586                    if (IsLastSpan)
 01587                    {
 01588                        _consumed--;
 01589                        _bytePositionInLine--;
 01590                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 1591                    }
 01592                    if (!GetNextSpan())
 01593                    {
 01594                        if (IsLastSpan)
 01595                        {
 01596                            _consumed--;
 01597                            _bytePositionInLine--;
 01598                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrVa
 1599                        }
 01600                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 1601                    }
 01602                }
 01603                byte first = _buffer[_consumed];
 1604
 1605                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01606                if (first <= JsonConstants.Space)
 01607                {
 01608                    SkipWhiteSpaceMultiSegment();
 1609                    // The next character must be a start of a property name or value.
 01610                    if (!HasMoreDataMultiSegment(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 01611                    {
 01612                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 1613                    }
 01614                    first = _buffer[_consumed];
 01615                }
 1616
 01617                TokenStartIndex = BytesConsumed;
 1618
 01619                if (_readerOptions.CommentHandling == JsonCommentHandling.Allow && first == JsonConstants.Slash)
 01620                {
 01621                    _trailingCommaBeforeComment = true;
 01622                    return SkipOrConsumeCommentMultiSegmentWithRollback() ? ConsumeTokenResult.Success : ConsumeTokenRes
 1623                }
 1624
 01625                if (_inObject)
 01626                {
 01627                    if (first != JsonConstants.Quote)
 01628                    {
 01629                        if (first == JsonConstants.CloseBrace)
 01630                        {
 01631                            if (_readerOptions.AllowTrailingCommas)
 01632                            {
 01633                                EndObject();
 01634                                return ConsumeTokenResult.Success;
 1635                            }
 01636                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 1637                        }
 01638                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 1639                    }
 01640                    return ConsumePropertyNameMultiSegment() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnough
 1641                }
 1642                else
 01643                {
 01644                    if (first == JsonConstants.CloseBracket)
 01645                    {
 01646                        if (_readerOptions.AllowTrailingCommas)
 01647                        {
 01648                            EndArray();
 01649                            return ConsumeTokenResult.Success;
 1650                        }
 01651                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 1652                    }
 01653                    return ConsumeValueMultiSegment(first) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDa
 1654                }
 1655            }
 701656            else if (marker == JsonConstants.CloseBrace)
 01657            {
 01658                EndObject();
 01659            }
 701660            else if (marker == JsonConstants.CloseBracket)
 01661            {
 01662                EndArray();
 01663            }
 1664            else
 701665            {
 701666                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.FoundInvalidCharacter, marker);
 1667            }
 01668            return ConsumeTokenResult.Success;
 01669        }
 1670
 1671        private ConsumeTokenResult ConsumeNextTokenFromLastNonCommentTokenMultiSegment()
 01672        {
 01673            Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Allow);
 01674            Debug.Assert(_tokenType == JsonTokenType.Comment);
 1675
 01676            if (JsonReaderHelper.IsTokenTypePrimitive(_previousTokenType))
 01677            {
 01678                _tokenType = _inObject ? JsonTokenType.StartObject : JsonTokenType.StartArray;
 01679            }
 1680            else
 01681            {
 01682                _tokenType = _previousTokenType;
 01683            }
 1684
 01685            Debug.Assert(_tokenType != JsonTokenType.Comment);
 1686
 01687            if (!HasMoreDataMultiSegment())
 01688            {
 01689                goto RollBack;
 1690            }
 1691
 01692            byte first = _buffer[_consumed];
 1693
 1694            // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01695            if (first <= JsonConstants.Space)
 01696            {
 01697                SkipWhiteSpaceMultiSegment();
 01698                if (!HasMoreDataMultiSegment())
 01699                {
 01700                    goto RollBack;
 1701                }
 01702                first = _buffer[_consumed];
 01703            }
 1704
 01705            if (_bitStack.CurrentDepth == 0 && _tokenType != JsonTokenType.None)
 01706            {
 01707                if (_readerOptions.AllowMultipleValues)
 01708                {
 01709                    return ReadFirstTokenMultiSegment(first) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnough
 1710                }
 1711
 01712                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, first);
 1713            }
 1714
 01715            Debug.Assert(first != JsonConstants.Slash);
 1716
 01717            TokenStartIndex = BytesConsumed;
 1718
 01719            if (first == JsonConstants.ListSeparator)
 01720            {
 1721                // A comma without some JSON value preceding it is invalid
 01722                if (_previousTokenType <= JsonTokenType.StartObject || _previousTokenType == JsonTokenType.StartArray ||
 01723                {
 01724                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueAfter
 1725                }
 1726
 01727                _consumed++;
 01728                _bytePositionInLine++;
 1729
 01730                if (_consumed >= (uint)_buffer.Length)
 01731                {
 01732                    if (IsLastSpan)
 01733                    {
 01734                        _consumed--;
 01735                        _bytePositionInLine--;
 01736                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 1737                    }
 01738                    if (!GetNextSpan())
 01739                    {
 01740                        if (IsLastSpan)
 01741                        {
 01742                            _consumed--;
 01743                            _bytePositionInLine--;
 01744                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrVa
 1745                        }
 01746                        goto RollBack;
 1747                    }
 01748                }
 01749                first = _buffer[_consumed];
 1750
 1751                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01752                if (first <= JsonConstants.Space)
 01753                {
 01754                    SkipWhiteSpaceMultiSegment();
 1755                    // The next character must be a start of a property name or value.
 01756                    if (!HasMoreDataMultiSegment(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 01757                    {
 01758                        goto RollBack;
 1759                    }
 01760                    first = _buffer[_consumed];
 01761                }
 1762
 01763                TokenStartIndex = BytesConsumed;
 1764
 01765                if (first == JsonConstants.Slash)
 01766                {
 01767                    _trailingCommaBeforeComment = true;
 01768                    if (SkipOrConsumeCommentMultiSegmentWithRollback())
 01769                    {
 01770                        goto Done;
 1771                    }
 1772                    else
 01773                    {
 01774                        goto RollBack;
 1775                    }
 1776                }
 1777
 01778                if (_inObject)
 01779                {
 01780                    if (first != JsonConstants.Quote)
 01781                    {
 01782                        if (first == JsonConstants.CloseBrace)
 01783                        {
 01784                            if (_readerOptions.AllowTrailingCommas)
 01785                            {
 01786                                EndObject();
 01787                                goto Done;
 1788                            }
 01789                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 1790                        }
 1791
 01792                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 1793                    }
 01794                    if (ConsumePropertyNameMultiSegment())
 01795                    {
 01796                        goto Done;
 1797                    }
 1798                    else
 01799                    {
 01800                        goto RollBack;
 1801                    }
 1802                }
 1803                else
 01804                {
 01805                    if (first == JsonConstants.CloseBracket)
 01806                    {
 01807                        if (_readerOptions.AllowTrailingCommas)
 01808                        {
 01809                            EndArray();
 01810                            goto Done;
 1811                        }
 01812                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 1813                    }
 1814
 01815                    if (ConsumeValueMultiSegment(first))
 01816                    {
 01817                        goto Done;
 1818                    }
 1819                    else
 01820                    {
 01821                        goto RollBack;
 1822                    }
 1823                }
 1824            }
 01825            else if (first == JsonConstants.CloseBrace)
 01826            {
 01827                EndObject();
 01828            }
 01829            else if (first == JsonConstants.CloseBracket)
 01830            {
 01831                EndArray();
 01832            }
 01833            else if (_tokenType == JsonTokenType.None)
 01834            {
 01835                if (ReadFirstTokenMultiSegment(first))
 01836                {
 01837                    goto Done;
 1838                }
 1839                else
 01840                {
 01841                    goto RollBack;
 1842                }
 1843            }
 01844            else if (_tokenType == JsonTokenType.StartObject)
 01845            {
 01846                Debug.Assert(first != JsonConstants.CloseBrace);
 01847                if (first != JsonConstants.Quote)
 01848                {
 01849                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound, fi
 1850                }
 1851
 01852                long prevTotalConsumed = _totalConsumed;
 01853                int prevConsumed = _consumed;
 01854                long prevPosition = _bytePositionInLine;
 01855                long prevLineNumber = _lineNumber;
 01856                if (!ConsumePropertyNameMultiSegment())
 01857                {
 1858                    // roll back potential changes
 01859                    _consumed = prevConsumed;
 01860                    _tokenType = JsonTokenType.StartObject;
 01861                    _bytePositionInLine = prevPosition;
 01862                    _lineNumber = prevLineNumber;
 01863                    _totalConsumed = prevTotalConsumed;
 01864                    goto RollBack;
 1865                }
 01866                goto Done;
 1867            }
 01868            else if (_tokenType == JsonTokenType.StartArray)
 01869            {
 01870                Debug.Assert(first != JsonConstants.CloseBracket);
 01871                if (!ConsumeValueMultiSegment(first))
 01872                {
 01873                    goto RollBack;
 1874                }
 01875                goto Done;
 1876            }
 01877            else if (_tokenType == JsonTokenType.PropertyName)
 01878            {
 01879                if (!ConsumeValueMultiSegment(first))
 01880                {
 01881                    goto RollBack;
 1882                }
 01883                goto Done;
 1884            }
 1885            else
 01886            {
 01887                Debug.Assert(_tokenType == JsonTokenType.EndArray || _tokenType == JsonTokenType.EndObject);
 01888                if (_inObject)
 01889                {
 01890                    Debug.Assert(first != JsonConstants.CloseBrace);
 01891                    if (first != JsonConstants.Quote)
 01892                    {
 01893                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 1894                    }
 1895
 01896                    if (ConsumePropertyNameMultiSegment())
 01897                    {
 01898                        goto Done;
 1899                    }
 1900                    else
 01901                    {
 01902                        goto RollBack;
 1903                    }
 1904                }
 1905                else
 01906                {
 01907                    Debug.Assert(first != JsonConstants.CloseBracket);
 1908
 01909                    if (ConsumeValueMultiSegment(first))
 01910                    {
 01911                        goto Done;
 1912                    }
 1913                    else
 01914                    {
 01915                        goto RollBack;
 1916                    }
 1917                }
 1918            }
 1919
 01920        Done:
 01921            return ConsumeTokenResult.Success;
 1922
 01923        RollBack:
 01924            return ConsumeTokenResult.NotEnoughDataRollBackState;
 01925        }
 1926
 1927        private bool SkipAllCommentsMultiSegment(scoped ref byte marker)
 1401928        {
 1401929            while (marker == JsonConstants.Slash)
 61930            {
 61931                if (SkipOrConsumeCommentMultiSegmentWithRollback())
 01932                {
 01933                    if (!HasMoreDataMultiSegment())
 01934                    {
 01935                        goto IncompleteNoRollback;
 1936                    }
 1937
 01938                    marker = _buffer[_consumed];
 1939
 1940                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01941                    if (marker <= JsonConstants.Space)
 01942                    {
 01943                        SkipWhiteSpaceMultiSegment();
 01944                        if (!HasMoreDataMultiSegment())
 01945                        {
 01946                            goto IncompleteNoRollback;
 1947                        }
 01948                        marker = _buffer[_consumed];
 01949                    }
 01950                }
 1951                else
 01952                {
 01953                    goto IncompleteNoRollback;
 1954                }
 01955            }
 1341956            return true;
 1957
 01958        IncompleteNoRollback:
 01959            return false;
 1341960        }
 1961
 1962        private bool SkipAllCommentsMultiSegment(scoped ref byte marker, ExceptionResource resource)
 01963        {
 01964            while (marker == JsonConstants.Slash)
 01965            {
 01966                if (SkipOrConsumeCommentMultiSegmentWithRollback())
 01967                {
 1968                    // The next character must be a start of a property name or value.
 01969                    if (!HasMoreDataMultiSegment(resource))
 01970                    {
 01971                        goto IncompleteRollback;
 1972                    }
 1973
 01974                    marker = _buffer[_consumed];
 1975
 1976                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01977                    if (marker <= JsonConstants.Space)
 01978                    {
 01979                        SkipWhiteSpaceMultiSegment();
 1980                        // The next character must be a start of a property name or value.
 01981                        if (!HasMoreDataMultiSegment(resource))
 01982                        {
 01983                            goto IncompleteRollback;
 1984                        }
 01985                        marker = _buffer[_consumed];
 01986                    }
 01987                }
 1988                else
 01989                {
 01990                    goto IncompleteRollback;
 1991                }
 01992            }
 01993            return true;
 1994
 01995        IncompleteRollback:
 01996            return false;
 01997        }
 1998
 1999        private ConsumeTokenResult ConsumeNextTokenUntilAfterAllCommentsAreSkippedMultiSegment(byte marker)
 1402000        {
 1402001            if (!SkipAllCommentsMultiSegment(ref marker))
 02002            {
 02003                goto IncompleteNoRollback;
 2004            }
 2005
 1342006            TokenStartIndex = BytesConsumed;
 2007
 1342008            if (_tokenType == JsonTokenType.StartObject)
 02009            {
 02010                if (marker == JsonConstants.CloseBrace)
 02011                {
 02012                    EndObject();
 02013                }
 2014                else
 02015                {
 02016                    if (marker != JsonConstants.Quote)
 02017                    {
 02018                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 2019                    }
 2020
 02021                    long prevTotalConsumed = _totalConsumed;
 02022                    int prevConsumed = _consumed;
 02023                    long prevPosition = _bytePositionInLine;
 02024                    long prevLineNumber = _lineNumber;
 02025                    SequencePosition copy = _currentPosition;
 02026                    if (!ConsumePropertyNameMultiSegment())
 02027                    {
 2028                        // roll back potential changes
 02029                        _consumed = prevConsumed;
 02030                        _tokenType = JsonTokenType.StartObject;
 02031                        _bytePositionInLine = prevPosition;
 02032                        _lineNumber = prevLineNumber;
 02033                        _totalConsumed = prevTotalConsumed;
 02034                        _currentPosition = copy;
 02035                        goto IncompleteNoRollback;
 2036                    }
 02037                    goto Done;
 2038                }
 02039            }
 1342040            else if (_tokenType == JsonTokenType.StartArray)
 02041            {
 02042                if (marker == JsonConstants.CloseBracket)
 02043                {
 02044                    EndArray();
 02045                }
 2046                else
 02047                {
 02048                    if (!ConsumeValueMultiSegment(marker))
 02049                    {
 02050                        goto IncompleteNoRollback;
 2051                    }
 02052                    goto Done;
 2053                }
 02054            }
 1342055            else if (_tokenType == JsonTokenType.PropertyName)
 02056            {
 02057                if (!ConsumeValueMultiSegment(marker))
 02058                {
 02059                    goto IncompleteNoRollback;
 2060                }
 02061                goto Done;
 2062            }
 1342063            else if (_bitStack.CurrentDepth == 0)
 1162064            {
 1162065                if (_readerOptions.AllowMultipleValues)
 02066                {
 02067                    return ReadFirstTokenMultiSegment(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoug
 2068                }
 2069
 1162070                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, marker);
 2071            }
 182072            else if (marker == JsonConstants.ListSeparator)
 02073            {
 02074                _consumed++;
 02075                _bytePositionInLine++;
 2076
 02077                if (_consumed >= (uint)_buffer.Length)
 02078                {
 02079                    if (IsLastSpan)
 02080                    {
 02081                        _consumed--;
 02082                        _bytePositionInLine--;
 02083                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 2084                    }
 02085                    if (!GetNextSpan())
 02086                    {
 02087                        if (IsLastSpan)
 02088                        {
 02089                            _consumed--;
 02090                            _bytePositionInLine--;
 02091                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrVa
 2092                        }
 02093                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 2094                    }
 02095                }
 02096                marker = _buffer[_consumed];
 2097
 2098                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 02099                if (marker <= JsonConstants.Space)
 02100                {
 02101                    SkipWhiteSpaceMultiSegment();
 2102                    // The next character must be a start of a property name or value.
 02103                    if (!HasMoreDataMultiSegment(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 02104                    {
 02105                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 2106                    }
 02107                    marker = _buffer[_consumed];
 02108                }
 2109
 02110                if (!SkipAllCommentsMultiSegment(ref marker, ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 02111                {
 02112                    goto IncompleteRollback;
 2113                }
 2114
 02115                TokenStartIndex = BytesConsumed;
 2116
 02117                if (_inObject)
 02118                {
 02119                    if (marker != JsonConstants.Quote)
 02120                    {
 02121                        if (marker == JsonConstants.CloseBrace)
 02122                        {
 02123                            if (_readerOptions.AllowTrailingCommas)
 02124                            {
 02125                                EndObject();
 02126                                goto Done;
 2127                            }
 02128                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 2129                        }
 2130
 02131                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 2132                    }
 02133                    return ConsumePropertyNameMultiSegment() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnough
 2134                }
 2135                else
 02136                {
 02137                    if (marker == JsonConstants.CloseBracket)
 02138                    {
 02139                        if (_readerOptions.AllowTrailingCommas)
 02140                        {
 02141                            EndArray();
 02142                            goto Done;
 2143                        }
 02144                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 2145                    }
 02146                    return ConsumeValueMultiSegment(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughD
 2147                }
 2148            }
 182149            else if (marker == JsonConstants.CloseBrace)
 02150            {
 02151                EndObject();
 02152            }
 182153            else if (marker == JsonConstants.CloseBracket)
 02154            {
 02155                EndArray();
 02156            }
 2157            else
 182158            {
 182159                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.FoundInvalidCharacter, marker);
 2160            }
 2161
 02162        Done:
 02163            return ConsumeTokenResult.Success;
 02164        IncompleteNoRollback:
 02165            return ConsumeTokenResult.IncompleteNoRollBackNecessary;
 02166        IncompleteRollback:
 02167            return ConsumeTokenResult.NotEnoughDataRollBackState;
 02168        }
 2169
 2170        private bool SkipOrConsumeCommentMultiSegmentWithRollback()
 62171        {
 62172            long prevTotalConsumed = BytesConsumed;
 62173            SequencePosition start = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetInteger() + 
 62174            bool skipSucceeded = SkipCommentMultiSegment(out int tailBytesToIgnore);
 2175
 02176            if (skipSucceeded)
 02177            {
 02178                Debug.Assert(
 02179                    _readerOptions.CommentHandling == JsonCommentHandling.Allow ||
 02180                    _readerOptions.CommentHandling == JsonCommentHandling.Skip);
 2181
 02182                if (_readerOptions.CommentHandling == JsonCommentHandling.Allow)
 02183                {
 02184                    SequencePosition end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetIntege
 2185
 02186                    ReadOnlySequence<byte> commentSequence = _sequence.Slice(start, end);
 02187                    commentSequence = commentSequence.Slice(2, commentSequence.Length - 2 - tailBytesToIgnore);
 02188                    HasValueSequence = !commentSequence.IsSingleSegment;
 2189
 02190                    if (HasValueSequence)
 02191                    {
 02192                        ValueSequence = commentSequence;
 02193                    }
 2194                    else
 02195                    {
 02196                        ValueSpan = commentSequence.FirstSpan;
 02197                    }
 2198
 02199                    if (_tokenType != JsonTokenType.Comment)
 02200                    {
 02201                        _previousTokenType = _tokenType;
 02202                    }
 2203
 02204                    _tokenType = JsonTokenType.Comment;
 02205                }
 02206            }
 2207            else
 02208            {
 02209                _totalConsumed = prevTotalConsumed;
 2210                // Note: BytesConsumed = _totalConsumed + _consumed
 2211                // Changing _consumed and _totalConsumed to original values might not work correctly
 2212                // since _consumed is tracking position in the current sequence
 2213                // and current sequence might not be the same as we could've called GetNextSpan.
 2214                // Since we return false we do not expect these APIs to be called again
 2215                // so the values are ok to be slightly incorrect as long as the sum remains the same
 2216                // if we don't reset this value to zero the BytesConsumed might be reported incorrectly.
 02217                _consumed = 0;
 02218            }
 2219
 02220            return skipSucceeded;
 02221        }
 2222
 2223        private bool SkipCommentMultiSegment(out int tailBytesToIgnore)
 882224        {
 882225            _consumed++;
 882226            _bytePositionInLine++;
 2227            // Create local copy to avoid bounds checks.
 882228            ReadOnlySpan<byte> localBuffer = _buffer.Slice(_consumed);
 2229
 882230            if (localBuffer.Length == 0)
 412231            {
 412232                if (IsLastSpan)
 02233                {
 02234                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileReadingComm
 2235                }
 2236
 412237                if (!GetNextSpan())
 02238                {
 02239                    if (IsLastSpan)
 02240                    {
 02241                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileReading
 2242                    }
 2243
 02244                    tailBytesToIgnore = 0;
 02245                    return false;
 2246                }
 2247
 412248                localBuffer = _buffer;
 412249            }
 2250
 882251            byte marker = localBuffer[0];
 882252            if (marker is not (JsonConstants.Slash or JsonConstants.Asterisk))
 882253            {
 882254                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterAtStartOfComment, marke
 2255            }
 2256
 02257            bool multiLine = marker == JsonConstants.Asterisk;
 2258
 02259            _consumed++;
 02260            _bytePositionInLine++;
 02261            localBuffer = localBuffer.Slice(1);
 2262
 02263            if (localBuffer.Length == 0)
 02264            {
 02265                if (IsLastSpan)
 02266                {
 02267                    tailBytesToIgnore = 0;
 2268
 02269                    if (multiLine)
 02270                    {
 02271                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileReading
 2272                    }
 2273
 02274                    return true;
 2275                }
 2276
 02277                if (!GetNextSpan())
 02278                {
 02279                    tailBytesToIgnore = 0;
 2280
 02281                    if (IsLastSpan)
 02282                    {
 02283                        if (multiLine)
 02284                        {
 02285                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileRea
 2286                        }
 2287
 02288                        return true;
 2289                    }
 2290
 02291                    return false;
 2292                }
 2293
 02294                localBuffer = _buffer;
 02295            }
 2296
 02297            if (multiLine)
 02298            {
 02299                tailBytesToIgnore = 2;
 02300                return SkipMultiLineCommentMultiSegment(localBuffer);
 2301            }
 2302            else
 02303            {
 02304                return SkipSingleLineCommentMultiSegment(localBuffer, out tailBytesToIgnore);
 2305            }
 02306        }
 2307
 2308        private bool SkipSingleLineCommentMultiSegment(ReadOnlySpan<byte> localBuffer, out int tailBytesToSkip)
 02309        {
 02310            bool expectLF = false;
 02311            int dangerousLineSeparatorBytesConsumed = 0;
 02312            tailBytesToSkip = 0;
 2313
 02314            while (true)
 02315            {
 02316                if (expectLF)
 02317                {
 02318                    if (localBuffer[0] == JsonConstants.LineFeed)
 02319                    {
 02320                        tailBytesToSkip++;
 02321                        _consumed++;
 02322                    }
 2323
 02324                    break;
 2325                }
 2326
 02327                int idx = FindLineSeparatorMultiSegment(localBuffer, ref dangerousLineSeparatorBytesConsumed);
 02328                Debug.Assert(dangerousLineSeparatorBytesConsumed is >= 0 and <= 2);
 2329
 02330                if (idx != -1)
 02331                {
 02332                    tailBytesToSkip++;
 02333                    _consumed += idx + 1;
 02334                    _bytePositionInLine += idx + 1;
 2335
 02336                    if (localBuffer[idx] == JsonConstants.LineFeed)
 02337                    {
 02338                        break;
 2339                    }
 2340
 2341                    // If we are here, we have definintely found a \r. So now to check if \n follows.
 02342                    Debug.Assert(localBuffer[idx] == JsonConstants.CarriageReturn);
 2343
 02344                    if (idx < localBuffer.Length - 1)
 02345                    {
 02346                        if (localBuffer[idx + 1] == JsonConstants.LineFeed)
 02347                        {
 02348                            tailBytesToSkip++;
 02349                            _consumed++;
 02350                            _bytePositionInLine++;
 02351                        }
 2352
 02353                        break;
 2354                    }
 2355
 02356                    expectLF = true;
 02357                }
 2358                else
 02359                {
 02360                    _consumed += localBuffer.Length;
 02361                    _bytePositionInLine += localBuffer.Length;
 02362                }
 2363
 02364                if (IsLastSpan)
 02365                {
 02366                    if (expectLF)
 02367                    {
 02368                        break;
 2369                    }
 2370
 02371                    return true;
 2372                }
 2373
 02374                if (!GetNextSpan())
 02375                {
 02376                    if (IsLastSpan)
 02377                    {
 02378                        if (expectLF)
 02379                        {
 02380                            break;
 2381                        }
 2382
 02383                        return true;
 2384                    }
 2385                    else
 02386                    {
 02387                        return false;
 2388                    }
 2389                }
 2390
 02391                localBuffer = _buffer;
 02392            }
 2393
 02394            _bytePositionInLine = 0;
 02395            _lineNumber++;
 2396
 02397            return true;
 02398        }
 2399
 2400        private int FindLineSeparatorMultiSegment(ReadOnlySpan<byte> localBuffer, scoped ref int dangerousLineSeparatorB
 02401        {
 02402            Debug.Assert(dangerousLineSeparatorBytesConsumed >= 0 && dangerousLineSeparatorBytesConsumed <= 2);
 2403
 02404            if (dangerousLineSeparatorBytesConsumed != 0)
 02405            {
 02406                ThrowOnDangerousLineSeparatorMultiSegment(localBuffer, ref dangerousLineSeparatorBytesConsumed);
 2407
 02408                if (dangerousLineSeparatorBytesConsumed != 0)
 02409                {
 2410                    // this can only happen if localBuffer size is 1 and we have previously only consumed 1 byte
 2411                    // or localBuffer is 0
 02412                    Debug.Assert(dangerousLineSeparatorBytesConsumed >= 1 && dangerousLineSeparatorBytesConsumed <= 2 &&
 02413                    return -1;
 2414                }
 02415            }
 2416
 02417            int totalIdx = 0;
 02418            while (true)
 02419            {
 02420                int idx = localBuffer.IndexOfAny(JsonConstants.LineFeed, JsonConstants.CarriageReturn, JsonConstants.Sta
 02421                dangerousLineSeparatorBytesConsumed = 0;
 2422
 02423                if (idx == -1)
 02424                {
 02425                    return -1;
 2426                }
 2427
 02428                if (localBuffer[idx] != JsonConstants.StartingByteOfNonStandardSeparator)
 02429                {
 02430                    return totalIdx + idx;
 2431                }
 2432
 02433                int p = idx + 1;
 02434                localBuffer = localBuffer.Slice(p);
 02435                totalIdx += p;
 2436
 02437                dangerousLineSeparatorBytesConsumed++;
 02438                ThrowOnDangerousLineSeparatorMultiSegment(localBuffer, ref dangerousLineSeparatorBytesConsumed);
 2439
 02440                if (dangerousLineSeparatorBytesConsumed != 0)
 02441                {
 2442                    // this can only happen in the end of the local buffer
 02443                    Debug.Assert(localBuffer.Length < 2);
 02444                    return -1;
 2445                }
 02446            }
 02447        }
 2448
 2449        // assumes first byte (JsonConstants.UnexpectedEndOfLineSeparator) is already read
 2450        private void ThrowOnDangerousLineSeparatorMultiSegment(ReadOnlySpan<byte> localBuffer, scoped ref int dangerousL
 02451        {
 02452            Debug.Assert(dangerousLineSeparatorBytesConsumed == 1 || dangerousLineSeparatorBytesConsumed == 2);
 2453
 2454            // \u2028 and \u2029 are considered respectively line and paragraph separators
 2455            // UTF-8 representation for them is E2, 80, A8/A9
 2456            // we have already read E2 and maybe 80 we need to check for remaining 1 or 2 bytes
 2457
 02458            if (localBuffer.IsEmpty)
 02459            {
 02460                return;
 2461            }
 2462
 02463            if (dangerousLineSeparatorBytesConsumed == 1)
 02464            {
 02465                if (localBuffer[0] == 0x80)
 02466                {
 02467                    localBuffer = localBuffer.Slice(1);
 02468                    dangerousLineSeparatorBytesConsumed++;
 2469
 02470                    if (localBuffer.IsEmpty)
 02471                    {
 02472                        return;
 2473                    }
 02474                }
 2475                else
 02476                {
 2477                    // no match
 02478                    dangerousLineSeparatorBytesConsumed = 0;
 02479                    return;
 2480                }
 02481            }
 2482
 02483            if (dangerousLineSeparatorBytesConsumed == 2)
 02484            {
 02485                byte lastByte = localBuffer[0];
 02486                if (lastByte is 0xA8 or 0xA9)
 02487                {
 02488                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfLineSeparator);
 2489                }
 2490                else
 02491                {
 2492                    // no match
 02493                    dangerousLineSeparatorBytesConsumed = 0;
 02494                    return;
 2495                }
 2496            }
 02497        }
 2498
 2499        private bool SkipMultiLineCommentMultiSegment(ReadOnlySpan<byte> localBuffer)
 02500        {
 02501            bool expectSlash = false;
 02502            bool ignoreNextLfForLineTracking = false;
 2503
 02504            while (true)
 02505            {
 02506                Debug.Assert(localBuffer.Length > 0);
 2507
 02508                if (expectSlash)
 02509                {
 02510                    if (localBuffer[0] == JsonConstants.Slash)
 02511                    {
 02512                        _consumed++;
 02513                        _bytePositionInLine++;
 02514                        return true;
 2515                    }
 2516
 02517                    expectSlash = false;
 02518                }
 2519
 02520                if (ignoreNextLfForLineTracking)
 02521                {
 02522                    if (localBuffer[0] == JsonConstants.LineFeed)
 02523                    {
 02524                        _consumed++;
 02525                        localBuffer = localBuffer.Slice(1);
 02526                    }
 2527
 02528                    ignoreNextLfForLineTracking = false;
 02529                }
 2530
 02531                int idx = localBuffer.IndexOfAny(JsonConstants.Asterisk, JsonConstants.LineFeed, JsonConstants.CarriageR
 2532
 02533                if (idx != -1)
 02534                {
 02535                    int nextIdx = idx + 1;
 02536                    byte marker = localBuffer[idx];
 02537                    localBuffer = localBuffer.Slice(nextIdx);
 2538
 02539                    _consumed += nextIdx;
 2540
 02541                    switch (marker)
 2542                    {
 2543                        case JsonConstants.Asterisk:
 02544                            expectSlash = true;
 02545                            _bytePositionInLine += nextIdx;
 02546                            break;
 2547                        case JsonConstants.LineFeed:
 02548                            _bytePositionInLine = 0;
 02549                            _lineNumber++;
 02550                            break;
 2551                        default:
 02552                            Debug.Assert(marker == JsonConstants.CarriageReturn);
 02553                            _bytePositionInLine = 0;
 02554                            _lineNumber++;
 02555                            ignoreNextLfForLineTracking = true;
 02556                            break;
 2557                    }
 02558                }
 2559                else
 02560                {
 02561                    _consumed += localBuffer.Length;
 02562                    _bytePositionInLine += localBuffer.Length;
 02563                    localBuffer = ReadOnlySpan<byte>.Empty;
 02564                }
 2565
 02566                if (localBuffer.IsEmpty)
 02567                {
 02568                    if (IsLastSpan)
 02569                    {
 02570                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileReading
 2571                    }
 2572
 02573                    if (!GetNextSpan())
 02574                    {
 02575                        if (IsLastSpan)
 02576                        {
 02577                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileRea
 2578                        }
 2579                        else
 02580                        {
 02581                            return false;
 2582                        }
 2583                    }
 2584
 02585                    localBuffer = _buffer;
 02586                    Debug.Assert(!localBuffer.IsEmpty);
 02587                }
 02588            }
 02589        }
 2590
 2591        private PartialStateForRollback CaptureState() =>
 34322592            new PartialStateForRollback(_totalConsumed, _bytePositionInLine, _consumed, _currentPosition);
 2593
 2594        private readonly struct PartialStateForRollback
 2595        {
 2596            public readonly long _prevTotalConsumed;
 2597            public readonly long _prevBytePositionInLine;
 2598            public readonly int _prevConsumed;
 2599            public readonly SequencePosition _prevCurrentPosition;
 2600
 2601            public PartialStateForRollback(long totalConsumed, long bytePositionInLine, int consumed, SequencePosition c
 34322602            {
 34322603                _prevTotalConsumed = totalConsumed;
 34322604                _prevBytePositionInLine = bytePositionInLine;
 34322605                _prevConsumed = consumed;
 34322606                _prevCurrentPosition = currentPosition;
 34322607            }
 2608
 2609            public SequencePosition GetStartPosition(int offset = 0)
 13522610            {
 13522611                return new SequencePosition(_prevCurrentPosition.GetObject(), _prevCurrentPosition.GetInteger() + _prevC
 13522612            }
 2613        }
 2614    }
 2615}

D:\runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Reader\Utf8JsonReader.TryGet.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Buffers;
 5using System.Buffers.Text;
 6using System.Diagnostics;
 7using System.Diagnostics.CodeAnalysis;
 8using System.Runtime.CompilerServices;
 9
 10namespace System.Text.Json
 11{
 12    public ref partial struct Utf8JsonReader
 13    {
 14        /// <summary>
 15        /// Parses the current JSON token value from the source, unescaped, and transcoded as a <see cref="string"/>.
 16        /// </summary>
 17        /// <remarks>
 18        /// Returns <see langword="null" /> when <see cref="TokenType"/> is <see cref="JsonTokenType.Null"/>.
 19        /// </remarks>
 20        /// <exception cref="InvalidOperationException">
 21        /// Thrown if trying to get the value of the JSON token that is not a string
 22        /// (i.e. other than <see cref="JsonTokenType.String"/>, <see cref="JsonTokenType.PropertyName"/> or
 23        /// <see cref="JsonTokenType.Null"/>).
 24        /// <seealso cref="TokenType" />
 25        /// It will also throw when the JSON string contains invalid UTF-8 bytes, or invalid UTF-16 surrogates.
 26        /// </exception>
 27        public string? GetString()
 87828        {
 87829            if (TokenType == JsonTokenType.Null)
 030            {
 031                return null;
 32            }
 33
 87834            if (TokenType != JsonTokenType.String && TokenType != JsonTokenType.PropertyName)
 54635            {
 54636                ThrowHelper.ThrowInvalidOperationException_ExpectedString(TokenType);
 37            }
 38
 33239            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 40
 33241            if (ValueIsEscaped)
 042            {
 043                return JsonReaderHelper.GetUnescapedString(span);
 44            }
 45
 33246            Debug.Assert(!span.Contains(JsonConstants.BackSlash));
 33247            return JsonReaderHelper.TranscodeHelper(span);
 27248        }
 49
 50        /// <summary>
 51        /// Copies the current JSON token value from the source, unescaped as a UTF-8 string to the destination buffer.
 52        /// </summary>
 53        /// <param name="utf8Destination">A buffer to write the unescaped UTF-8 bytes into.</param>
 54        /// <returns>The number of bytes written to <paramref name="utf8Destination"/>.</returns>
 55        /// <remarks>
 56        /// Unlike <see cref="GetString"/>, this method does not support <see cref="JsonTokenType.Null"/>.
 57        ///
 58        /// This method will throw <see cref="ArgumentException"/> if the destination buffer is too small to hold the un
 59        /// An appropriately sized buffer can be determined by consulting the length of either <see cref="ValueSpan"/> o
 60        /// since the unescaped result is always less than or equal to the length of the encoded strings.
 61        /// </remarks>
 62        /// <exception cref="InvalidOperationException">
 63        /// Thrown if trying to get the value of the JSON token that is not a string
 64        /// (i.e. other than <see cref="JsonTokenType.String"/> or <see cref="JsonTokenType.PropertyName"/>.
 65        /// <seealso cref="TokenType" />
 66        /// It will also throw when the JSON string contains invalid UTF-8 bytes, or invalid UTF-16 surrogates.
 67        /// </exception>
 68        /// <exception cref="ArgumentException">The destination buffer is too small to hold the unescaped value.</except
 69        public readonly int CopyString(Span<byte> utf8Destination)
 36570        {
 36571            if (_tokenType is not (JsonTokenType.String or JsonTokenType.PropertyName))
 072            {
 073                ThrowHelper.ThrowInvalidOperationException_ExpectedString(_tokenType);
 74            }
 75
 36576            return CopyValue(utf8Destination);
 28777        }
 78
 79        internal readonly int CopyValue(Span<byte> utf8Destination)
 77580        {
 77581            Debug.Assert(_tokenType is JsonTokenType.String or JsonTokenType.PropertyName or JsonTokenType.Number);
 77582            Debug.Assert(_tokenType != JsonTokenType.Number || !ValueIsEscaped, "Numbers can't contain escape characters
 83
 84            int bytesWritten;
 85
 77586            if (ValueIsEscaped)
 087            {
 088                if (!TryCopyEscapedString(utf8Destination, out bytesWritten))
 089                {
 090                    utf8Destination.Slice(0, bytesWritten).Clear();
 091                    ThrowHelper.ThrowArgumentException_DestinationTooShort();
 92                }
 093            }
 94            else
 77595            {
 77596                if (HasValueSequence)
 19397                {
 19398                    ReadOnlySequence<byte> valueSequence = ValueSequence;
 19399                    valueSequence.CopyTo(utf8Destination);
 193100                    bytesWritten = (int)valueSequence.Length;
 193101                }
 102                else
 582103                {
 582104                    ReadOnlySpan<byte> valueSpan = ValueSpan;
 582105                    valueSpan.CopyTo(utf8Destination);
 582106                    bytesWritten = valueSpan.Length;
 582107                }
 775108            }
 109
 775110            JsonReaderHelper.ValidateUtf8(utf8Destination.Slice(0, bytesWritten));
 671111            return bytesWritten;
 671112        }
 113
 114        /// <summary>
 115        /// Copies the current JSON token value from the source, unescaped, and transcoded as a UTF-16 char buffer.
 116        /// </summary>
 117        /// <param name="destination">A buffer to write the transcoded UTF-16 characters into.</param>
 118        /// <returns>The number of characters written to <paramref name="destination"/>.</returns>
 119        /// <remarks>
 120        /// Unlike <see cref="GetString"/>, this method does not support <see cref="JsonTokenType.Null"/>.
 121        ///
 122        /// This method will throw <see cref="ArgumentException"/> if the destination buffer is too small to hold the un
 123        /// An appropriately sized buffer can be determined by consulting the length of either <see cref="ValueSpan"/> o
 124        /// since the unescaped result is always less than or equal to the length of the encoded strings.
 125        /// </remarks>
 126        /// <exception cref="InvalidOperationException">
 127        /// Thrown if trying to get the value of the JSON token that is not a string
 128        /// (i.e. other than <see cref="JsonTokenType.String"/> or <see cref="JsonTokenType.PropertyName"/>.
 129        /// <seealso cref="TokenType" />
 130        /// It will also throw when the JSON string contains invalid UTF-8 bytes, or invalid UTF-16 surrogates.
 131        /// </exception>
 132        /// <exception cref="ArgumentException">The destination buffer is too small to hold the unescaped value.</except
 133        public readonly int CopyString(Span<char> destination)
 166134        {
 166135            if (_tokenType is not (JsonTokenType.String or JsonTokenType.PropertyName))
 0136            {
 0137                ThrowHelper.ThrowInvalidOperationException_ExpectedString(_tokenType);
 138            }
 139
 166140            return CopyValue(destination);
 136141        }
 142
 143        internal readonly unsafe int CopyValue(Span<char> destination)
 166144        {
 166145            Debug.Assert(_tokenType is JsonTokenType.String or JsonTokenType.PropertyName or JsonTokenType.Number);
 166146            Debug.Assert(_tokenType != JsonTokenType.Number || !ValueIsEscaped, "Numbers can't contain escape characters
 147
 148            scoped ReadOnlySpan<byte> unescapedSource;
 166149            byte[]? rentedBuffer = null;
 150            int valueLength;
 151
 166152            if (ValueIsEscaped)
 0153            {
 0154                valueLength = ValueLength;
 155
 0156                Span<byte> unescapedBuffer = valueLength <= JsonConstants.StackallocByteThreshold ?
 0157                    stackalloc byte[JsonConstants.StackallocByteThreshold] :
 0158                    (rentedBuffer = ArrayPool<byte>.Shared.Rent(valueLength));
 159
 0160                bool success = TryCopyEscapedString(unescapedBuffer, out int bytesWritten);
 0161                Debug.Assert(success);
 0162                unescapedSource = unescapedBuffer.Slice(0, bytesWritten);
 0163            }
 164            else
 166165            {
 166166                if (HasValueSequence)
 40167                {
 40168                    ReadOnlySequence<byte> valueSequence = ValueSequence;
 40169                    valueLength = checked((int)valueSequence.Length);
 170
 40171                    Span<byte> intermediate = valueLength <= JsonConstants.StackallocByteThreshold ?
 40172                        stackalloc byte[JsonConstants.StackallocByteThreshold] :
 40173                        (rentedBuffer = ArrayPool<byte>.Shared.Rent(valueLength));
 174
 40175                    valueSequence.CopyTo(intermediate);
 40176                    unescapedSource = intermediate.Slice(0, valueLength);
 40177                }
 178                else
 126179                {
 126180                    unescapedSource = ValueSpan;
 126181                }
 166182            }
 183
 166184            int charsWritten = JsonReaderHelper.TranscodeHelper(unescapedSource, destination);
 185
 136186            if (rentedBuffer is not null)
 0187            {
 0188                new Span<byte>(rentedBuffer, 0, unescapedSource.Length).Clear();
 0189                ArrayPool<byte>.Shared.Return(rentedBuffer);
 0190            }
 191
 136192            return charsWritten;
 136193        }
 194
 195        private readonly unsafe bool TryCopyEscapedString(Span<byte> destination, out int bytesWritten)
 0196        {
 0197            Debug.Assert(_tokenType is JsonTokenType.String or JsonTokenType.PropertyName);
 0198            Debug.Assert(ValueIsEscaped);
 199
 0200            byte[]? rentedBuffer = null;
 201            scoped ReadOnlySpan<byte> source;
 202
 0203            if (HasValueSequence)
 0204            {
 0205                ReadOnlySequence<byte> valueSequence = ValueSequence;
 0206                int sequenceLength = checked((int)valueSequence.Length);
 207
 0208                Span<byte> intermediate = sequenceLength <= JsonConstants.StackallocByteThreshold ?
 0209                    stackalloc byte[JsonConstants.StackallocByteThreshold] :
 0210                    (rentedBuffer = ArrayPool<byte>.Shared.Rent(sequenceLength));
 211
 0212                valueSequence.CopyTo(intermediate);
 0213                source = intermediate.Slice(0, sequenceLength);
 0214            }
 215            else
 0216            {
 0217                source = ValueSpan;
 0218            }
 219
 0220            bool success = JsonReaderHelper.TryUnescape(source, destination, out bytesWritten);
 221
 0222            if (rentedBuffer is not null)
 0223            {
 0224                new Span<byte>(rentedBuffer, 0, source.Length).Clear();
 0225                ArrayPool<byte>.Shared.Return(rentedBuffer);
 0226            }
 227
 0228            Debug.Assert(bytesWritten < source.Length, "source buffer must contain at least one escape sequence");
 0229            return success;
 0230        }
 231
 232        /// <summary>
 233        /// Parses the current JSON token value from the source as a comment, transcoded as a <see cref="string"/>.
 234        /// </summary>
 235        /// <exception cref="InvalidOperationException">
 236        /// Thrown if trying to get the value of the JSON token that is not a comment.
 237        /// <seealso cref="TokenType" />
 238        /// </exception>
 239        public string GetComment()
 0240        {
 0241            if (TokenType != JsonTokenType.Comment)
 0242            {
 0243                ThrowHelper.ThrowInvalidOperationException_ExpectedComment(TokenType);
 244            }
 0245            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 0246            return JsonReaderHelper.TranscodeHelper(span);
 0247        }
 248
 249        /// <summary>
 250        /// Parses the current JSON token value from the source as a <see cref="bool"/>.
 251        /// Returns <see langword="true"/> if the TokenType is JsonTokenType.True and <see langword="false"/> if the Tok
 252        /// </summary>
 253        /// <exception cref="InvalidOperationException">
 254        /// Thrown if trying to get the value of a JSON token that is not a boolean (i.e. <see cref="JsonTokenType.True"
 255        /// <seealso cref="TokenType" />
 256        /// </exception>
 257        public bool GetBoolean()
 382258        {
 382259            JsonTokenType type = TokenType;
 382260            if (type == JsonTokenType.True)
 0261            {
 0262                Debug.Assert((HasValueSequence ? ValueSequence.ToArray() : ValueSpan).Length == 4);
 0263                return true;
 264            }
 382265            else if (type != JsonTokenType.False)
 382266            {
 382267                ThrowHelper.ThrowInvalidOperationException_ExpectedBoolean(TokenType);
 268                Debug.Fail("Throw helper should have thrown an exception.");
 269            }
 270
 0271            Debug.Assert((HasValueSequence ? ValueSequence.ToArray() : ValueSpan).Length == 5);
 0272            return false;
 0273        }
 274
 275        /// <summary>
 276        /// Parses the current JSON token value from the source and decodes the Base64 encoded JSON string as bytes.
 277        /// </summary>
 278        /// <exception cref="InvalidOperationException">
 279        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.String"/>.
 280        /// <seealso cref="TokenType" />
 281        /// </exception>
 282        /// <exception cref="FormatException">
 283        /// The JSON string contains data outside of the expected Base64 range, or if it contains invalid/more than two 
 284        /// or is incomplete (i.e. the JSON string length is not a multiple of 4).
 285        /// </exception>
 286        public byte[] GetBytesFromBase64()
 1128287        {
 1128288            if (!TryGetBytesFromBase64(out byte[]? value))
 198289            {
 198290                ThrowHelper.ThrowFormatException(DataType.Base64String);
 291            }
 120292            return value;
 120293        }
 294
 295        /// <summary>
 296        /// Parses the current JSON token value from the source as a <see cref="byte"/>.
 297        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="byte"/>
 298        /// value.
 299        /// Throws exceptions otherwise.
 300        /// </summary>
 301        /// <exception cref="InvalidOperationException">
 302        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 303        /// <seealso cref="TokenType" />
 304        /// </exception>
 305        /// <exception cref="FormatException">
 306        /// Thrown if the JSON token value is either of incorrect numeric format (for example if it contains a decimal o
 307        /// is written in scientific notation) or, it represents a number less than <see cref="byte.MinValue"/> or great
 308        /// than <see cref="byte.MaxValue"/>.
 309        /// </exception>
 310        public byte GetByte()
 328311        {
 328312            if (!TryGetByte(out byte value))
 4313            {
 4314                ThrowHelper.ThrowFormatException(NumericType.Byte);
 315            }
 64316            return value;
 64317        }
 318
 319        internal byte GetByteWithQuotes()
 54320        {
 54321            ReadOnlySpan<byte> span = GetUnescapedSpan();
 54322            if (!TryGetByteCore(out byte value, span))
 54323            {
 54324                ThrowHelper.ThrowFormatException(NumericType.Byte);
 325            }
 0326            return value;
 0327        }
 328
 329        /// <summary>
 330        /// Parses the current JSON token value from the source as an <see cref="sbyte"/>.
 331        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to an <see cref="sbyte"
 332        /// value.
 333        /// Throws exceptions otherwise.
 334        /// </summary>
 335        /// <exception cref="InvalidOperationException">
 336        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 337        /// <seealso cref="TokenType" />
 338        /// </exception>
 339        /// <exception cref="FormatException">
 340        /// Thrown if the JSON token value is either of incorrect numeric format (for example if it contains a decimal o
 341        /// is written in scientific notation) or, it represents a number less than <see cref="sbyte.MinValue"/> or grea
 342        /// than <see cref="sbyte.MaxValue"/>.
 343        /// </exception>
 344        [System.CLSCompliantAttribute(false)]
 345        public sbyte GetSByte()
 324346        {
 324347            if (!TryGetSByte(out sbyte value))
 4348            {
 4349                ThrowHelper.ThrowFormatException(NumericType.SByte);
 350            }
 64351            return value;
 64352        }
 353
 354        internal sbyte GetSByteWithQuotes()
 52355        {
 52356            ReadOnlySpan<byte> span = GetUnescapedSpan();
 52357            if (!TryGetSByteCore(out sbyte value, span))
 52358            {
 52359                ThrowHelper.ThrowFormatException(NumericType.SByte);
 360            }
 0361            return value;
 0362        }
 363
 364        /// <summary>
 365        /// Parses the current JSON token value from the source as a <see cref="short"/>.
 366        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="short"/
 367        /// value.
 368        /// Throws exceptions otherwise.
 369        /// </summary>
 370        /// <exception cref="InvalidOperationException">
 371        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 372        /// <seealso cref="TokenType" />
 373        /// </exception>
 374        /// <exception cref="FormatException">
 375        /// Thrown if the JSON token value is either of incorrect numeric format (for example if it contains a decimal o
 376        /// is written in scientific notation) or, it represents a number less than <see cref="short.MinValue"/> or grea
 377        /// than <see cref="short.MaxValue"/>.
 378        /// </exception>
 379        public short GetInt16()
 324380        {
 324381            if (!TryGetInt16(out short value))
 0382            {
 0383                ThrowHelper.ThrowFormatException(NumericType.Int16);
 384            }
 68385            return value;
 68386        }
 387
 388        internal short GetInt16WithQuotes()
 52389        {
 52390            ReadOnlySpan<byte> span = GetUnescapedSpan();
 52391            if (!TryGetInt16Core(out short value, span))
 52392            {
 52393                ThrowHelper.ThrowFormatException(NumericType.Int16);
 394            }
 0395            return value;
 0396        }
 397
 398        /// <summary>
 399        /// Parses the current JSON token value from the source as an <see cref="int"/>.
 400        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to an <see cref="int"/>
 401        /// value.
 402        /// Throws exceptions otherwise.
 403        /// </summary>
 404        /// <exception cref="InvalidOperationException">
 405        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 406        /// <seealso cref="TokenType" />
 407        /// </exception>
 408        /// <exception cref="FormatException">
 409        /// Thrown if the JSON token value is either of incorrect numeric format (for example if it contains a decimal o
 410        /// is written in scientific notation) or, it represents a number less than <see cref="int.MinValue"/> or greate
 411        /// than <see cref="int.MaxValue"/>.
 412        /// </exception>
 413        public int GetInt32()
 538414        {
 538415            if (!TryGetInt32(out int value))
 0416            {
 0417                ThrowHelper.ThrowFormatException(NumericType.Int32);
 418            }
 112419            return value;
 112420        }
 421
 422        internal int GetInt32WithQuotes()
 76423        {
 76424            ReadOnlySpan<byte> span = GetUnescapedSpan();
 76425            if (!TryGetInt32Core(out int value, span))
 76426            {
 76427                ThrowHelper.ThrowFormatException(NumericType.Int32);
 428            }
 0429            return value;
 0430        }
 431
 432        /// <summary>
 433        /// Parses the current JSON token value from the source as a <see cref="long"/>.
 434        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="long"/>
 435        /// value.
 436        /// Throws exceptions otherwise.
 437        /// </summary>
 438        /// <exception cref="InvalidOperationException">
 439        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 440        /// <seealso cref="TokenType" />
 441        /// </exception>
 442        /// <exception cref="FormatException">
 443        /// Thrown if the JSON token value is either of incorrect numeric format (for example if it contains a decimal o
 444        /// is written in scientific notation) or, it represents a number less than <see cref="long.MinValue"/> or great
 445        /// than <see cref="long.MaxValue"/>.
 446        /// </exception>
 447        public long GetInt64()
 338448        {
 338449            if (!TryGetInt64(out long value))
 0450            {
 0451                ThrowHelper.ThrowFormatException(NumericType.Int64);
 452            }
 70453            return value;
 70454        }
 455
 456        internal long GetInt64WithQuotes()
 52457        {
 52458            ReadOnlySpan<byte> span = GetUnescapedSpan();
 52459            if (!TryGetInt64Core(out long value, span))
 52460            {
 52461                ThrowHelper.ThrowFormatException(NumericType.Int64);
 462            }
 0463            return value;
 0464        }
 465
 466        /// <summary>
 467        /// Parses the current JSON token value from the source as a <see cref="ushort"/>.
 468        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="ushort"
 469        /// value.
 470        /// Throws exceptions otherwise.
 471        /// </summary>
 472        /// <exception cref="InvalidOperationException">
 473        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 474        /// <seealso cref="TokenType" />
 475        /// </exception>
 476        /// <exception cref="FormatException">
 477        /// Thrown if the JSON token value is either of incorrect numeric format (for example if it contains a decimal o
 478        /// is written in scientific notation) or, it represents a number less than <see cref="ushort.MinValue"/> or gre
 479        /// than <see cref="ushort.MaxValue"/>.
 480        /// </exception>
 481        [System.CLSCompliantAttribute(false)]
 482        public ushort GetUInt16()
 324483        {
 324484            if (!TryGetUInt16(out ushort value))
 0485            {
 0486                ThrowHelper.ThrowFormatException(NumericType.UInt16);
 487            }
 68488            return value;
 68489        }
 490
 491        internal ushort GetUInt16WithQuotes()
 52492        {
 52493            ReadOnlySpan<byte> span = GetUnescapedSpan();
 52494            if (!TryGetUInt16Core(out ushort value, span))
 52495            {
 52496                ThrowHelper.ThrowFormatException(NumericType.UInt16);
 497            }
 0498            return value;
 0499        }
 500
 501        /// <summary>
 502        /// Parses the current JSON token value from the source as a <see cref="uint"/>.
 503        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="uint"/>
 504        /// value.
 505        /// Throws exceptions otherwise.
 506        /// </summary>
 507        /// <exception cref="InvalidOperationException">
 508        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 509        /// <seealso cref="TokenType" />
 510        /// </exception>
 511        /// <exception cref="FormatException">
 512        /// Thrown if the JSON token value is either of incorrect numeric format (for example if it contains a decimal o
 513        /// is written in scientific notation) or, it represents a number less than <see cref="uint.MinValue"/> or great
 514        /// than <see cref="uint.MaxValue"/>.
 515        /// </exception>
 516        [System.CLSCompliantAttribute(false)]
 517        public uint GetUInt32()
 324518        {
 324519            if (!TryGetUInt32(out uint value))
 0520            {
 0521                ThrowHelper.ThrowFormatException(NumericType.UInt32);
 522            }
 68523            return value;
 68524        }
 525
 526        internal uint GetUInt32WithQuotes()
 52527        {
 52528            ReadOnlySpan<byte> span = GetUnescapedSpan();
 52529            if (!TryGetUInt32Core(out uint value, span))
 52530            {
 52531                ThrowHelper.ThrowFormatException(NumericType.UInt32);
 532            }
 0533            return value;
 0534        }
 535
 536        /// <summary>
 537        /// Parses the current JSON token value from the source as a <see cref="ulong"/>.
 538        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="ulong"/
 539        /// value.
 540        /// Throws exceptions otherwise.
 541        /// </summary>
 542        /// <exception cref="InvalidOperationException">
 543        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 544        /// <seealso cref="TokenType" />
 545        /// </exception>
 546        /// <exception cref="FormatException">
 547        /// Thrown if the JSON token value is either of incorrect numeric format (for example if it contains a decimal o
 548        /// is written in scientific notation) or, it represents a number less than <see cref="ulong.MinValue"/> or grea
 549        /// than <see cref="ulong.MaxValue"/>.
 550        /// </exception>
 551        [System.CLSCompliantAttribute(false)]
 552        public ulong GetUInt64()
 324553        {
 324554            if (!TryGetUInt64(out ulong value))
 0555            {
 0556                ThrowHelper.ThrowFormatException(NumericType.UInt64);
 557            }
 68558            return value;
 68559        }
 560
 561        internal ulong GetUInt64WithQuotes()
 52562        {
 52563            ReadOnlySpan<byte> span = GetUnescapedSpan();
 52564            if (!TryGetUInt64Core(out ulong value, span))
 52565            {
 52566                ThrowHelper.ThrowFormatException(NumericType.UInt64);
 567            }
 0568            return value;
 0569        }
 570
 571        /// <summary>
 572        /// Parses the current JSON token value from the source as a <see cref="float"/>.
 573        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="float"/
 574        /// value.
 575        /// Throws exceptions otherwise.
 576        /// </summary>
 577        /// <exception cref="InvalidOperationException">
 578        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 579        /// <seealso cref="TokenType" />
 580        /// </exception>
 581        /// <exception cref="FormatException">
 582        /// On any framework that is not .NET Core 3.0 or higher, thrown if the JSON token value represents a number les
 583        /// than <see cref="float.MaxValue"/>.
 584        /// </exception>
 585        public float GetSingle()
 324586        {
 324587            if (!TryGetSingle(out float value))
 0588            {
 0589                ThrowHelper.ThrowFormatException(NumericType.Single);
 590            }
 68591            return value;
 68592        }
 593
 594        internal float GetSingleWithQuotes()
 52595        {
 52596            ReadOnlySpan<byte> span = GetUnescapedSpan();
 597
 52598            if (JsonReaderHelper.TryGetFloatingPointConstant(span, out float value))
 0599            {
 0600                return value;
 601            }
 602
 603            // NETCOREAPP implementation of the TryParse method above permits case-insensitive variants of the
 604            // float constants "NaN", "Infinity", "-Infinity". This differs from the NETFRAMEWORK implementation.
 605            // The following logic reconciles the two implementations to enforce consistent behavior.
 52606            if (!(Utf8Parser.TryParse(span, out value, out int bytesConsumed)
 52607                  && span.Length == bytesConsumed
 52608                  && float.IsFinite(value)))
 52609            {
 52610                ThrowHelper.ThrowFormatException(NumericType.Single);
 611            }
 612
 0613            return value;
 0614        }
 615
 616        internal float GetSingleFloatingPointConstant()
 0617        {
 0618            ReadOnlySpan<byte> span = GetUnescapedSpan();
 619
 0620            if (!JsonReaderHelper.TryGetFloatingPointConstant(span, out float value))
 0621            {
 0622                ThrowHelper.ThrowFormatException(NumericType.Single);
 623            }
 624
 0625            return value;
 0626        }
 627
 628        /// <summary>
 629        /// Parses the current JSON token value from the source as a <see cref="double"/>.
 630        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="double"
 631        /// value.
 632        /// Throws exceptions otherwise.
 633        /// </summary>
 634        /// <exception cref="InvalidOperationException">
 635        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 636        /// <seealso cref="TokenType" />
 637        /// </exception>
 638        /// <exception cref="FormatException">
 639        /// On any framework that is not .NET Core 3.0 or higher, thrown if the JSON token value represents a number les
 640        /// than <see cref="double.MaxValue"/>.
 641        /// </exception>
 642        public double GetDouble()
 330643        {
 330644            if (!TryGetDouble(out double value))
 0645            {
 0646                ThrowHelper.ThrowFormatException(NumericType.Double);
 647            }
 68648            return value;
 68649        }
 650
 651        internal double GetDoubleWithQuotes()
 58652        {
 58653            ReadOnlySpan<byte> span = GetUnescapedSpan();
 654
 58655            if (JsonReaderHelper.TryGetFloatingPointConstant(span, out double value))
 0656            {
 0657                return value;
 658            }
 659
 660            // NETCOREAPP implementation of the TryParse method above permits case-insensitive variants of the
 661            // float constants "NaN", "Infinity", "-Infinity". This differs from the NETFRAMEWORK implementation.
 662            // The following logic reconciles the two implementations to enforce consistent behavior.
 58663            if (!(Utf8Parser.TryParse(span, out value, out int bytesConsumed)
 58664                  && span.Length == bytesConsumed
 58665                  && double.IsFinite(value)))
 58666            {
 58667                ThrowHelper.ThrowFormatException(NumericType.Double);
 668            }
 669
 0670            return value;
 0671        }
 672
 673        internal double GetDoubleFloatingPointConstant()
 0674        {
 0675            ReadOnlySpan<byte> span = GetUnescapedSpan();
 676
 0677            if (!JsonReaderHelper.TryGetFloatingPointConstant(span, out double value))
 0678            {
 0679                ThrowHelper.ThrowFormatException(NumericType.Double);
 680            }
 681
 0682            return value;
 0683        }
 684
 685        /// <summary>
 686        /// Parses the current JSON token value from the source as a <see cref="decimal"/>.
 687        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="decimal
 688        /// value.
 689        /// Throws exceptions otherwise.
 690        /// </summary>
 691        /// <exception cref="InvalidOperationException">
 692        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 693        /// <seealso cref="TokenType" />
 694        /// </exception>
 695        /// <exception cref="FormatException">
 696        /// Thrown if the JSON token value represents a number less than <see cref="decimal.MinValue"/> or greater
 697        /// than <see cref="decimal.MaxValue"/>.
 698        /// </exception>
 699        public decimal GetDecimal()
 410700        {
 410701            if (!TryGetDecimal(out decimal value))
 0702            {
 0703                ThrowHelper.ThrowFormatException(NumericType.Decimal);
 704            }
 96705            return value;
 96706        }
 707
 708        internal decimal GetDecimalWithQuotes()
 54709        {
 54710            ReadOnlySpan<byte> span = GetUnescapedSpan();
 54711            if (!TryGetDecimalCore(out decimal value, span))
 54712            {
 54713                ThrowHelper.ThrowFormatException(NumericType.Decimal);
 714            }
 0715            return value;
 0716        }
 717
 718        /// <summary>
 719        /// Parses the current JSON token value from the source as a <see cref="DateTime"/>.
 720        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="DateTim
 721        /// value.
 722        /// Throws exceptions otherwise.
 723        /// </summary>
 724        /// <exception cref="InvalidOperationException">
 725        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.String"/>.
 726        /// <seealso cref="TokenType" />
 727        /// </exception>
 728        /// <exception cref="FormatException">
 729        /// Thrown if the JSON token value is of an unsupported format. Only a subset of ISO 8601 formats are supported.
 730        /// </exception>
 731        public DateTime GetDateTime()
 380732        {
 380733            if (!TryGetDateTime(out DateTime value))
 106734            {
 106735                ThrowHelper.ThrowFormatException(DataType.DateTime);
 736            }
 737
 0738            return value;
 0739        }
 740
 741        internal DateTime GetDateTimeNoValidation()
 0742        {
 0743            if (!TryGetDateTimeCore(out DateTime value))
 0744            {
 0745                ThrowHelper.ThrowFormatException(DataType.DateTime);
 746            }
 747
 0748            return value;
 0749        }
 750
 751        /// <summary>
 752        /// Parses the current JSON token value from the source as a <see cref="DateTimeOffset"/>.
 753        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="DateTim
 754        /// value.
 755        /// Throws exceptions otherwise.
 756        /// </summary>
 757        /// <exception cref="InvalidOperationException">
 758        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.String"/>.
 759        /// <seealso cref="TokenType" />
 760        /// </exception>
 761        /// <exception cref="FormatException">
 762        /// Thrown if the JSON token value is of an unsupported format. Only a subset of ISO 8601 formats are supported.
 763        /// </exception>
 764        public DateTimeOffset GetDateTimeOffset()
 386765        {
 386766            if (!TryGetDateTimeOffset(out DateTimeOffset value))
 112767            {
 112768                ThrowHelper.ThrowFormatException(DataType.DateTimeOffset);
 769            }
 770
 0771            return value;
 0772        }
 773
 774        internal DateTimeOffset GetDateTimeOffsetNoValidation()
 0775        {
 0776            if (!TryGetDateTimeOffsetCore(out DateTimeOffset value))
 0777            {
 0778                ThrowHelper.ThrowFormatException(DataType.DateTimeOffset);
 779            }
 780
 0781            return value;
 0782        }
 783
 784        /// <summary>
 785        /// Parses the current JSON token value from the source as a <see cref="Guid"/>.
 786        /// Returns the value if the entire UTF-8 encoded token value can be successfully parsed to a <see cref="Guid"/>
 787        /// value.
 788        /// Throws exceptions otherwise.
 789        /// </summary>
 790        /// <exception cref="InvalidOperationException">
 791        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.String"/>.
 792        /// <seealso cref="TokenType" />
 793        /// </exception>
 794        /// <exception cref="FormatException">
 795        /// Thrown if the JSON token value is of an unsupported format for a Guid.
 796        /// </exception>
 797        public Guid GetGuid()
 382798        {
 382799            if (!TryGetGuid(out Guid value))
 110800            {
 110801                ThrowHelper.ThrowFormatException(DataType.Guid);
 802            }
 803
 0804            return value;
 0805        }
 806
 807        internal Guid GetGuidNoValidation()
 0808        {
 0809            if (!TryGetGuidCore(out Guid value))
 0810            {
 0811                ThrowHelper.ThrowFormatException(DataType.Guid);
 812            }
 813
 0814            return value;
 0815        }
 816
 817        /// <summary>
 818        /// Parses the current JSON token value from the source and decodes the Base64 encoded JSON string as bytes.
 819        /// Returns <see langword="true"/> if the entire token value is encoded as valid Base64 text and can be successf
 820        /// decoded to bytes.
 821        /// Returns <see langword="false"/> otherwise.
 822        /// </summary>
 823        /// <exception cref="InvalidOperationException">
 824        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.String"/>.
 825        /// <seealso cref="TokenType" />
 826        /// </exception>
 827        public bool TryGetBytesFromBase64([NotNullWhen(true)] out byte[]? value)
 1128828        {
 1128829            if (TokenType != JsonTokenType.String)
 810830            {
 810831                ThrowHelper.ThrowInvalidOperationException_ExpectedString(TokenType);
 832            }
 833
 318834            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 835
 318836            if (ValueIsEscaped)
 0837            {
 0838                return JsonReaderHelper.TryGetUnescapedBase64Bytes(span, out value);
 839            }
 840
 318841            Debug.Assert(!span.Contains(JsonConstants.BackSlash));
 318842            return JsonReaderHelper.TryDecodeBase64(span, out value);
 318843        }
 844
 845        /// <summary>
 846        /// Parses the current JSON token value from the source as a <see cref="byte"/>.
 847        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 848        /// parsed to a <see cref="byte"/> value.
 849        /// Returns <see langword="false"/> otherwise.
 850        /// </summary>
 851        /// <exception cref="InvalidOperationException">
 852        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 853        /// <seealso cref="TokenType" />
 854        /// </exception>
 855        public bool TryGetByte(out byte value)
 418856        {
 418857            if (TokenType != JsonTokenType.Number)
 260858            {
 260859                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 860            }
 861
 158862            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 158863            return TryGetByteCore(out value, span);
 158864        }
 865
 866        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 867        internal static bool TryGetByteCore(out byte value, ReadOnlySpan<byte> span)
 212868        {
 212869            if (Utf8Parser.TryParse(span, out byte tmp, out int bytesConsumed)
 212870                && span.Length == bytesConsumed)
 150871            {
 150872                value = tmp;
 150873                return true;
 874            }
 875
 62876            value = 0;
 62877            return false;
 212878        }
 879
 880        /// <summary>
 881        /// Parses the current JSON token value from the source as an <see cref="sbyte"/>.
 882        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 883        /// parsed to an <see cref="sbyte"/> value.
 884        /// Returns <see langword="false"/> otherwise.
 885        /// </summary>
 886        /// <exception cref="InvalidOperationException">
 887        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 888        /// <seealso cref="TokenType" />
 889        /// </exception>
 890        [System.CLSCompliantAttribute(false)]
 891        public bool TryGetSByte(out sbyte value)
 414892        {
 414893            if (TokenType != JsonTokenType.Number)
 256894            {
 256895                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 896            }
 897
 158898            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 158899            return TryGetSByteCore(out value, span);
 158900        }
 901
 902        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 903        internal static bool TryGetSByteCore(out sbyte value, ReadOnlySpan<byte> span)
 210904        {
 210905            if (Utf8Parser.TryParse(span, out sbyte tmp, out int bytesConsumed)
 210906                && span.Length == bytesConsumed)
 150907            {
 150908                value = tmp;
 150909                return true;
 910            }
 911
 60912            value = 0;
 60913            return false;
 210914        }
 915
 916        /// <summary>
 917        /// Parses the current JSON token value from the source as a <see cref="short"/>.
 918        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 919        /// parsed to a <see cref="short"/> value.
 920        /// Returns <see langword="false"/> otherwise.
 921        /// </summary>
 922        /// <exception cref="InvalidOperationException">
 923        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 924        /// <seealso cref="TokenType" />
 925        /// </exception>
 926        public bool TryGetInt16(out short value)
 414927        {
 414928            if (TokenType != JsonTokenType.Number)
 256929            {
 256930                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 931            }
 932
 158933            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 158934            return TryGetInt16Core(out value, span);
 158935        }
 936
 937        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 938        internal static bool TryGetInt16Core(out short value, ReadOnlySpan<byte> span)
 210939        {
 210940            if (Utf8Parser.TryParse(span, out short tmp, out int bytesConsumed)
 210941                && span.Length == bytesConsumed)
 158942            {
 158943                value = tmp;
 158944                return true;
 945            }
 946
 52947            value = 0;
 52948            return false;
 210949        }
 950
 951        /// <summary>
 952        /// Parses the current JSON token value from the source as an <see cref="int"/>.
 953        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 954        /// parsed to an <see cref="int"/> value.
 955        /// Returns <see langword="false"/> otherwise.
 956        /// </summary>
 957        /// <exception cref="InvalidOperationException">
 958        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 959        /// <seealso cref="TokenType" />
 960        /// </exception>
 961        public bool TryGetInt32(out int value)
 764962        {
 764963            if (TokenType != JsonTokenType.Number)
 426964            {
 426965                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 966            }
 967
 338968            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 338969            return TryGetInt32Core(out value, span);
 338970        }
 971
 972        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 973        internal static bool TryGetInt32Core(out int value, ReadOnlySpan<byte> span)
 414974        {
 414975            if (Utf8Parser.TryParse(span, out int tmp, out int bytesConsumed)
 414976                && span.Length == bytesConsumed)
 338977            {
 338978                value = tmp;
 338979                return true;
 980            }
 981
 76982            value = 0;
 76983            return false;
 414984        }
 985
 986        /// <summary>
 987        /// Parses the current JSON token value from the source as a <see cref="long"/>.
 988        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 989        /// parsed to a <see cref="long"/> value.
 990        /// Returns <see langword="false"/> otherwise.
 991        /// </summary>
 992        /// <exception cref="InvalidOperationException">
 993        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 994        /// <seealso cref="TokenType" />
 995        /// </exception>
 996        public bool TryGetInt64(out long value)
 428997        {
 428998            if (TokenType != JsonTokenType.Number)
 268999            {
 2681000                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1001            }
 1002
 1601003            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 1601004            return TryGetInt64Core(out value, span);
 1601005        }
 1006
 1007        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1008        internal static bool TryGetInt64Core(out long value, ReadOnlySpan<byte> span)
 2121009        {
 2121010            if (Utf8Parser.TryParse(span, out long tmp, out int bytesConsumed)
 2121011                && span.Length == bytesConsumed)
 1601012            {
 1601013                value = tmp;
 1601014                return true;
 1015            }
 1016
 521017            value = 0;
 521018            return false;
 2121019        }
 1020
 1021        /// <summary>
 1022        /// Parses the current JSON token value from the source as a <see cref="ushort"/>.
 1023        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 1024        /// parsed to a <see cref="ushort"/> value.
 1025        /// Returns <see langword="false"/> otherwise.
 1026        /// </summary>
 1027        /// <exception cref="InvalidOperationException">
 1028        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 1029        /// <seealso cref="TokenType" />
 1030        /// </exception>
 1031        [System.CLSCompliantAttribute(false)]
 1032        public bool TryGetUInt16(out ushort value)
 3241033        {
 3241034            if (TokenType != JsonTokenType.Number)
 2561035            {
 2561036                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1037            }
 1038
 681039            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 681040            return TryGetUInt16Core(out value, span);
 681041        }
 1042
 1043        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1044        internal static bool TryGetUInt16Core(out ushort value, ReadOnlySpan<byte> span)
 1201045        {
 1201046            if (Utf8Parser.TryParse(span, out ushort tmp, out int bytesConsumed)
 1201047                && span.Length == bytesConsumed)
 681048            {
 681049                value = tmp;
 681050                return true;
 1051            }
 1052
 521053            value = 0;
 521054            return false;
 1201055        }
 1056
 1057        /// <summary>
 1058        /// Parses the current JSON token value from the source as a <see cref="uint"/>.
 1059        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 1060        /// parsed to a <see cref="uint"/> value.
 1061        /// Returns <see langword="false"/> otherwise.
 1062        /// </summary>
 1063        /// <exception cref="InvalidOperationException">
 1064        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 1065        /// <seealso cref="TokenType" />
 1066        /// </exception>
 1067        [System.CLSCompliantAttribute(false)]
 1068        public bool TryGetUInt32(out uint value)
 3241069        {
 3241070            if (TokenType != JsonTokenType.Number)
 2561071            {
 2561072                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1073            }
 1074
 681075            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 681076            return TryGetUInt32Core(out value, span);
 681077        }
 1078
 1079        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1080        internal static bool TryGetUInt32Core(out uint value, ReadOnlySpan<byte> span)
 1201081        {
 1201082            if (Utf8Parser.TryParse(span, out uint tmp, out int bytesConsumed)
 1201083                && span.Length == bytesConsumed)
 681084            {
 681085                value = tmp;
 681086                return true;
 1087            }
 1088
 521089            value = 0;
 521090            return false;
 1201091        }
 1092
 1093        /// <summary>
 1094        /// Parses the current JSON token value from the source as a <see cref="ulong"/>.
 1095        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 1096        /// parsed to a <see cref="ulong"/> value.
 1097        /// Returns <see langword="false"/> otherwise.
 1098        /// </summary>
 1099        /// <exception cref="InvalidOperationException">
 1100        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 1101        /// <seealso cref="TokenType" />
 1102        /// </exception>
 1103        [System.CLSCompliantAttribute(false)]
 1104        public bool TryGetUInt64(out ulong value)
 3241105        {
 3241106            if (TokenType != JsonTokenType.Number)
 2561107            {
 2561108                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1109            }
 1110
 681111            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 681112            return TryGetUInt64Core(out value, span);
 681113        }
 1114
 1115        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1116        internal static bool TryGetUInt64Core(out ulong value, ReadOnlySpan<byte> span)
 1201117        {
 1201118            if (Utf8Parser.TryParse(span, out ulong tmp, out int bytesConsumed)
 1201119                && span.Length == bytesConsumed)
 681120            {
 681121                value = tmp;
 681122                return true;
 1123            }
 1124
 521125            value = 0;
 521126            return false;
 1201127        }
 1128
 1129        /// <summary>
 1130        /// Parses the current JSON token value from the source as a <see cref="float"/>.
 1131        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 1132        /// parsed to a <see cref="float"/> value.
 1133        /// Returns <see langword="false"/> otherwise.
 1134        /// </summary>
 1135        /// <exception cref="InvalidOperationException">
 1136        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 1137        /// <seealso cref="TokenType" />
 1138        /// </exception>
 1139        public bool TryGetSingle(out float value)
 4141140        {
 4141141            if (TokenType != JsonTokenType.Number)
 2561142            {
 2561143                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1144            }
 1145
 1581146            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 1147
 1581148            if (Utf8Parser.TryParse(span, out float tmp, out int bytesConsumed)
 1581149                && span.Length == bytesConsumed)
 1581150            {
 1581151                value = tmp;
 1581152                return true;
 1153            }
 1154
 01155            value = 0;
 01156            return false;
 1581157        }
 1158
 1159        /// <summary>
 1160        /// Parses the current JSON token value from the source as a <see cref="double"/>.
 1161        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 1162        /// parsed to a <see cref="double"/> value.
 1163        /// Returns <see langword="false"/> otherwise.
 1164        /// </summary>
 1165        /// <exception cref="InvalidOperationException">
 1166        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 1167        /// <seealso cref="TokenType" />
 1168        /// </exception>
 1169        public bool TryGetDouble(out double value)
 4201170        {
 4201171            if (TokenType != JsonTokenType.Number)
 2621172            {
 2621173                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1174            }
 1175
 1581176            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 1177
 1581178            if (Utf8Parser.TryParse(span, out double tmp, out int bytesConsumed)
 1581179                && span.Length == bytesConsumed)
 1581180            {
 1581181                value = tmp;
 1581182                return true;
 1183            }
 1184
 01185            value = 0;
 01186            return false;
 1581187        }
 1188
 1189        /// <summary>
 1190        /// Parses the current JSON token value from the source as a <see cref="decimal"/>.
 1191        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 1192        /// parsed to a <see cref="decimal"/> value.
 1193        /// Returns <see langword="false"/> otherwise.
 1194        /// </summary>
 1195        /// <exception cref="InvalidOperationException">
 1196        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.Number"/>.
 1197        /// <seealso cref="TokenType" />
 1198        /// </exception>
 1199        public bool TryGetDecimal(out decimal value)
 5001200        {
 5001201            if (TokenType != JsonTokenType.Number)
 3141202            {
 3141203                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1204            }
 1205
 1861206            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 1861207            return TryGetDecimalCore(out value, span);
 1861208        }
 1209
 1210        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1211        internal static bool TryGetDecimalCore(out decimal value, ReadOnlySpan<byte> span)
 2401212        {
 2401213            if (Utf8Parser.TryParse(span, out decimal tmp, out int bytesConsumed)
 2401214                && span.Length == bytesConsumed)
 1861215            {
 1861216                value = tmp;
 1861217                return true;
 1218            }
 1219
 541220            value = 0;
 541221            return false;
 2401222        }
 1223
 1224        /// <summary>
 1225        /// Parses the current JSON token value from the source as a <see cref="DateTime"/>.
 1226        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 1227        /// parsed to a <see cref="DateTime"/> value.
 1228        /// Returns <see langword="false"/> otherwise.
 1229        /// </summary>
 1230        /// <exception cref="InvalidOperationException">
 1231        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.String"/>.
 1232        /// <seealso cref="TokenType" />
 1233        /// </exception>
 1234        public bool TryGetDateTime(out DateTime value)
 4861235        {
 4861236            if (TokenType != JsonTokenType.String)
 2741237            {
 2741238                ThrowHelper.ThrowInvalidOperationException_ExpectedString(TokenType);
 1239            }
 1240
 2121241            return TryGetDateTimeCore(out value);
 2121242        }
 1243
 1244        internal unsafe bool TryGetDateTimeCore(out DateTime value)
 2121245        {
 1246            scoped ReadOnlySpan<byte> span;
 1247
 2121248            if (HasValueSequence)
 501249            {
 501250                long sequenceLength = ValueSequence.Length;
 501251                if (!JsonHelpers.IsInRangeInclusive(sequenceLength, JsonConstants.MinimumDateTimeParseLength, JsonConsta
 501252                {
 501253                    value = default;
 501254                    return false;
 1255                }
 1256
 01257                Span<byte> stackSpan = stackalloc byte[JsonConstants.MaximumEscapedDateTimeOffsetParseLength];
 01258                ValueSequence.CopyTo(stackSpan);
 01259                span = stackSpan.Slice(0, (int)sequenceLength);
 01260            }
 1261            else
 1621262            {
 1621263                span = ValueSpan;
 1621264            }
 1265
 1621266            return JsonReaderHelper.TryGetValue(span, ValueIsEscaped, out value);
 2121267        }
 1268
 1269        /// <summary>
 1270        /// Parses the current JSON token value from the source as a <see cref="DateTimeOffset"/>.
 1271        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 1272        /// parsed to a <see cref="DateTimeOffset"/> value.
 1273        /// Returns <see langword="false"/> otherwise.
 1274        /// </summary>
 1275        /// <exception cref="InvalidOperationException">
 1276        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.String"/>.
 1277        /// <seealso cref="TokenType" />
 1278        /// </exception>
 1279        public bool TryGetDateTimeOffset(out DateTimeOffset value)
 3861280        {
 3861281            if (TokenType != JsonTokenType.String)
 2741282            {
 2741283                ThrowHelper.ThrowInvalidOperationException_ExpectedString(TokenType);
 1284            }
 1285
 1121286            return TryGetDateTimeOffsetCore(out value);
 1121287        }
 1288
 1289        internal unsafe bool TryGetDateTimeOffsetCore(out DateTimeOffset value)
 1121290        {
 1291            scoped ReadOnlySpan<byte> span;
 1292
 1121293            if (HasValueSequence)
 261294            {
 261295                long sequenceLength = ValueSequence.Length;
 261296                if (!JsonHelpers.IsInRangeInclusive(sequenceLength, JsonConstants.MinimumDateTimeParseLength, JsonConsta
 261297                {
 261298                    value = default;
 261299                    return false;
 1300                }
 1301
 01302                Span<byte> stackSpan = stackalloc byte[JsonConstants.MaximumEscapedDateTimeOffsetParseLength];
 01303                ValueSequence.CopyTo(stackSpan);
 01304                span = stackSpan.Slice(0, (int)sequenceLength);
 01305            }
 1306            else
 861307            {
 861308                span = ValueSpan;
 861309            }
 1310
 861311            return JsonReaderHelper.TryGetValue(span, ValueIsEscaped, out value);
 1121312        }
 1313
 1314        /// <summary>
 1315        /// Parses the current JSON token value from the source as a <see cref="Guid"/>.
 1316        /// Returns <see langword="true"/> if the entire UTF-8 encoded token value can be successfully
 1317        /// parsed to a <see cref="Guid"/> value. Only supports <see cref="Guid"/> values with hyphens
 1318        /// and without any surrounding decorations.
 1319        /// Returns <see langword="false"/> otherwise.
 1320        /// </summary>
 1321        /// <exception cref="InvalidOperationException">
 1322        /// Thrown if trying to get the value of a JSON token that is not a <see cref="JsonTokenType.String"/>.
 1323        /// <seealso cref="TokenType" />
 1324        /// </exception>
 1325        public bool TryGetGuid(out Guid value)
 3821326        {
 3821327            if (TokenType != JsonTokenType.String)
 2721328            {
 2721329                ThrowHelper.ThrowInvalidOperationException_ExpectedString(TokenType);
 1330            }
 1331
 1101332            return TryGetGuidCore(out value);
 1101333        }
 1334
 1335        internal unsafe bool TryGetGuidCore(out Guid value)
 1101336        {
 1337            scoped ReadOnlySpan<byte> span;
 1338
 1101339            if (HasValueSequence)
 261340            {
 261341                long sequenceLength = ValueSequence.Length;
 261342                if (sequenceLength > JsonConstants.MaximumEscapedGuidLength)
 01343                {
 01344                    value = default;
 01345                    return false;
 1346                }
 1347
 261348                Span<byte> stackSpan = stackalloc byte[JsonConstants.MaximumEscapedGuidLength];
 261349                ValueSequence.CopyTo(stackSpan);
 261350                span = stackSpan.Slice(0, (int)sequenceLength);
 261351            }
 1352            else
 841353            {
 841354                span = ValueSpan;
 841355            }
 1356
 1101357            return JsonReaderHelper.TryGetValue(span, ValueIsEscaped, out value);
 1101358        }
 1359    }
 1360}

Methods/Properties

IsLastSpan()
OriginalSequence()
OriginalSpan()
ValueLength()
AllowMultipleValues()
ValueSpan()
BytesConsumed()
TokenStartIndex()
CurrentDepth()
IsInArray()
TokenType()
HasValueSequence()
ValueIsEscaped()
IsFinalBlock()
ValueSequence()
Position()
CurrentState()
.ctor(System.ReadOnlySpan`1<System.Byte>,System.Boolean,System.Text.Json.JsonReaderState)
.ctor(System.ReadOnlySpan`1<System.Byte>,System.Text.Json.JsonReaderOptions)
Read()
Skip()
SkipHelper()
TrySkip()
TrySkipPartial(System.Int32)
ValueTextEquals(System.ReadOnlySpan`1<System.Byte>)
ValueTextEquals(System.String)
TextEqualsHelper(System.ReadOnlySpan`1<System.Byte>)
ValueTextEquals(System.ReadOnlySpan`1<System.Char>)
CompareToSequence(System.ReadOnlySpan`1<System.Byte>)
UnescapeAndCompare(System.ReadOnlySpan`1<System.Byte>)
UnescapeSequenceAndCompare(System.ReadOnlySpan`1<System.Byte>)
IsTokenTypeString(System.Text.Json.JsonTokenType)
MatchNotPossible(System.Int32)
MatchNotPossibleSequence(System.Int32)
StartObject()
EndObject()
StartArray()
EndArray()
UpdateBitStackOnEndToken()
ReadSingleSegment()
HasMoreData()
HasMoreData(System.Text.Json.ExceptionResource)
ReadFirstToken(System.Byte)
SkipWhiteSpace()
ConsumeValue(System.Byte)
ConsumeLiteral(System.ReadOnlySpan`1<System.Byte>,System.Text.Json.JsonTokenType)
CheckLiteral(System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>)
ThrowInvalidLiteral(System.ReadOnlySpan`1<System.Byte>)
ConsumeNumber()
ConsumePropertyName()
ConsumeString()
ConsumeStringAndValidate(System.ReadOnlySpan`1<System.Byte>,System.Int32)
ValidateHexDigits(System.ReadOnlySpan`1<System.Byte>,System.Int32)
TryGetNumber(System.ReadOnlySpan`1<System.Byte>,System.Int32&)
ConsumeNegativeSign(System.ReadOnlySpan`1<System.Byte>&,System.Int32&)
ConsumeZero(System.ReadOnlySpan`1<System.Byte>&,System.Int32&)
ConsumeIntegerDigits(System.ReadOnlySpan`1<System.Byte>&,System.Int32&)
ConsumeDecimalDigits(System.ReadOnlySpan`1<System.Byte>&,System.Int32&)
ConsumeSign(System.ReadOnlySpan`1<System.Byte>&,System.Int32&)
ConsumeNextTokenOrRollback(System.Byte)
ConsumeNextToken(System.Byte)
ConsumeNextTokenFromLastNonCommentToken()
SkipAllComments(System.Byte&)
SkipAllComments(System.Byte&,System.Text.Json.ExceptionResource)
ConsumeNextTokenUntilAfterAllCommentsAreSkipped(System.Byte)
SkipComment()
SkipSingleLineComment(System.ReadOnlySpan`1<System.Byte>,System.Int32&)
FindLineSeparator(System.ReadOnlySpan`1<System.Byte>)
ThrowOnDangerousLineSeparator(System.ReadOnlySpan`1<System.Byte>)
SkipMultiLineComment(System.ReadOnlySpan`1<System.Byte>,System.Int32&)
ConsumeComment()
ConsumeSingleLineComment(System.ReadOnlySpan`1<System.Byte>,System.Int32)
ConsumeMultiLineComment(System.ReadOnlySpan`1<System.Byte>,System.Int32)
DebuggerDisplay()
DebugTokenType()
GetUnescapedSpan()
.ctor(System.Buffers.ReadOnlySequence`1<System.Byte>,System.Boolean,System.Text.Json.JsonReaderState)
.ctor(System.Buffers.ReadOnlySequence`1<System.Byte>,System.Text.Json.JsonReaderOptions)
ReadMultiSegment()
ValidateStateAtEndOfData()
HasMoreDataMultiSegment()
HasMoreDataMultiSegment(System.Text.Json.ExceptionResource)
GetNextSpan()
ReadFirstTokenMultiSegment(System.Byte)
SkipWhiteSpaceMultiSegment()
ConsumeValueMultiSegment(System.Byte)
ConsumeLiteralMultiSegment(System.ReadOnlySpan`1<System.Byte>,System.Text.Json.JsonTokenType)
CheckLiteralMultiSegment(System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.Int32&)
AmountToWrite(System.ReadOnlySpan`1<System.Byte>,System.Int64,System.ReadOnlySpan`1<System.Byte>,System.Int32)
FindMismatch(System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>)
GetInvalidLiteralMultiSegment(System.ReadOnlySpan`1<System.Byte>)
ConsumeNumberMultiSegment()
ConsumePropertyNameMultiSegment()
ConsumeStringMultiSegment()
ConsumeStringNextSegment()
ConsumeStringAndValidateMultiSegment(System.ReadOnlySpan`1<System.Byte>,System.Int32)
RollBackState(System.Text.Json.Utf8JsonReader/PartialStateForRollback&,System.Boolean)
TryGetNumberMultiSegment(System.ReadOnlySpan`1<System.Byte>,System.Int32&)
ConsumeNegativeSignMultiSegment(System.ReadOnlySpan`1<System.Byte>&,System.Int32&,System.Text.Json.Utf8JsonReader/PartialStateForRollback&)
ConsumeZeroMultiSegment(System.ReadOnlySpan`1<System.Byte>&,System.Int32&,System.Text.Json.Utf8JsonReader/PartialStateForRollback&)
ConsumeIntegerDigitsMultiSegment(System.ReadOnlySpan`1<System.Byte>&,System.Int32&)
ConsumeDecimalDigitsMultiSegment(System.ReadOnlySpan`1<System.Byte>&,System.Int32&,System.Text.Json.Utf8JsonReader/PartialStateForRollback&)
ConsumeSignMultiSegment(System.ReadOnlySpan`1<System.Byte>&,System.Int32&,System.Text.Json.Utf8JsonReader/PartialStateForRollback&)
ConsumeNextTokenOrRollbackMultiSegment(System.Byte)
ConsumeNextTokenMultiSegment(System.Byte)
ConsumeNextTokenFromLastNonCommentTokenMultiSegment()
SkipAllCommentsMultiSegment(System.Byte&)
SkipAllCommentsMultiSegment(System.Byte&,System.Text.Json.ExceptionResource)
ConsumeNextTokenUntilAfterAllCommentsAreSkippedMultiSegment(System.Byte)
SkipOrConsumeCommentMultiSegmentWithRollback()
SkipCommentMultiSegment(System.Int32&)
SkipSingleLineCommentMultiSegment(System.ReadOnlySpan`1<System.Byte>,System.Int32&)
FindLineSeparatorMultiSegment(System.ReadOnlySpan`1<System.Byte>,System.Int32&)
ThrowOnDangerousLineSeparatorMultiSegment(System.ReadOnlySpan`1<System.Byte>,System.Int32&)
SkipMultiLineCommentMultiSegment(System.ReadOnlySpan`1<System.Byte>)
CaptureState()
.ctor(System.Int64,System.Int64,System.Int32,System.SequencePosition)
GetStartPosition(System.Int32)
GetString()
CopyString(System.Span`1<System.Byte>)
CopyValue(System.Span`1<System.Byte>)
CopyString(System.Span`1<System.Char>)
CopyValue(System.Span`1<System.Char>)
TryCopyEscapedString(System.Span`1<System.Byte>,System.Int32&)
GetComment()
GetBoolean()
GetBytesFromBase64()
GetByte()
GetByteWithQuotes()
GetSByte()
GetSByteWithQuotes()
GetInt16()
GetInt16WithQuotes()
GetInt32()
GetInt32WithQuotes()
GetInt64()
GetInt64WithQuotes()
GetUInt16()
GetUInt16WithQuotes()
GetUInt32()
GetUInt32WithQuotes()
GetUInt64()
GetUInt64WithQuotes()
GetSingle()
GetSingleWithQuotes()
GetSingleFloatingPointConstant()
GetDouble()
GetDoubleWithQuotes()
GetDoubleFloatingPointConstant()
GetDecimal()
GetDecimalWithQuotes()
GetDateTime()
GetDateTimeNoValidation()
GetDateTimeOffset()
GetDateTimeOffsetNoValidation()
GetGuid()
GetGuidNoValidation()
TryGetBytesFromBase64(System.Byte[]&)
TryGetByte(System.Byte&)
TryGetByteCore(System.Byte&,System.ReadOnlySpan`1<System.Byte>)
TryGetSByte(System.SByte&)
TryGetSByteCore(System.SByte&,System.ReadOnlySpan`1<System.Byte>)
TryGetInt16(System.Int16&)
TryGetInt16Core(System.Int16&,System.ReadOnlySpan`1<System.Byte>)
TryGetInt32(System.Int32&)
TryGetInt32Core(System.Int32&,System.ReadOnlySpan`1<System.Byte>)
TryGetInt64(System.Int64&)
TryGetInt64Core(System.Int64&,System.ReadOnlySpan`1<System.Byte>)
TryGetUInt16(System.UInt16&)
TryGetUInt16Core(System.UInt16&,System.ReadOnlySpan`1<System.Byte>)
TryGetUInt32(System.UInt32&)
TryGetUInt32Core(System.UInt32&,System.ReadOnlySpan`1<System.Byte>)
TryGetUInt64(System.UInt64&)
TryGetUInt64Core(System.UInt64&,System.ReadOnlySpan`1<System.Byte>)
TryGetSingle(System.Single&)
TryGetDouble(System.Double&)
TryGetDecimal(System.Decimal&)
TryGetDecimalCore(System.Decimal&,System.ReadOnlySpan`1<System.Byte>)
TryGetDateTime(System.DateTime&)
TryGetDateTimeCore(System.DateTime&)
TryGetDateTimeOffset(System.DateTimeOffset&)
TryGetDateTimeOffsetCore(System.DateTimeOffset&)
TryGetGuid(System.Guid&)
TryGetGuidCore(System.Guid&)