< Summary

Line coverage
47%
Covered lines: 1894
Uncovered lines: 2114
Coverable lines: 4008
Total lines: 6583
Line coverage: 47.2%
Branch coverage
42%
Covered branches: 751
Total branches: 1771
Branch coverage: 42.4%
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()80%101076.47%
File 1: TrySkip()25%4446.15%
File 1: TrySkipPartial(...)0%18180%
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()50%2290%
File 1: EndObject()0%880%
File 1: StartArray()50%2290%
File 1: EndArray()37.5%8850%
File 1: UpdateBitStackOnEndToken()100%11100%
File 1: ReadSingleSegment()83.33%242473.23%
File 1: HasMoreData()68.75%161666.66%
File 1: HasMoreData(...)0%440%
File 1: ReadFirstToken(...)93.75%161694.73%
File 1: SkipWhiteSpace()100%1212100%
File 1: ConsumeValue(...)75%484885.93%
File 1: ConsumeLiteral(...)83.33%6653.84%
File 1: CheckLiteral(...)33.33%121244%
File 1: ThrowInvalidLiteral(...)100%44100%
File 1: ConsumeNumber()50%121261.9%
File 1: ConsumePropertyName()0%101012%
File 1: ConsumeString()83.33%6696%
File 1: ConsumeStringAndValidate(...)26.92%262627.41%
File 1: ValidateHexDigits(...)0%660%
File 1: TryGetNumber(...)66.66%424275%
File 1: ConsumeNegativeSign(...)62.5%8870%
File 1: ConsumeZero(...)50%141460%
File 1: ConsumeIntegerDigits(...)90%101090.47%
File 1: ConsumeDecimalDigits(...)50%6662.5%
File 1: ConsumeSign(...)35.71%141437.03%
File 1: ConsumeNextTokenOrRollback(...)0%4435%
File 1: ConsumeNextToken(...)30.76%525234.14%
File 1: ConsumeNextTokenFromLastNonCommentToken()0%88880%
File 1: SkipAllComments(...)20%101024%
File 1: SkipAllComments(...)0%10100%
File 1: ConsumeNextTokenUntilAfterAllCommentsAreSkipped(...)10.34%58588.69%
File 1: SkipComment()50%8866.66%
File 1: SkipSingleLineComment(...)58.33%121272.97%
File 1: FindLineSeparator(...)75%4476.47%
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()83.33%242472.72%
File 2: ValidateStateAtEndOfData()0%12120%
File 2: HasMoreDataMultiSegment()64.28%141457.89%
File 2: HasMoreDataMultiSegment(...)0%880%
File 2: GetNextSpan()60%101088.88%
File 2: ReadFirstTokenMultiSegment(...)93.75%161694.44%
File 2: SkipWhiteSpaceMultiSegment()75%4483.33%
File 2: ConsumeValueMultiSegment(...)68.33%606075.94%
File 2: ConsumeLiteralMultiSegment(...)62.5%8842.85%
File 2: CheckLiteralMultiSegment(...)61.11%181871.21%
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(...)100%44100%
File 2: ConsumeNumberMultiSegment()50%121260%
File 2: ConsumePropertyNameMultiSegment()0%101012%
File 2: ConsumeStringMultiSegment()83.33%6688.46%
File 2: ConsumeStringNextSegment()31.57%383841.12%
File 2: ConsumeStringAndValidateMultiSegment(...)17.5%404019.29%
File 2: RollBackState(...)50%2266.66%
File 2: TryGetNumberMultiSegment(...)68.18%444473.46%
File 2: ConsumeNegativeSignMultiSegment(...)66.66%121273.52%
File 2: ConsumeZeroMultiSegment(...)54.54%222267.5%
File 2: ConsumeIntegerDigitsMultiSegment(...)81.81%222284.48%
File 2: ConsumeDecimalDigitsMultiSegment(...)60%101067.85%
File 2: ConsumeSignMultiSegment(...)36.36%222236%
File 2: ConsumeNextTokenOrRollbackMultiSegment(...)0%4437.5%
File 2: ConsumeNextTokenMultiSegment(...)33.92%565635.55%
File 2: ConsumeNextTokenFromLastNonCommentTokenMultiSegment()0%90900%
File 2: SkipAllCommentsMultiSegment(...)20%101024%
File 2: SkipAllCommentsMultiSegment(...)0%10100%
File 2: ConsumeNextTokenUntilAfterAllCommentsAreSkippedMultiSegment(...)9.67%62627.87%
File 2: SkipOrConsumeCommentMultiSegmentWithRollback()0%101011.42%
File 2: SkipCommentMultiSegment(...)50%262651.85%
File 2: SkipSingleLineCommentMultiSegment(...)54.16%242459.67%
File 2: FindLineSeparatorMultiSegment(...)31.25%161646.87%
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(...)66.66%6666.66%
File 3: CopyValue(...)66.66%121276.92%
File 3: CopyString(...)66.66%6666.66%
File 3: CopyValue(...)56.25%161664.86%
File 3: TryCopyEscapedString(...)0%10100%
File 3: GetComment()0%440%
File 3: GetBoolean()25%8850%
File 3: GetBytesFromBase64()100%22100%
File 3: GetByte()100%2285.71%
File 3: GetByteWithQuotes()100%2287.5%
File 3: GetSByte()100%2285.71%
File 3: GetSByteWithQuotes()100%2287.5%
File 3: GetInt16()100%2285.71%
File 3: GetInt16WithQuotes()100%2287.5%
File 3: GetInt32()100%2285.71%
File 3: GetInt32WithQuotes()100%2287.5%
File 3: GetInt64()100%2285.71%
File 3: GetInt64WithQuotes()100%2287.5%
File 3: GetUInt16()100%2285.71%
File 3: GetUInt16WithQuotes()100%2287.5%
File 3: GetUInt32()100%2285.71%
File 3: GetUInt32WithQuotes()100%2287.5%
File 3: GetUInt64()100%2285.71%
File 3: GetUInt64WithQuotes()100%2287.5%
File 3: GetSingle()50%2257.14%
File 3: GetSingleWithQuotes()87.5%8876.92%
File 3: GetSingleFloatingPointConstant()0%220%
File 3: GetDouble()50%2257.14%
File 3: GetDoubleWithQuotes()87.5%8876.92%
File 3: GetDoubleFloatingPointConstant()0%220%
File 3: GetDecimal()100%2285.71%
File 3: GetDecimalWithQuotes()100%2287.5%
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(...)100%44100%
File 3: TryGetDateTimeOffset(...)100%22100%
File 3: TryGetDateTimeOffsetCore(...)100%44100%
File 3: TryGetGuid(...)100%22100%
File 3: TryGetGuidCore(...)75%4482.35%

File(s)

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\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
 1279149        private readonly bool IsLastSpan => _isFinalBlock && (!_isMultiSegment || _isLastSegment);
 50
 98451        internal readonly ReadOnlySequence<byte> OriginalSequence => _sequence;
 52
 49253        internal readonly ReadOnlySpan<byte> OriginalSpan => _sequence.IsEmpty ? _buffer : default;
 54
 320855        internal readonly int ValueLength => HasValueSequence ? checked((int)ValueSequence.Length) : ValueSpan.Length;
 56
 459857        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>
 16336771        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
 12161080            {
 81#if DEBUG
 12161082                if (!_isInputSequence)
 4461583                {
 4461584                    Debug.Assert(_totalConsumed == 0);
 4461585                }
 86#endif
 12161087                return _totalConsumed + _consumed;
 12161088            }
 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>
 13560899        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
 28244108            {
 28244109                int readerDepth = _bitStack.CurrentDepth;
 28244110                if (TokenType is JsonTokenType.StartArray or JsonTokenType.StartObject)
 11668111                {
 11668112                    Debug.Assert(readerDepth >= 1);
 11668113                    readerDepth--;
 11668114                }
 28244115                return readerDepth;
 28244116            }
 117        }
 118
 1538119        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>
 151174124        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>
 118967133        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>
 264568139        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>
 52382146        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>
 101765160        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() != 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>
 116968187        public readonly JsonReaderState CurrentState => new JsonReaderState
 116968188        (
 116968189            lineNumber: _lineNumber,
 116968190            bytePositionInLine: _bytePositionInLine,
 116968191            inObject: _inObject,
 116968192            isNotPrimitive: _isNotPrimitive,
 116968193            valueIsEscaped: ValueIsEscaped,
 116968194            trailingCommaBeforeComment: _trailingCommaBeforeComment,
 116968195            tokenType: _tokenType,
 116968196            previousTokenType: _previousTokenType,
 116968197            readerOptions: _readerOptions,
 116968198            bitStack: _bitStack
 116968199        );
 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)
 30072214        {
 30072215            _buffer = jsonData;
 216
 30072217            _isFinalBlock = isFinalBlock;
 30072218            _isInputSequence = false;
 219
 30072220            _lineNumber = state._lineNumber;
 30072221            _bytePositionInLine = state._bytePositionInLine;
 30072222            _inObject = state._inObject;
 30072223            _isNotPrimitive = state._isNotPrimitive;
 30072224            ValueIsEscaped = state._valueIsEscaped;
 30072225            _trailingCommaBeforeComment = state._trailingCommaBeforeComment;
 30072226            _tokenType = state._tokenType;
 30072227            _previousTokenType = state._previousTokenType;
 30072228            _readerOptions = state._readerOptions;
 30072229            if (_readerOptions.MaxDepth == 0)
 710230            {
 710231                _readerOptions.MaxDepth = JsonReaderOptions.DefaultMaxDepth;  // If max depth is not set, revert to the 
 710232            }
 30072233            _bitStack = state._bitStack;
 234
 30072235            _consumed = 0;
 30072236            TokenStartIndex = 0;
 30072237            _totalConsumed = 0;
 30072238            _isLastSegment = _isFinalBlock;
 30072239            _isMultiSegment = false;
 240
 30072241            ValueSpan = ReadOnlySpan<byte>.Empty;
 242
 30072243            _currentPosition = default;
 30072244            _nextPosition = default;
 30072245            _sequence = default;
 30072246            HasValueSequence = false;
 30072247            ValueSequence = ReadOnlySequence<byte>.Empty;
 30072248        }
 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)
 28266            : this(jsonData, isFinalBlock: true, new JsonReaderState(options))
 28267        {
 28268        }
 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()
 68398279        {
 68398280            bool retVal = _isMultiSegment ? ReadMultiSegment() : ReadSingleSegment();
 281
 32148282            if (!retVal)
 2328283            {
 2328284                if (_isFinalBlock && TokenType is JsonTokenType.None && !_readerOptions.AllowMultipleValues)
 738285                {
 738286                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedJsonTokens);
 287                }
 1590288            }
 31410289            return retVal;
 31410290        }
 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()
 1380323        {
 1380324            Debug.Assert(_isFinalBlock);
 325
 1380326            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
 1380334            if (TokenType is JsonTokenType.StartObject or JsonTokenType.StartArray)
 1380335            {
 1380336                int depth = CurrentDepth;
 337                do
 2558338                {
 2558339                    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.
 1316342                    Debug.Assert(result);
 1316343                }
 1316344                while (depth < CurrentDepth);
 138345            }
 138346        }
 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()
 1380372        {
 1380373            if (_isFinalBlock)
 1380374            {
 1380375                SkipHelper();
 138376                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;
 138388        }
 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 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 != 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.First.Span, 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 == JsonTokenType.PropertyName || tokenType == 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()
 82740        {
 82741            if (_bitStack.CurrentDepth >= _readerOptions.MaxDepth)
 0742                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ObjectDepthTooLarge);
 743
 82744            _bitStack.PushTrue();
 745
 82746            ValueSpan = _buffer.Slice(_consumed, 1);
 82747            _consumed++;
 82748            _bytePositionInLine++;
 82749            _tokenType = JsonTokenType.StartObject;
 82750            _inObject = true;
 82751        }
 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()
 1354774        {
 1354775            if (_bitStack.CurrentDepth >= _readerOptions.MaxDepth)
 0776                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ArrayDepthTooLarge);
 777
 1354778            _bitStack.PushFalse();
 779
 1354780            ValueSpan = _buffer.Slice(_consumed, 1);
 1354781            _consumed++;
 1354782            _bytePositionInLine++;
 1354783            _tokenType = JsonTokenType.StartArray;
 1354784            _inObject = false;
 1354785        }
 786
 787        private void EndArray()
 332788        {
 332789            if (_inObject || _bitStack.CurrentDepth <= 0)
 0790                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.MismatchedObjectArray, JsonConstants.Cl
 791
 332792            if (_trailingCommaBeforeComment)
 0793            {
 0794                if (!_readerOptions.AllowTrailingCommas)
 0795                {
 0796                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeArrayE
 797                }
 0798                _trailingCommaBeforeComment = false;
 0799            }
 800
 332801            _tokenType = JsonTokenType.EndArray;
 332802            ValueSpan = _buffer.Slice(_consumed, 1);
 803
 332804            UpdateBitStackOnEndToken();
 332805        }
 806
 807        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 808        private void UpdateBitStackOnEndToken()
 332809        {
 332810            _consumed++;
 332811            _bytePositionInLine++;
 332812            _inObject = _bitStack.Pop();
 332813        }
 814
 815        private bool ReadSingleSegment()
 35682816        {
 35682817            bool retVal = false;
 35682818            ValueSpan = default;
 35682819            ValueIsEscaped = false;
 820
 35682821            if (!HasMoreData())
 1495822            {
 1495823                goto Done;
 824            }
 825
 34187826            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.
 34187832            if (first <= JsonConstants.Space)
 3871833            {
 3871834                SkipWhiteSpace();
 3871835                if (!HasMoreData())
 0836                {
 0837                    goto Done;
 838                }
 3871839                first = _buffer[_consumed];
 3871840            }
 841
 34187842            TokenStartIndex = _consumed;
 843
 34187844            if (_tokenType == JsonTokenType.None)
 30072845            {
 30072846                goto ReadFirstToken;
 847            }
 848
 4115849            if (first == JsonConstants.Slash)
 785850            {
 785851                retVal = ConsumeNextTokenOrRollback(first);
 0852                goto Done;
 853            }
 854
 3330855            if (_tokenType == JsonTokenType.StartObject)
 212856            {
 212857                if (first == JsonConstants.CloseBrace)
 0858                {
 0859                    EndObject();
 0860                }
 861                else
 212862                {
 212863                    if (first != JsonConstants.Quote)
 204864                    {
 204865                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 866                    }
 867
 8868                    int prevConsumed = _consumed;
 8869                    long prevPosition = _bytePositionInLine;
 8870                    long prevLineNumber = _lineNumber;
 8871                    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            }
 3118883            else if (_tokenType == JsonTokenType.StartArray)
 1495884            {
 1495885                if (first == JsonConstants.CloseBracket)
 235886                {
 235887                    EndArray();
 235888                }
 889                else
 1260890                {
 1260891                    retVal = ConsumeValue(first);
 717892                    goto Done;
 893                }
 235894            }
 1623895            else if (_tokenType == JsonTokenType.PropertyName)
 0896            {
 0897                retVal = ConsumeValue(first);
 0898                goto Done;
 899            }
 900            else
 1623901            {
 1623902                retVal = ConsumeNextTokenOrRollback(first);
 0903                goto Done;
 904            }
 905
 235906            retVal = true;
 907
 17557908        Done:
 17557909            return retVal;
 910
 30072911        ReadFirstToken:
 30072912            retVal = ReadFirstToken(first);
 15110913            goto Done;
 17557914        }
 915
 916        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 917        private bool HasMoreData()
 39594918        {
 39594919            if (_consumed >= (uint)_buffer.Length)
 1495920            {
 1495921                if (_isNotPrimitive && IsLastSpan)
 138922                {
 138923                    if (_bitStack.CurrentDepth != 0)
 0924                    {
 0925                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ZeroDepthAtEnd);
 926                    }
 927
 138928                    if (_readerOptions.CommentHandling == JsonCommentHandling.Allow && _tokenType == JsonTokenType.Comme
 0929                    {
 0930                        return false;
 931                    }
 932
 138933                    if (_tokenType is not JsonTokenType.EndArray and not JsonTokenType.EndObject)
 0934                    {
 0935                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidEndOfJsonNonPrimitive);
 936                    }
 138937                }
 1495938                return false;
 939            }
 38099940            return true;
 39594941        }
 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)
 30072961        {
 30072962            if (first == JsonConstants.OpenBrace)
 966963            {
 966964                _bitStack.SetFirstBit();
 966965                _tokenType = JsonTokenType.StartObject;
 966966                ValueSpan = _buffer.Slice(_consumed, 1);
 966967                _consumed++;
 966968                _bytePositionInLine++;
 966969                _inObject = true;
 966970                _isNotPrimitive = true;
 966971            }
 29106972            else if (first == JsonConstants.OpenBracket)
 3918973            {
 3918974                _bitStack.ResetFirstBit();
 3918975                _tokenType = JsonTokenType.StartArray;
 3918976                ValueSpan = _buffer.Slice(_consumed, 1);
 3918977                _consumed++;
 3918978                _bytePositionInLine++;
 3918979                _isNotPrimitive = true;
 3918980            }
 981            else
 25188982            {
 983                // Create local copy to avoid bounds checks.
 25188984                ReadOnlySpan<byte> localBuffer = _buffer;
 985
 25188986                if (JsonHelpers.IsDigit(first) || first == '-')
 4308987                {
 4308988                    if (!TryGetNumber(localBuffer.Slice(_consumed), out int numberOfBytes))
 0989                    {
 0990                        return false;
 991                    }
 3132992                    _tokenType = JsonTokenType.Number;
 3132993                    _consumed += numberOfBytes;
 3132994                    _bytePositionInLine += numberOfBytes;
 3132995                }
 20880996                else if (!ConsumeValue(first))
 369997                {
 369998                    return false;
 999                }
 1000
 98571001                _isNotPrimitive = _tokenType is JsonTokenType.StartObject or JsonTokenType.StartArray;
 1002                // Intentionally fall out of the if-block to return true
 98571003            }
 147411004            return true;
 151101005        }
 1006
 1007        private void SkipWhiteSpace()
 84511008        {
 1009            // Create local copy to avoid bounds checks.
 84511010            ReadOnlySpan<byte> localBuffer = _buffer;
 204431011            for (; _consumed < localBuffer.Length; _consumed++)
 138201012            {
 138201013                byte val = localBuffer[_consumed];
 1014
 1015                // JSON RFC 8259 section 2 says only these 4 characters count, not all of the Unicode definitions of whi
 138201016                if (val is not JsonConstants.Space and
 138201017                           not JsonConstants.CarriageReturn and
 138201018                           not JsonConstants.LineFeed and
 138201019                           not JsonConstants.Tab)
 78241020                {
 78241021                    break;
 1022                }
 1023
 59961024                if (val == JsonConstants.LineFeed)
 45041025                {
 45041026                    _lineNumber++;
 45041027                    _bytePositionInLine = 0;
 45041028                }
 1029                else
 14921030                {
 14921031                    _bytePositionInLine++;
 14921032                }
 59961033            }
 84511034        }
 1035
 1036        /// <summary>
 1037        /// This method contains the logic for processing the next value token and determining
 1038        /// what type of data it is.
 1039        /// </summary>
 1040        private bool ConsumeValue(byte marker)
 221801041        {
 223031042            while (true)
 223031043            {
 223031044                Debug.Assert((_trailingCommaBeforeComment && _readerOptions.CommentHandling == JsonCommentHandling.Allow
 223031045                Debug.Assert((_trailingCommaBeforeComment && marker != JsonConstants.Slash) || !_trailingCommaBeforeComm
 223031046                _trailingCommaBeforeComment = false;
 1047
 223031048                if (marker == JsonConstants.Quote)
 70781049                {
 70781050                    return ConsumeString();
 1051                }
 152251052                else if (marker == JsonConstants.OpenBrace)
 411053                {
 411054                    StartObject();
 411055                }
 151841056                else if (marker == JsonConstants.OpenBracket)
 6771057                {
 6771058                    StartArray();
 6771059                }
 145071060                else if (JsonHelpers.IsDigit(marker) || marker == '-')
 1661061                {
 1661062                    return ConsumeNumber();
 1063                }
 143411064                else if (marker == 'f')
 2101065                {
 2101066                    return ConsumeLiteral(JsonConstants.FalseValue, JsonTokenType.False);
 1067                }
 141311068                else if (marker == 't')
 1261069                {
 1261070                    return ConsumeLiteral(JsonConstants.TrueValue, JsonTokenType.True);
 1071                }
 140051072                else if (marker == 'n')
 1681073                {
 1681074                    return ConsumeLiteral(JsonConstants.NullValue, JsonTokenType.Null);
 1075                }
 1076                else
 138371077                {
 138371078                    switch (_readerOptions.CommentHandling)
 1079                    {
 1080                        case JsonCommentHandling.Disallow:
 114291081                            break;
 1082                        case JsonCommentHandling.Allow:
 01083                            if (marker == JsonConstants.Slash)
 01084                            {
 01085                                return ConsumeComment();
 1086                            }
 01087                            break;
 1088                        default:
 24081089                            Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Skip);
 24081090                            if (marker == JsonConstants.Slash)
 5741091                            {
 5741092                                if (SkipComment())
 4921093                                {
 4921094                                    if (_consumed >= (uint)_buffer.Length)
 3691095                                    {
 3691096                                        if (_isNotPrimitive && IsLastSpan && _tokenType != JsonTokenType.EndArray && _to
 01097                                        {
 01098                                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidEndO
 1099                                        }
 3691100                                        return false;
 1101                                    }
 1102
 1231103                                    marker = _buffer[_consumed];
 1104
 1105                                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not ne
 1231106                                    if (marker <= JsonConstants.Space)
 411107                                    {
 411108                                        SkipWhiteSpace();
 411109                                        if (!HasMoreData())
 01110                                        {
 01111                                            return false;
 1112                                        }
 411113                                        marker = _buffer[_consumed];
 411114                                    }
 1115
 1231116                                    TokenStartIndex = _consumed;
 1117
 1118                                    // Skip comments and consume the actual JSON value.
 1231119                                    continue;
 1120                                }
 01121                                return false;
 1122                            }
 18341123                            break;
 1124                    }
 132631125                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfValueNotFound, marke
 1126                }
 7181127                break;
 1128            }
 7181129            return true;
 78111130        }
 1131
 1132        // Consumes 'null', or 'true', or 'false'
 1133        private bool ConsumeLiteral(ReadOnlySpan<byte> literal, JsonTokenType tokenType)
 5041134        {
 5041135            ReadOnlySpan<byte> span = _buffer.Slice(_consumed);
 5041136            Debug.Assert(span.Length > 0);
 5041137            Debug.Assert(span[0] == 'n' || span[0] == 't' || span[0] == 'f');
 1138
 5041139            if (!span.StartsWith(literal))
 5041140            {
 5041141                return CheckLiteral(span, literal);
 1142            }
 1143
 01144            ValueSpan = span.Slice(0, literal.Length);
 01145            _tokenType = tokenType;
 01146            _consumed += literal.Length;
 01147            _bytePositionInLine += literal.Length;
 01148            return true;
 01149        }
 1150
 1151        private bool CheckLiteral(ReadOnlySpan<byte> span, ReadOnlySpan<byte> literal)
 5041152        {
 5041153            Debug.Assert(span.Length > 0 && span[0] == literal[0]);
 1154
 5041155            int indexOfFirstMismatch = 0;
 1156
 10081157            for (int i = 1; i < literal.Length; i++)
 5041158            {
 5041159                if (span.Length > i)
 5041160                {
 5041161                    if (span[i] != literal[i])
 5041162                    {
 5041163                        _bytePositionInLine += i;
 5041164                        ThrowInvalidLiteral(span);
 01165                    }
 01166                }
 1167                else
 01168                {
 01169                    indexOfFirstMismatch = i;
 01170                    break;
 1171                }
 01172            }
 1173
 01174            Debug.Assert(indexOfFirstMismatch > 0 && indexOfFirstMismatch < literal.Length);
 1175
 01176            if (IsLastSpan)
 01177            {
 01178                _bytePositionInLine += indexOfFirstMismatch;
 01179                ThrowInvalidLiteral(span);
 01180            }
 01181            return false;
 01182        }
 1183
 1184        private void ThrowInvalidLiteral(ReadOnlySpan<byte> span)
 5041185        {
 5041186            byte firstByte = span[0];
 1187
 1188            ExceptionResource resource;
 5041189            switch (firstByte)
 1190            {
 1191                case (byte)'t':
 1261192                    resource = ExceptionResource.ExpectedTrue;
 1261193                    break;
 1194                case (byte)'f':
 2101195                    resource = ExceptionResource.ExpectedFalse;
 2101196                    break;
 1197                default:
 1681198                    Debug.Assert(firstByte == 'n');
 1681199                    resource = ExceptionResource.ExpectedNull;
 1681200                    break;
 1201            }
 5041202            ThrowHelper.ThrowJsonReaderException(ref this, resource, bytes: span);
 1203        }
 1204
 1205        private bool ConsumeNumber()
 1661206        {
 1661207            if (!TryGetNumber(_buffer.Slice(_consumed), out int consumed))
 01208            {
 01209                return false;
 1210            }
 1211
 401212            _tokenType = JsonTokenType.Number;
 401213            _consumed += consumed;
 401214            _bytePositionInLine += consumed;
 1215
 401216            if (_consumed >= (uint)_buffer.Length)
 01217            {
 01218                Debug.Assert(IsLastSpan);
 1219
 1220                // If there is no more data, and the JSON is not a single value, throw.
 01221                if (_isNotPrimitive)
 01222                {
 01223                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, _buffer
 1224                }
 01225            }
 1226
 1227            // If there is more data and the JSON is not a single value, assert that there is an end of number delimiter
 1228            // Else, if either the JSON is a single value XOR if there is no more data, don't assert anything since ther
 401229            Debug.Assert(
 401230                ((_consumed < _buffer.Length) &&
 401231                !_isNotPrimitive &&
 401232                JsonConstants.Delimiters.Contains(_buffer[_consumed]))
 401233                || (_isNotPrimitive ^ (_consumed >= (uint)_buffer.Length)));
 1234
 401235            return true;
 401236        }
 1237
 1238        private bool ConsumePropertyName()
 81239        {
 81240            _trailingCommaBeforeComment = false;
 1241
 81242            if (!ConsumeString())
 01243            {
 01244                return false;
 1245            }
 1246
 01247            if (!HasMoreData(ExceptionResource.ExpectedValueAfterPropertyNameNotFound))
 01248            {
 01249                return false;
 1250            }
 1251
 01252            byte first = _buffer[_consumed];
 1253
 1254            // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 1255            // We do not validate if 'first' is an invalid JSON byte here (such as control characters).
 1256            // Those cases are captured below where we only accept ':'.
 01257            if (first <= JsonConstants.Space)
 01258            {
 01259                SkipWhiteSpace();
 01260                if (!HasMoreData(ExceptionResource.ExpectedValueAfterPropertyNameNotFound))
 01261                {
 01262                    return false;
 1263                }
 01264                first = _buffer[_consumed];
 01265            }
 1266
 1267            // The next character must be a key / value separator. Validate and skip.
 01268            if (first != JsonConstants.KeyValueSeparator)
 01269            {
 01270                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedSeparatorAfterPropertyNameNotFo
 1271            }
 1272
 01273            _consumed++;
 01274            _bytePositionInLine++;
 01275            _tokenType = JsonTokenType.PropertyName;
 01276            return true;
 01277        }
 1278
 1279        private bool ConsumeString()
 70861280        {
 70861281            Debug.Assert(_buffer.Length >= _consumed + 1);
 70861282            Debug.Assert(_buffer[_consumed] == JsonConstants.Quote);
 1283
 1284            // Create local copy to avoid bounds checks.
 70861285            ReadOnlySpan<byte> localBuffer = _buffer.Slice(_consumed + 1);
 1286
 1287            // Vectorized search for either quote, backslash, or any control character.
 1288            // If the first found byte is a quote, we have reached an end of string, and
 1289            // can avoid validation.
 1290            // Otherwise, in the uncommon case, iterate one character at a time and validate.
 70861291            int idx = localBuffer.IndexOfQuoteOrAnyControlOrBackSlash();
 1292
 70861293            if (idx >= 0)
 69181294            {
 69181295                byte foundByte = localBuffer[idx];
 69181296                if (foundByte == JsonConstants.Quote)
 66841297                {
 66841298                    _bytePositionInLine += idx + 2; // Add 2 for the start and end quotes.
 66841299                    ValueSpan = localBuffer.Slice(0, idx);
 66841300                    ValueIsEscaped = false;
 66841301                    _tokenType = JsonTokenType.String;
 66841302                    _consumed += idx + 2;
 66841303                    return true;
 1304                }
 1305                else
 2341306                {
 2341307                    return ConsumeStringAndValidate(localBuffer, idx);
 1308                }
 1309            }
 1310            else
 1681311            {
 1681312                if (IsLastSpan)
 1681313                {
 1681314                    _bytePositionInLine += localBuffer.Length + 1;  // Account for the start quote
 1681315                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound);
 1316                }
 01317                return false;
 1318            }
 66841319        }
 1320
 1321        // Found a backslash or control characters which are considered invalid within a string.
 1322        // Search through the rest of the string one byte at a time.
 1323        // https://tools.ietf.org/html/rfc8259#section-7
 1324        private bool ConsumeStringAndValidate(ReadOnlySpan<byte> data, int idx)
 2341325        {
 2341326            Debug.Assert(idx >= 0 && idx < data.Length);
 2341327            Debug.Assert(data[idx] != JsonConstants.Quote);
 2341328            Debug.Assert(data[idx] == JsonConstants.BackSlash || data[idx] < JsonConstants.Space);
 1329
 2341330            long prevLineBytePosition = _bytePositionInLine;
 2341331            long prevLineNumber = _lineNumber;
 1332
 2341333            _bytePositionInLine += idx + 1; // Add 1 for the first quote
 1334
 2341335            bool nextCharEscaped = false;
 2341336            for (; idx < data.Length; idx++)
 2341337            {
 2341338                byte currentByte = data[idx];
 2341339                if (currentByte == JsonConstants.Quote)
 01340                {
 01341                    if (!nextCharEscaped)
 01342                    {
 01343                        goto Done;
 1344                    }
 01345                    nextCharEscaped = false;
 01346                }
 2341347                else if (currentByte == JsonConstants.BackSlash)
 01348                {
 01349                    nextCharEscaped = !nextCharEscaped;
 01350                }
 2341351                else if (nextCharEscaped)
 01352                {
 01353                    int index = JsonConstants.EscapableChars.IndexOf(currentByte);
 01354                    if (index == -1)
 01355                    {
 01356                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterAfterEscapeWith
 1357                    }
 1358
 01359                    if (currentByte == 'u')
 01360                    {
 1361                        // Expecting 4 hex digits to follow the escaped 'u'
 01362                        _bytePositionInLine++;  // move past the 'u'
 01363                        if (ValidateHexDigits(data, idx + 1))
 01364                        {
 01365                            idx += 4;   // Skip the 4 hex digits, the for loop accounts for idx incrementing past the 'u
 01366                        }
 1367                        else
 01368                        {
 1369                            // We found less than 4 hex digits. Check if there is more data to follow, otherwise throw.
 01370                            idx = data.Length;
 01371                            break;
 1372                        }
 1373
 01374                    }
 01375                    nextCharEscaped = false;
 01376                }
 2341377                else if (currentByte < JsonConstants.Space)
 2341378                {
 2341379                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterWithinString, curre
 1380                }
 1381
 01382                _bytePositionInLine++;
 01383            }
 1384
 01385            if (idx >= data.Length)
 01386            {
 01387                if (IsLastSpan)
 01388                {
 01389                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound);
 1390                }
 01391                _lineNumber = prevLineNumber;
 01392                _bytePositionInLine = prevLineBytePosition;
 01393                return false;
 1394            }
 1395
 01396        Done:
 01397            _bytePositionInLine++;  // Add 1 for the end quote
 01398            ValueSpan = data.Slice(0, idx);
 01399            ValueIsEscaped = true;
 01400            _tokenType = JsonTokenType.String;
 01401            _consumed += idx + 2;
 01402            return true;
 01403        }
 1404
 1405        private bool ValidateHexDigits(ReadOnlySpan<byte> data, int idx)
 01406        {
 01407            for (int j = idx; j < data.Length; j++)
 01408            {
 01409                byte nextByte = data[j];
 01410                if (!JsonReaderHelper.IsHexDigit(nextByte))
 01411                {
 01412                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidHexCharacterWithinString, ne
 1413                }
 01414                if (j - idx >= 3)
 01415                {
 01416                    return true;
 1417                }
 01418                _bytePositionInLine++;
 01419            }
 1420
 01421            return false;
 01422        }
 1423
 1424        // https://tools.ietf.org/html/rfc7159#section-6
 1425        private bool TryGetNumber(ReadOnlySpan<byte> data, out int consumed)
 44741426        {
 1427            // TODO: https://github.com/dotnet/runtime/issues/27837
 44741428            Debug.Assert(data.Length > 0);
 1429
 44741430            consumed = 0;
 44741431            int i = 0;
 1432
 44741433            ConsumeNumberResult signResult = ConsumeNegativeSign(ref data, ref i);
 43531434            if (signResult == ConsumeNumberResult.NeedMoreData)
 01435            {
 01436                return false;
 1437            }
 1438
 43531439            Debug.Assert(signResult == ConsumeNumberResult.OperationIncomplete);
 1440
 43531441            byte nextByte = data[i];
 43531442            Debug.Assert(nextByte >= '0' && nextByte <= '9');
 1443
 43531444            if (nextByte == '0')
 2421445            {
 2421446                ConsumeNumberResult result = ConsumeZero(ref data, ref i);
 01447                if (result == ConsumeNumberResult.NeedMoreData)
 01448                {
 01449                    return false;
 1450                }
 01451                if (result == ConsumeNumberResult.Success)
 01452                {
 01453                    goto Done;
 1454                }
 1455
 01456                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 01457                nextByte = data[i];
 01458            }
 1459            else
 41111460            {
 41111461                i++;
 41111462                ConsumeNumberResult result = ConsumeIntegerDigits(ref data, ref i);
 41111463                if (result == ConsumeNumberResult.NeedMoreData)
 01464                {
 01465                    return false;
 1466                }
 41111467                if (result == ConsumeNumberResult.Success)
 30281468                {
 30281469                    goto Done;
 1470                }
 1471
 10831472                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 10831473                nextByte = data[i];
 10831474                if (nextByte != '.' && nextByte != 'E' && nextByte != 'e')
 6031475                {
 6031476                    _bytePositionInLine += i;
 6031477                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, nextByt
 1478                }
 4801479            }
 1480
 4801481            Debug.Assert(nextByte == '.' || nextByte == 'E' || nextByte == 'e');
 1482
 4801483            if (nextByte == '.')
 2641484            {
 2641485                i++;
 2641486                ConsumeNumberResult result = ConsumeDecimalDigits(ref data, ref i);
 2221487                if (result == ConsumeNumberResult.NeedMoreData)
 01488                {
 01489                    return false;
 1490                }
 2221491                if (result == ConsumeNumberResult.Success)
 961492                {
 961493                    goto Done;
 1494                }
 1495
 1261496                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 1261497                nextByte = data[i];
 1261498                if (nextByte != 'E' && nextByte != 'e')
 1261499                {
 1261500                    _bytePositionInLine += i;
 1261501                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedNextDigitEValueNotFound, ne
 1502                }
 01503            }
 1504
 2161505            Debug.Assert(nextByte == 'E' || nextByte == 'e');
 2161506            i++;
 1507
 2161508            signResult = ConsumeSign(ref data, ref i);
 1321509            if (signResult == ConsumeNumberResult.NeedMoreData)
 01510            {
 01511                return false;
 1512            }
 1513
 1321514            Debug.Assert(signResult == ConsumeNumberResult.OperationIncomplete);
 1515
 1321516            i++;
 1321517            ConsumeNumberResult resultExponent = ConsumeIntegerDigits(ref data, ref i);
 1321518            if (resultExponent == ConsumeNumberResult.NeedMoreData)
 01519            {
 01520                return false;
 1521            }
 1321522            if (resultExponent == ConsumeNumberResult.Success)
 481523            {
 481524                goto Done;
 1525            }
 1526
 841527            Debug.Assert(resultExponent == ConsumeNumberResult.OperationIncomplete);
 1528
 841529            _bytePositionInLine += i;
 841530            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, data[i]);
 1531
 31721532        Done:
 31721533            ValueSpan = data.Slice(0, i);
 31721534            consumed = i;
 31721535            return true;
 31721536        }
 1537
 1538        private ConsumeNumberResult ConsumeNegativeSign(ref ReadOnlySpan<byte> data, scoped ref int i)
 44741539        {
 44741540            byte nextByte = data[i];
 1541
 44741542            if (nextByte == '-')
 2091543            {
 2091544                i++;
 2091545                if (i >= data.Length)
 01546                {
 01547                    if (IsLastSpan)
 01548                    {
 01549                        _bytePositionInLine += i;
 01550                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1551                    }
 01552                    return ConsumeNumberResult.NeedMoreData;
 1553                }
 1554
 2091555                nextByte = data[i];
 2091556                if (!JsonHelpers.IsDigit(nextByte))
 1211557                {
 1211558                    _bytePositionInLine += i;
 1211559                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nex
 1560                }
 881561            }
 43531562            return ConsumeNumberResult.OperationIncomplete;
 43531563        }
 1564
 1565        private ConsumeNumberResult ConsumeZero(ref ReadOnlySpan<byte> data, scoped ref int i)
 2421566        {
 2421567            Debug.Assert(data[i] == (byte)'0');
 2421568            i++;
 1569            byte nextByte;
 2421570            if (i < data.Length)
 2421571            {
 2421572                nextByte = data[i];
 2421573                if (JsonConstants.Delimiters.Contains(nextByte))
 01574                {
 01575                    return ConsumeNumberResult.Success;
 1576                }
 2421577            }
 1578            else
 01579            {
 01580                if (IsLastSpan)
 01581                {
 1582                    // A payload containing a single value: "0" is valid
 1583                    // If we are dealing with multi-value JSON,
 1584                    // ConsumeNumber will validate that we have a delimiter following the "0".
 01585                    return ConsumeNumberResult.Success;
 1586                }
 1587                else
 01588                {
 01589                    return ConsumeNumberResult.NeedMoreData;
 1590                }
 1591            }
 2421592            nextByte = data[i];
 2421593            if (nextByte != '.' && nextByte != 'E' && nextByte != 'e')
 2421594            {
 2421595                _bytePositionInLine += i;
 2421596                ThrowHelper.ThrowJsonReaderException(ref this,
 2421597                    JsonHelpers.IsInRangeInclusive(nextByte, '0', '9') ? ExceptionResource.InvalidLeadingZeroInNumber : 
 2421598                    nextByte);
 1599            }
 1600
 01601            return ConsumeNumberResult.OperationIncomplete;
 01602        }
 1603
 1604        private ConsumeNumberResult ConsumeIntegerDigits(ref ReadOnlySpan<byte> data, scoped ref int i)
 44651605        {
 44651606            byte nextByte = default;
 557631607            for (; i < data.Length; i++)
 293761608            {
 293761609                nextByte = data[i];
 293761610                if (!JsonHelpers.IsDigit(nextByte))
 37271611                {
 37271612                    break;
 1613                }
 256491614            }
 44651615            if (i >= data.Length)
 7381616            {
 7381617                if (IsLastSpan)
 7381618                {
 1619                    // A payload containing a single value of integers (e.g. "12") is valid
 1620                    // If we are dealing with multi-value JSON,
 1621                    // ConsumeNumber will validate that we have a delimiter following the integer.
 7381622                    return ConsumeNumberResult.Success;
 1623                }
 1624                else
 01625                {
 01626                    return ConsumeNumberResult.NeedMoreData;
 1627                }
 1628            }
 37271629            if (JsonConstants.Delimiters.Contains(nextByte))
 24341630            {
 24341631                return ConsumeNumberResult.Success;
 1632            }
 1633
 12931634            return ConsumeNumberResult.OperationIncomplete;
 44651635        }
 1636
 1637        private ConsumeNumberResult ConsumeDecimalDigits(ref ReadOnlySpan<byte> data, scoped ref int i)
 2641638        {
 2641639            if (i >= data.Length)
 01640            {
 01641                if (IsLastSpan)
 01642                {
 01643                    _bytePositionInLine += i;
 01644                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData);
 1645                }
 01646                return ConsumeNumberResult.NeedMoreData;
 1647            }
 2641648            byte nextByte = data[i];
 2641649            if (!JsonHelpers.IsDigit(nextByte))
 421650            {
 421651                _bytePositionInLine += i;
 421652                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterDecimal, next
 1653            }
 2221654            i++;
 1655
 2221656            return ConsumeIntegerDigits(ref data, ref i);
 2221657        }
 1658
 1659        private ConsumeNumberResult ConsumeSign(ref ReadOnlySpan<byte> data, scoped ref int i)
 2161660        {
 2161661            if (i >= data.Length)
 01662            {
 01663                if (IsLastSpan)
 01664                {
 01665                    _bytePositionInLine += i;
 01666                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData);
 1667                }
 01668                return ConsumeNumberResult.NeedMoreData;
 1669            }
 1670
 2161671            byte nextByte = data[i];
 2161672            if (nextByte == '+' || nextByte == '-')
 01673            {
 01674                i++;
 01675                if (i >= data.Length)
 01676                {
 01677                    if (IsLastSpan)
 01678                    {
 01679                        _bytePositionInLine += i;
 01680                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1681                    }
 01682                    return ConsumeNumberResult.NeedMoreData;
 1683                }
 01684                nextByte = data[i];
 01685            }
 1686
 2161687            if (!JsonHelpers.IsDigit(nextByte))
 841688            {
 841689                _bytePositionInLine += i;
 841690                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nextByt
 1691            }
 1692
 1321693            return ConsumeNumberResult.OperationIncomplete;
 1321694        }
 1695
 1696        private bool ConsumeNextTokenOrRollback(byte marker)
 24081697        {
 24081698            int prevConsumed = _consumed;
 24081699            long prevPosition = _bytePositionInLine;
 24081700            long prevLineNumber = _lineNumber;
 24081701            JsonTokenType prevTokenType = _tokenType;
 24081702            bool prevTrailingCommaBeforeComment = _trailingCommaBeforeComment;
 24081703            ConsumeTokenResult result = ConsumeNextToken(marker);
 01704            if (result == ConsumeTokenResult.Success)
 01705            {
 01706                return true;
 1707            }
 01708            if (result == ConsumeTokenResult.NotEnoughDataRollBackState)
 01709            {
 01710                _consumed = prevConsumed;
 01711                _tokenType = prevTokenType;
 01712                _bytePositionInLine = prevPosition;
 01713                _lineNumber = prevLineNumber;
 01714                _trailingCommaBeforeComment = prevTrailingCommaBeforeComment;
 01715            }
 01716            return false;
 01717        }
 1718
 1719        /// <summary>
 1720        /// This method consumes the next token regardless of whether we are inside an object or an array.
 1721        /// For an object, it reads the next property name token. For an array, it just reads the next value.
 1722        /// </summary>
 1723        private ConsumeTokenResult ConsumeNextToken(byte marker)
 24081724        {
 24081725            if (_readerOptions.CommentHandling != JsonCommentHandling.Disallow)
 11701726            {
 11701727                if (_readerOptions.CommentHandling == JsonCommentHandling.Allow)
 01728                {
 01729                    if (marker == JsonConstants.Slash)
 01730                    {
 01731                        return ConsumeComment() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBackS
 1732                    }
 01733                    if (_tokenType == JsonTokenType.Comment)
 01734                    {
 01735                        return ConsumeNextTokenFromLastNonCommentToken();
 1736                    }
 01737                }
 1738                else
 11701739                {
 11701740                    Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Skip);
 11701741                    return ConsumeNextTokenUntilAfterAllCommentsAreSkipped(marker);
 1742                }
 01743            }
 1744
 12381745            if (_bitStack.CurrentDepth == 0)
 11791746            {
 11791747                if (_readerOptions.AllowMultipleValues)
 01748                {
 01749                    return ReadFirstToken(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBac
 1750                }
 1751
 11791752                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, marker);
 1753            }
 1754
 591755            if (marker == JsonConstants.ListSeparator)
 401756            {
 401757                _consumed++;
 401758                _bytePositionInLine++;
 1759
 401760                if (_consumed >= (uint)_buffer.Length)
 01761                {
 01762                    if (IsLastSpan)
 01763                    {
 01764                        _consumed--;
 01765                        _bytePositionInLine--;
 01766                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 1767                    }
 01768                    return ConsumeTokenResult.NotEnoughDataRollBackState;
 1769                }
 401770                byte first = _buffer[_consumed];
 1771
 1772                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 401773                if (first <= JsonConstants.Space)
 01774                {
 01775                    SkipWhiteSpace();
 1776                    // The next character must be a start of a property name or value.
 01777                    if (!HasMoreData(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 01778                    {
 01779                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 1780                    }
 01781                    first = _buffer[_consumed];
 01782                }
 1783
 401784                TokenStartIndex = _consumed;
 1785
 401786                if (_readerOptions.CommentHandling == JsonCommentHandling.Allow && first == JsonConstants.Slash)
 01787                {
 01788                    _trailingCommaBeforeComment = true;
 01789                    return ConsumeComment() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBackState
 1790                }
 1791
 401792                if (_inObject)
 01793                {
 01794                    if (first != JsonConstants.Quote)
 01795                    {
 01796                        if (first == JsonConstants.CloseBrace)
 01797                        {
 01798                            if (_readerOptions.AllowTrailingCommas)
 01799                            {
 01800                                EndObject();
 01801                                return ConsumeTokenResult.Success;
 1802                            }
 01803                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 1804                        }
 01805                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 1806                    }
 01807                    return ConsumePropertyName() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBack
 1808                }
 1809                else
 401810                {
 401811                    if (first == JsonConstants.CloseBracket)
 01812                    {
 01813                        if (_readerOptions.AllowTrailingCommas)
 01814                        {
 01815                            EndArray();
 01816                            return ConsumeTokenResult.Success;
 1817                        }
 01818                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 1819                    }
 401820                    return ConsumeValue(first) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBackSt
 1821                }
 1822            }
 191823            else if (marker == JsonConstants.CloseBrace)
 01824            {
 01825                EndObject();
 01826            }
 191827            else if (marker == JsonConstants.CloseBracket)
 01828            {
 01829                EndArray();
 01830            }
 1831            else
 191832            {
 191833                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.FoundInvalidCharacter, marker);
 1834            }
 01835            return ConsumeTokenResult.Success;
 01836        }
 1837
 1838        private ConsumeTokenResult ConsumeNextTokenFromLastNonCommentToken()
 01839        {
 01840            Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Allow);
 01841            Debug.Assert(_tokenType == JsonTokenType.Comment);
 1842
 01843            if (JsonReaderHelper.IsTokenTypePrimitive(_previousTokenType))
 01844            {
 01845                _tokenType = _inObject ? JsonTokenType.StartObject : JsonTokenType.StartArray;
 01846            }
 1847            else
 01848            {
 01849                _tokenType = _previousTokenType;
 01850            }
 1851
 01852            Debug.Assert(_tokenType != JsonTokenType.Comment);
 1853
 01854            if (!HasMoreData())
 01855            {
 01856                goto RollBack;
 1857            }
 1858
 01859            byte first = _buffer[_consumed];
 1860
 1861            // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01862            if (first <= JsonConstants.Space)
 01863            {
 01864                SkipWhiteSpace();
 01865                if (!HasMoreData())
 01866                {
 01867                    goto RollBack;
 1868                }
 01869                first = _buffer[_consumed];
 01870            }
 1871
 01872            if (_bitStack.CurrentDepth == 0 && _tokenType != JsonTokenType.None)
 01873            {
 01874                if (_readerOptions.AllowMultipleValues)
 01875                {
 01876                    return ReadFirstToken(first) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBack
 1877                }
 1878
 01879                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, first);
 1880            }
 1881
 01882            Debug.Assert(first != JsonConstants.Slash);
 1883
 01884            TokenStartIndex = _consumed;
 1885
 01886            if (first == JsonConstants.ListSeparator)
 01887            {
 1888                // A comma without some JSON value preceding it is invalid
 01889                if (_previousTokenType <= JsonTokenType.StartObject || _previousTokenType == JsonTokenType.StartArray ||
 01890                {
 01891                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueAfter
 1892                }
 1893
 01894                _consumed++;
 01895                _bytePositionInLine++;
 1896
 01897                if (_consumed >= (uint)_buffer.Length)
 01898                {
 01899                    if (IsLastSpan)
 01900                    {
 01901                        _consumed--;
 01902                        _bytePositionInLine--;
 01903                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 1904                    }
 01905                    goto RollBack;
 1906                }
 01907                first = _buffer[_consumed];
 1908
 1909                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01910                if (first <= JsonConstants.Space)
 01911                {
 01912                    SkipWhiteSpace();
 1913                    // The next character must be a start of a property name or value.
 01914                    if (!HasMoreData(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 01915                    {
 01916                        goto RollBack;
 1917                    }
 01918                    first = _buffer[_consumed];
 01919                }
 1920
 01921                TokenStartIndex = _consumed;
 1922
 01923                if (first == JsonConstants.Slash)
 01924                {
 01925                    _trailingCommaBeforeComment = true;
 01926                    if (ConsumeComment())
 01927                    {
 01928                        goto Done;
 1929                    }
 1930                    else
 01931                    {
 01932                        goto RollBack;
 1933                    }
 1934                }
 1935
 01936                if (_inObject)
 01937                {
 01938                    if (first != JsonConstants.Quote)
 01939                    {
 01940                        if (first == JsonConstants.CloseBrace)
 01941                        {
 01942                            if (_readerOptions.AllowTrailingCommas)
 01943                            {
 01944                                EndObject();
 01945                                goto Done;
 1946                            }
 01947                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 1948                        }
 1949
 01950                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 1951                    }
 01952                    if (ConsumePropertyName())
 01953                    {
 01954                        goto Done;
 1955                    }
 1956                    else
 01957                    {
 01958                        goto RollBack;
 1959                    }
 1960                }
 1961                else
 01962                {
 01963                    if (first == JsonConstants.CloseBracket)
 01964                    {
 01965                        if (_readerOptions.AllowTrailingCommas)
 01966                        {
 01967                            EndArray();
 01968                            goto Done;
 1969                        }
 01970                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 1971                    }
 1972
 01973                    if (ConsumeValue(first))
 01974                    {
 01975                        goto Done;
 1976                    }
 1977                    else
 01978                    {
 01979                        goto RollBack;
 1980                    }
 1981                }
 1982            }
 01983            else if (first == JsonConstants.CloseBrace)
 01984            {
 01985                EndObject();
 01986            }
 01987            else if (first == JsonConstants.CloseBracket)
 01988            {
 01989                EndArray();
 01990            }
 01991            else if (_tokenType == JsonTokenType.None)
 01992            {
 01993                if (ReadFirstToken(first))
 01994                {
 01995                    goto Done;
 1996                }
 1997                else
 01998                {
 01999                    goto RollBack;
 2000                }
 2001            }
 02002            else if (_tokenType == JsonTokenType.StartObject)
 02003            {
 02004                Debug.Assert(first != JsonConstants.CloseBrace);
 02005                if (first != JsonConstants.Quote)
 02006                {
 02007                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound, fi
 2008                }
 2009
 02010                int prevConsumed = _consumed;
 02011                long prevPosition = _bytePositionInLine;
 02012                long prevLineNumber = _lineNumber;
 02013                if (!ConsumePropertyName())
 02014                {
 2015                    // roll back potential changes
 02016                    _consumed = prevConsumed;
 02017                    _tokenType = JsonTokenType.StartObject;
 02018                    _bytePositionInLine = prevPosition;
 02019                    _lineNumber = prevLineNumber;
 02020                    goto RollBack;
 2021                }
 02022                goto Done;
 2023            }
 02024            else if (_tokenType == JsonTokenType.StartArray)
 02025            {
 02026                Debug.Assert(first != JsonConstants.CloseBracket);
 02027                if (!ConsumeValue(first))
 02028                {
 02029                    goto RollBack;
 2030                }
 02031                goto Done;
 2032            }
 02033            else if (_tokenType == JsonTokenType.PropertyName)
 02034            {
 02035                if (!ConsumeValue(first))
 02036                {
 02037                    goto RollBack;
 2038                }
 02039                goto Done;
 2040            }
 2041            else
 02042            {
 02043                Debug.Assert(_tokenType is JsonTokenType.EndArray or JsonTokenType.EndObject);
 02044                if (_inObject)
 02045                {
 02046                    Debug.Assert(first != JsonConstants.CloseBrace);
 02047                    if (first != JsonConstants.Quote)
 02048                    {
 02049                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 2050                    }
 2051
 02052                    if (ConsumePropertyName())
 02053                    {
 02054                        goto Done;
 2055                    }
 2056                    else
 02057                    {
 02058                        goto RollBack;
 2059                    }
 2060                }
 2061                else
 02062                {
 02063                    Debug.Assert(first != JsonConstants.CloseBracket);
 2064
 02065                    if (ConsumeValue(first))
 02066                    {
 02067                        goto Done;
 2068                    }
 2069                    else
 02070                    {
 02071                        goto RollBack;
 2072                    }
 2073                }
 2074            }
 2075
 02076        Done:
 02077            return ConsumeTokenResult.Success;
 2078
 02079        RollBack:
 02080            return ConsumeTokenResult.NotEnoughDataRollBackState;
 02081        }
 2082
 2083        private bool SkipAllComments(scoped ref byte marker)
 11702084        {
 11702085            while (marker == JsonConstants.Slash)
 5072086            {
 5072087                if (SkipComment())
 02088                {
 02089                    if (!HasMoreData())
 02090                    {
 02091                        goto IncompleteNoRollback;
 2092                    }
 2093
 02094                    marker = _buffer[_consumed];
 2095
 2096                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 02097                    if (marker <= JsonConstants.Space)
 02098                    {
 02099                        SkipWhiteSpace();
 02100                        if (!HasMoreData())
 02101                        {
 02102                            goto IncompleteNoRollback;
 2103                        }
 02104                        marker = _buffer[_consumed];
 02105                    }
 02106                }
 2107                else
 02108                {
 02109                    goto IncompleteNoRollback;
 2110                }
 02111            }
 6632112            return true;
 2113
 02114        IncompleteNoRollback:
 02115            return false;
 6632116        }
 2117
 2118        private bool SkipAllComments(scoped ref byte marker, ExceptionResource resource)
 02119        {
 02120            while (marker == JsonConstants.Slash)
 02121            {
 02122                if (SkipComment())
 02123                {
 2124                    // The next character must be a start of a property name or value.
 02125                    if (!HasMoreData(resource))
 02126                    {
 02127                        goto IncompleteRollback;
 2128                    }
 2129
 02130                    marker = _buffer[_consumed];
 2131
 2132                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 02133                    if (marker <= JsonConstants.Space)
 02134                    {
 02135                        SkipWhiteSpace();
 2136                        // The next character must be a start of a property name or value.
 02137                        if (!HasMoreData(resource))
 02138                        {
 02139                            goto IncompleteRollback;
 2140                        }
 02141                        marker = _buffer[_consumed];
 02142                    }
 02143                }
 2144                else
 02145                {
 02146                    goto IncompleteRollback;
 2147                }
 02148            }
 02149            return true;
 2150
 02151        IncompleteRollback:
 02152            return false;
 02153        }
 2154
 2155        private ConsumeTokenResult ConsumeNextTokenUntilAfterAllCommentsAreSkipped(byte marker)
 11702156        {
 11702157            if (!SkipAllComments(ref marker))
 02158            {
 02159                goto IncompleteNoRollback;
 2160            }
 2161
 6632162            TokenStartIndex = _consumed;
 2163
 6632164            if (_tokenType == JsonTokenType.StartObject)
 02165            {
 02166                if (marker == JsonConstants.CloseBrace)
 02167                {
 02168                    EndObject();
 02169                }
 2170                else
 02171                {
 02172                    if (marker != JsonConstants.Quote)
 02173                    {
 02174                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 2175                    }
 2176
 02177                    int prevConsumed = _consumed;
 02178                    long prevPosition = _bytePositionInLine;
 02179                    long prevLineNumber = _lineNumber;
 02180                    if (!ConsumePropertyName())
 02181                    {
 2182                        // roll back potential changes
 02183                        _consumed = prevConsumed;
 02184                        _tokenType = JsonTokenType.StartObject;
 02185                        _bytePositionInLine = prevPosition;
 02186                        _lineNumber = prevLineNumber;
 02187                        goto IncompleteNoRollback;
 2188                    }
 02189                    goto Done;
 2190                }
 02191            }
 6632192            else if (_tokenType == JsonTokenType.StartArray)
 02193            {
 02194                if (marker == JsonConstants.CloseBracket)
 02195                {
 02196                    EndArray();
 02197                }
 2198                else
 02199                {
 02200                    if (!ConsumeValue(marker))
 02201                    {
 02202                        goto IncompleteNoRollback;
 2203                    }
 02204                    goto Done;
 2205                }
 02206            }
 6632207            else if (_tokenType == JsonTokenType.PropertyName)
 02208            {
 02209                if (!ConsumeValue(marker))
 02210                {
 02211                    goto IncompleteNoRollback;
 2212                }
 02213                goto Done;
 2214            }
 6632215            else if (_bitStack.CurrentDepth == 0)
 6632216            {
 6632217                if (_readerOptions.AllowMultipleValues)
 02218                {
 02219                    return ReadFirstToken(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBac
 2220                }
 2221
 6632222                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, marker);
 2223            }
 02224            else if (marker == JsonConstants.ListSeparator)
 02225            {
 02226                _consumed++;
 02227                _bytePositionInLine++;
 2228
 02229                if (_consumed >= (uint)_buffer.Length)
 02230                {
 02231                    if (IsLastSpan)
 02232                    {
 02233                        _consumed--;
 02234                        _bytePositionInLine--;
 02235                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 2236                    }
 02237                    return ConsumeTokenResult.NotEnoughDataRollBackState;
 2238                }
 02239                marker = _buffer[_consumed];
 2240
 2241                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 02242                if (marker <= JsonConstants.Space)
 02243                {
 02244                    SkipWhiteSpace();
 2245                    // The next character must be a start of a property name or value.
 02246                    if (!HasMoreData(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 02247                    {
 02248                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 2249                    }
 02250                    marker = _buffer[_consumed];
 02251                }
 2252
 02253                if (!SkipAllComments(ref marker, ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 02254                {
 02255                    goto IncompleteRollback;
 2256                }
 2257
 02258                TokenStartIndex = _consumed;
 2259
 02260                if (_inObject)
 02261                {
 02262                    if (marker != JsonConstants.Quote)
 02263                    {
 02264                        if (marker == JsonConstants.CloseBrace)
 02265                        {
 02266                            if (_readerOptions.AllowTrailingCommas)
 02267                            {
 02268                                EndObject();
 02269                                goto Done;
 2270                            }
 02271                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 2272                        }
 2273
 02274                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 2275                    }
 02276                    return ConsumePropertyName() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBack
 2277                }
 2278                else
 02279                {
 02280                    if (marker == JsonConstants.CloseBracket)
 02281                    {
 02282                        if (_readerOptions.AllowTrailingCommas)
 02283                        {
 02284                            EndArray();
 02285                            goto Done;
 2286                        }
 02287                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 2288                    }
 2289
 02290                    return ConsumeValue(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDataRollBackS
 2291                }
 2292            }
 02293            else if (marker == JsonConstants.CloseBrace)
 02294            {
 02295                EndObject();
 02296            }
 02297            else if (marker == JsonConstants.CloseBracket)
 02298            {
 02299                EndArray();
 02300            }
 2301            else
 02302            {
 02303                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.FoundInvalidCharacter, marker);
 2304            }
 2305
 02306        Done:
 02307            return ConsumeTokenResult.Success;
 02308        IncompleteNoRollback:
 02309            return ConsumeTokenResult.IncompleteNoRollBackNecessary;
 02310        IncompleteRollback:
 02311            return ConsumeTokenResult.NotEnoughDataRollBackState;
 02312        }
 2313
 2314        private bool SkipComment()
 10812315        {
 2316            // Create local copy to avoid bounds checks.
 10812317            ReadOnlySpan<byte> localBuffer = _buffer.Slice(_consumed + 1);
 2318
 10812319            if (localBuffer.Length > 0)
 10812320            {
 10812321                byte marker = localBuffer[0];
 10812322                if (marker == JsonConstants.Slash)
 4922323                {
 4922324                    return SkipSingleLineComment(localBuffer.Slice(1), out _);
 2325                }
 5892326                else if (marker == JsonConstants.Asterisk)
 02327                {
 02328                    return SkipMultiLineComment(localBuffer.Slice(1), out _);
 2329                }
 2330                else
 5892331                {
 5892332                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfValueNotFound, JsonC
 2333                }
 2334            }
 2335
 02336            if (IsLastSpan)
 02337            {
 02338                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfValueNotFound, JsonConst
 2339            }
 02340            return false;
 4922341        }
 2342
 2343        private bool SkipSingleLineComment(ReadOnlySpan<byte> localBuffer, out int idx)
 4922344        {
 4922345            idx = FindLineSeparator(localBuffer);
 2346            int toConsume;
 4922347            if (idx != -1)
 1232348            {
 1232349                toConsume = idx;
 1232350                if (localBuffer[idx] == JsonConstants.LineFeed)
 822351                {
 822352                    goto EndOfComment;
 2353                }
 2354
 2355                // If we are here, we have definintely found a \r. So now to check if \n follows.
 412356                Debug.Assert(localBuffer[idx] == JsonConstants.CarriageReturn);
 2357
 412358                if (idx < localBuffer.Length - 1)
 412359                {
 412360                    if (localBuffer[idx + 1] == JsonConstants.LineFeed)
 02361                    {
 02362                        toConsume++;
 02363                    }
 2364
 412365                    goto EndOfComment;
 2366                }
 2367
 02368                if (IsLastSpan)
 02369                {
 02370                    goto EndOfComment;
 2371                }
 2372                else
 02373                {
 2374                    // there might be LF in the next segment
 02375                    return false;
 2376                }
 2377            }
 2378
 3692379            if (IsLastSpan)
 3692380            {
 3692381                idx = localBuffer.Length;
 3692382                toConsume = idx;
 2383                // Assume everything on this line is a comment and there is no more data.
 3692384                _bytePositionInLine += 2 + localBuffer.Length;
 3692385                goto Done;
 2386            }
 2387            else
 02388            {
 02389                return false;
 2390            }
 2391
 1232392        EndOfComment:
 1232393            toConsume++;
 1232394            _bytePositionInLine = 0;
 1232395            _lineNumber++;
 2396
 4922397        Done:
 4922398            _consumed += 2 + toConsume;
 4922399            return true;
 4922400        }
 2401
 2402        private int FindLineSeparator(ReadOnlySpan<byte> localBuffer)
 4922403        {
 4922404            int totalIdx = 0;
 4922405            while (true)
 4922406            {
 4922407                int idx = localBuffer.IndexOfAny(JsonConstants.LineFeed, JsonConstants.CarriageReturn, JsonConstants.Sta
 2408
 4922409                if (idx == -1)
 3692410                {
 3692411                    return -1;
 2412                }
 2413
 1232414                totalIdx += idx;
 2415
 1232416                if (localBuffer[idx] != JsonConstants.StartingByteOfNonStandardSeparator)
 1232417                {
 1232418                    return totalIdx;
 2419                }
 2420
 02421                totalIdx++;
 02422                localBuffer = localBuffer.Slice(idx + 1);
 2423
 02424                ThrowOnDangerousLineSeparator(localBuffer);
 02425            }
 4922426        }
 2427
 2428        // assumes first byte (JsonConstants.StartingByteOfNonStandardSeparator) is already read
 2429        private void ThrowOnDangerousLineSeparator(ReadOnlySpan<byte> localBuffer)
 02430        {
 2431            // \u2028 and \u2029 are considered respectively line and paragraph separators
 2432            // UTF-8 representation for them is E2, 80, A8/A9
 2433            // we have already read E2, we need to check for remaining 2 bytes
 2434
 02435            if (localBuffer.Length < 2)
 02436            {
 02437                return;
 2438            }
 2439
 02440            byte next = localBuffer[1];
 02441            if (localBuffer[0] == 0x80 && (next == 0xA8 || next == 0xA9))
 02442            {
 02443                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfLineSeparator);
 2444            }
 02445        }
 2446
 2447        private bool SkipMultiLineComment(ReadOnlySpan<byte> localBuffer, out int idx)
 02448        {
 02449            idx = 0;
 02450            while (true)
 02451            {
 02452                int foundIdx = localBuffer.Slice(idx).IndexOf(JsonConstants.Slash);
 02453                if (foundIdx == -1)
 02454                {
 02455                    if (IsLastSpan)
 02456                    {
 02457                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfCommentNotFound);
 2458                    }
 02459                    return false;
 2460                }
 02461                if (foundIdx != 0 && localBuffer[foundIdx + idx - 1] == JsonConstants.Asterisk)
 02462                {
 2463                    // foundIdx points just after '*' in the end-of-comment delimiter. Hence increment idx by one
 2464                    // position less to make it point right before beginning of end-of-comment delimiter i.e. */
 02465                    idx += foundIdx - 1;
 02466                    break;
 2467                }
 02468                idx += foundIdx + 1;
 02469            }
 2470
 2471            // Consume the /* and */ characters that are part of the multi-line comment.
 2472            // idx points right before the final '*' (which is right before the last '/'). Hence increment _consumed
 2473            // by 4 to exclude the start/end-of-comment delimiters.
 02474            _consumed += 4 + idx;
 2475
 02476            (int newLines, int newLineIndex) = JsonReaderHelper.CountNewLines(localBuffer.Slice(0, idx));
 02477            _lineNumber += newLines;
 02478            if (newLineIndex != -1)
 02479            {
 2480                // newLineIndex points at last newline character and byte positions in the new line start
 2481                // after that. Hence add 1 to skip the newline character.
 02482                _bytePositionInLine = idx - newLineIndex + 1;
 02483            }
 2484            else
 02485            {
 02486                _bytePositionInLine += 4 + idx;
 02487            }
 02488            return true;
 02489        }
 2490
 2491        private bool ConsumeComment()
 02492        {
 2493            // Create local copy to avoid bounds checks.
 02494            ReadOnlySpan<byte> localBuffer = _buffer.Slice(_consumed + 1);
 2495
 02496            if (localBuffer.Length > 0)
 02497            {
 02498                byte marker = localBuffer[0];
 02499                if (marker == JsonConstants.Slash)
 02500                {
 02501                    return ConsumeSingleLineComment(localBuffer.Slice(1), _consumed);
 2502                }
 02503                else if (marker == JsonConstants.Asterisk)
 02504                {
 02505                    return ConsumeMultiLineComment(localBuffer.Slice(1), _consumed);
 2506                }
 2507                else
 02508                {
 02509                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterAtStartOfComment, m
 2510                }
 2511            }
 2512
 02513            if (IsLastSpan)
 02514            {
 02515                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileReadingComment)
 2516            }
 02517            return false;
 02518        }
 2519
 2520        private bool ConsumeSingleLineComment(ReadOnlySpan<byte> localBuffer, int previousConsumed)
 02521        {
 02522            if (!SkipSingleLineComment(localBuffer, out int idx))
 02523            {
 02524                return false;
 2525            }
 2526
 2527            // Exclude the // at start of the comment. idx points right before the line separator
 2528            // at the end of the comment.
 02529            ValueSpan = _buffer.Slice(previousConsumed + 2, idx);
 02530            if (_tokenType != JsonTokenType.Comment)
 02531            {
 02532                _previousTokenType = _tokenType;
 02533            }
 02534            _tokenType = JsonTokenType.Comment;
 02535            return true;
 02536        }
 2537
 2538        private bool ConsumeMultiLineComment(ReadOnlySpan<byte> localBuffer, int previousConsumed)
 02539        {
 02540            if (!SkipMultiLineComment(localBuffer, out int idx))
 02541            {
 02542                return false;
 2543            }
 2544
 2545            // Exclude the /* at start of the comment. idx already points right before the terminal '*/'
 2546            // for the end of multiline comment.
 02547            ValueSpan = _buffer.Slice(previousConsumed + 2, idx);
 02548            if (_tokenType != JsonTokenType.Comment)
 02549            {
 02550                _previousTokenType = _tokenType;
 02551            }
 02552            _tokenType = JsonTokenType.Comment;
 02553            return true;
 02554        }
 2555
 2556        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 02557        private string DebuggerDisplay => $"TokenType = {DebugTokenType}, TokenStartIndex = {TokenStartIndex}, Consumed 
 2558
 2559        // Using TokenType.ToString() (or {TokenType}) fails to render in the debug window. The
 2560        // message "The runtime refused to evaluate the expression at this time." is shown. This
 2561        // is a workaround until we root cause and fix the issue.
 2562        private string DebugTokenType
 02563            => TokenType switch
 02564            {
 02565                JsonTokenType.Comment => nameof(JsonTokenType.Comment),
 02566                JsonTokenType.EndArray => nameof(JsonTokenType.EndArray),
 02567                JsonTokenType.EndObject => nameof(JsonTokenType.EndObject),
 02568                JsonTokenType.False => nameof(JsonTokenType.False),
 02569                JsonTokenType.None => nameof(JsonTokenType.None),
 02570                JsonTokenType.Null => nameof(JsonTokenType.Null),
 02571                JsonTokenType.Number => nameof(JsonTokenType.Number),
 02572                JsonTokenType.PropertyName => nameof(JsonTokenType.PropertyName),
 02573                JsonTokenType.StartArray => nameof(JsonTokenType.StartArray),
 02574                JsonTokenType.StartObject => nameof(JsonTokenType.StartObject),
 02575                JsonTokenType.String => nameof(JsonTokenType.String),
 02576                JsonTokenType.True => nameof(JsonTokenType.True),
 02577                _ => ((byte)TokenType).ToString()
 02578            };
 2579
 2580        private ReadOnlySpan<byte> GetUnescapedSpan()
 16342581        {
 16342582            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 16342583            if (ValueIsEscaped)
 02584            {
 02585                span = JsonReaderHelper.GetUnescaped(span);
 02586            }
 2587
 16342588            return span;
 16342589        }
 2590    }
 2591}

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\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)
 2864425        {
 2864426            _buffer = jsonData.First.Span;
 27
 2864428            _isFinalBlock = isFinalBlock;
 2864429            _isInputSequence = true;
 30
 2864431            _lineNumber = state._lineNumber;
 2864432            _bytePositionInLine = state._bytePositionInLine;
 2864433            _inObject = state._inObject;
 2864434            _isNotPrimitive = state._isNotPrimitive;
 2864435            ValueIsEscaped = state._valueIsEscaped;
 2864436            _trailingCommaBeforeComment = state._trailingCommaBeforeComment;
 2864437            _tokenType = state._tokenType;
 2864438            _previousTokenType = state._previousTokenType;
 2864439            _readerOptions = state._readerOptions;
 2864440            if (_readerOptions.MaxDepth == 0)
 68241            {
 68242                _readerOptions.MaxDepth = JsonReaderOptions.DefaultMaxDepth;  // If max depth is not set, revert to the 
 68243            }
 2864444            _bitStack = state._bitStack;
 45
 2864446            _consumed = 0;
 2864447            TokenStartIndex = 0;
 2864448            _totalConsumed = 0;
 49
 2864450            ValueSpan = ReadOnlySpan<byte>.Empty;
 51
 2864452            _sequence = jsonData;
 2864453            HasValueSequence = false;
 2864454            ValueSequence = ReadOnlySequence<byte>.Empty;
 55
 2864456            if (jsonData.IsSingleSegment)
 057            {
 058                _nextPosition = default;
 059                _currentPosition = jsonData.Start;
 060                _isLastSegment = isFinalBlock;
 061                _isMultiSegment = false;
 062            }
 63            else
 2864464            {
 2864465                _currentPosition = jsonData.Start;
 2864466                _nextPosition = _currentPosition;
 67
 2864468                bool firstSegmentIsEmpty = _buffer.Length == 0;
 2864469                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
 2864492                _isLastSegment = !jsonData.TryGet(ref _nextPosition, out _, advance: !firstSegmentIsEmpty) && isFinalBlo
 93
 2864494                Debug.Assert(!_nextPosition.Equals(_currentPosition));
 95
 2864496                _isMultiSegment = true;
 2864497            }
 2864498        }
 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()
 32716121        {
 32716122            bool retVal = false;
 32716123            HasValueSequence = false;
 32716124            ValueIsEscaped = false;
 32716125            ValueSpan = default;
 32716126            ValueSequence = default;
 127
 32716128            if (!HasMoreDataMultiSegment())
 95129            {
 95130                goto Done;
 131            }
 132
 32621133            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.
 32621139            if (first <= JsonConstants.Space)
 3871140            {
 3871141                SkipWhiteSpaceMultiSegment();
 3871142                if (!HasMoreDataMultiSegment())
 0143                {
 0144                    goto Done;
 145                }
 3871146                first = _buffer[_consumed];
 3871147            }
 148
 32621149            TokenStartIndex = BytesConsumed;
 150
 32621151            if (_tokenType == JsonTokenType.None)
 28644152            {
 28644153                goto ReadFirstToken;
 154            }
 155
 3977156            if (first == JsonConstants.Slash)
 785157            {
 785158                retVal = ConsumeNextTokenOrRollbackMultiSegment(first);
 0159                goto Done;
 160            }
 161
 3192162            if (_tokenType == JsonTokenType.StartObject)
 212163            {
 212164                if (first == JsonConstants.CloseBrace)
 0165                {
 0166                    EndObject();
 0167                }
 168                else
 212169                {
 212170                    if (first != JsonConstants.Quote)
 204171                    {
 204172                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 173                    }
 174
 8175                    long prevTotalConsumed = _totalConsumed;
 8176                    int prevConsumed = _consumed;
 8177                    long prevPosition = _bytePositionInLine;
 8178                    long prevLineNumber = _lineNumber;
 8179                    SequencePosition copy = _currentPosition;
 8180                    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            }
 2980194            else if (_tokenType == JsonTokenType.StartArray)
 1357195            {
 1357196                if (first == JsonConstants.CloseBracket)
 97197                {
 97198                    EndArray();
 97199                }
 200                else
 1260201                {
 1260202                    retVal = ConsumeValueMultiSegment(first);
 717203                    goto Done;
 204                }
 97205            }
 1623206            else if (_tokenType == JsonTokenType.PropertyName)
 0207            {
 0208                retVal = ConsumeValueMultiSegment(first);
 0209                goto Done;
 210            }
 211            else
 1623212            {
 1623213                retVal = ConsumeNextTokenOrRollbackMultiSegment(first);
 0214                goto Done;
 215            }
 216
 97217            retVal = true;
 218
 14591219        Done:
 14591220            return retVal;
 221
 28644222        ReadFirstToken:
 28644223            retVal = ReadFirstTokenMultiSegment(first);
 13682224            goto Done;
 14591225        }
 226
 227        private bool ValidateStateAtEndOfData()
 0228        {
 0229            Debug.Assert(_isNotPrimitive && IsLastSpan);
 230
 0231            if (_bitStack.CurrentDepth != 0)
 0232            {
 0233                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()
 36628251        {
 36628252            if (_consumed >= (uint)_buffer.Length)
 669253            {
 669254                if (_isNotPrimitive && IsLastSpan)
 0255                {
 0256                    if (!ValidateStateAtEndOfData())
 0257                    {
 0258                        return false;
 259                    }
 0260                }
 261
 669262                if (!GetNextSpan())
 95263                {
 95264                    if (_isNotPrimitive && IsLastSpan)
 0265                    {
 0266                        ValidateStateAtEndOfData();
 0267                    }
 95268                    return false;
 269                }
 574270            }
 36533271            return true;
 36628272        }
 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()
 13787299        {
 300            ReadOnlyMemory<byte> memory;
 13787301            while (true)
 13787302            {
 13787303                Debug.Assert(!_isMultiSegment || _currentPosition.GetObject() != null);
 13787304                SequencePosition copy = _currentPosition;
 13787305                _currentPosition = _nextPosition;
 13787306                bool noMoreData = !_sequence.TryGet(ref _nextPosition, out memory, advance: true);
 13787307                if (noMoreData)
 632308                {
 632309                    _currentPosition = copy;
 632310                    _isLastSegment = true;
 632311                    return false;
 312                }
 13155313                if (memory.Length != 0)
 13155314                {
 13155315                    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() != null);
 0321            }
 322
 13155323            if (_isFinalBlock)
 13155324            {
 13155325                _isLastSegment = !_sequence.TryGet(ref _nextPosition, out _, advance: false);
 13155326            }
 327
 13155328            _buffer = memory.Span;
 13155329            _totalConsumed += _consumed;
 13155330            _consumed = 0;
 331
 13155332            return true;
 13787333        }
 334
 335        private bool ReadFirstTokenMultiSegment(byte first)
 28644336        {
 28644337            if (first == JsonConstants.OpenBrace)
 966338            {
 966339                _bitStack.SetFirstBit();
 966340                _tokenType = JsonTokenType.StartObject;
 966341                ValueSpan = _buffer.Slice(_consumed, 1);
 966342                _consumed++;
 966343                _bytePositionInLine++;
 966344                _inObject = true;
 966345                _isNotPrimitive = true;
 966346            }
 27678347            else if (first == JsonConstants.OpenBracket)
 3780348            {
 3780349                _bitStack.ResetFirstBit();
 3780350                _tokenType = JsonTokenType.StartArray;
 3780351                ValueSpan = _buffer.Slice(_consumed, 1);
 3780352                _consumed++;
 3780353                _bytePositionInLine++;
 3780354                _isNotPrimitive = true;
 3780355            }
 356            else
 23898357            {
 23898358                if (JsonHelpers.IsDigit(first) || first == '-')
 3864359                {
 3864360                    if (!TryGetNumberMultiSegment(_buffer.Slice(_consumed), out int numberOfBytes))
 0361                    {
 0362                        return false;
 363                    }
 2688364                    _tokenType = JsonTokenType.Number;
 2688365                    _consumed += numberOfBytes;
 2688366                }
 20034367                else if (!ConsumeValueMultiSegment(first))
 369368                {
 369369                    return false;
 370                }
 371
 8567372                _isNotPrimitive = _tokenType is JsonTokenType.StartObject or JsonTokenType.StartArray;
 373                // Intentionally fall out of the if-block to return true
 8567374            }
 13313375            return true;
 13682376        }
 377
 378        private void SkipWhiteSpaceMultiSegment()
 3912379        {
 4539380            while (true)
 4539381            {
 4539382                SkipWhiteSpace();
 383
 4539384                if (_consumed < _buffer.Length)
 3912385                {
 3912386                    break;
 387                }
 388
 627389                if (!GetNextSpan())
 0390                {
 0391                    break;
 392                }
 627393            }
 3912394        }
 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)
 21334401        {
 21457402            while (true)
 21457403            {
 21457404                Debug.Assert((_trailingCommaBeforeComment && _readerOptions.CommentHandling == JsonCommentHandling.Allow
 21457405                Debug.Assert((_trailingCommaBeforeComment && marker != JsonConstants.Slash) || !_trailingCommaBeforeComm
 21457406                _trailingCommaBeforeComment = false;
 407
 21457408                if (marker == JsonConstants.Quote)
 6232409                {
 6232410                    return ConsumeStringMultiSegment();
 411                }
 15225412                else if (marker == JsonConstants.OpenBrace)
 41413                {
 41414                    StartObject();
 41415                }
 15184416                else if (marker == JsonConstants.OpenBracket)
 677417                {
 677418                    StartArray();
 677419                }
 14507420                else if (JsonHelpers.IsDigit(marker) || marker == '-')
 166421                {
 166422                    return ConsumeNumberMultiSegment();
 423                }
 14341424                else if (marker == 'f')
 210425                {
 210426                    return ConsumeLiteralMultiSegment(JsonConstants.FalseValue, JsonTokenType.False);
 427                }
 14131428                else if (marker == 't')
 126429                {
 126430                    return ConsumeLiteralMultiSegment(JsonConstants.TrueValue, JsonTokenType.True);
 431                }
 14005432                else if (marker == 'n')
 168433                {
 168434                    return ConsumeLiteralMultiSegment(JsonConstants.NullValue, JsonTokenType.Null);
 435                }
 436                else
 13837437                {
 13837438                    switch (_readerOptions.CommentHandling)
 439                    {
 440                        case JsonCommentHandling.Disallow:
 11429441                            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:
 2408455                            Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Skip);
 2408456                            if (marker == JsonConstants.Slash)
 574457                            {
 574458                                SequencePosition copy = _currentPosition;
 574459                                if (SkipCommentMultiSegment(out _))
 492460                                {
 492461                                    if (_consumed >= (uint)_buffer.Length)
 369462                                    {
 369463                                        if (_isNotPrimitive && IsLastSpan && _tokenType != JsonTokenType.EndArray && _to
 0464                                        {
 0465                                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidEndO
 466                                        }
 369467                                        if (!GetNextSpan())
 369468                                        {
 369469                                            if (_isNotPrimitive && IsLastSpan && _tokenType != JsonTokenType.EndArray &&
 0470                                            {
 0471                                                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.Invalid
 472                                            }
 369473                                            _currentPosition = copy;
 369474                                            return false;
 475                                        }
 0476                                    }
 477
 123478                                    marker = _buffer[_consumed];
 479
 480                                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not ne
 123481                                    if (marker <= JsonConstants.Space)
 41482                                    {
 41483                                        SkipWhiteSpaceMultiSegment();
 41484                                        if (!HasMoreDataMultiSegment())
 0485                                        {
 0486                                            _currentPosition = copy;
 0487                                            return false;
 488                                        }
 41489                                        marker = _buffer[_consumed];
 41490                                    }
 491
 123492                                    TokenStartIndex = BytesConsumed;
 493
 494                                    // Skip comments and consume the actual JSON value.
 123495                                    continue;
 496                                }
 0497                                _currentPosition = copy;
 0498                                return false;
 499                            }
 1834500                            break;
 501                    }
 13263502                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfValueNotFound, marke
 503                }
 718504                break;
 505            }
 718506            return true;
 6965507        }
 508
 509        // Consumes 'null', or 'true', or 'false'
 510        private bool ConsumeLiteralMultiSegment(ReadOnlySpan<byte> literal, JsonTokenType tokenType)
 504511        {
 504512            ReadOnlySpan<byte> span = _buffer.Slice(_consumed);
 504513            Debug.Assert(span.Length > 0);
 504514            Debug.Assert(span[0] == 'n' || span[0] == 't' || span[0] == 'f');
 515
 504516            int consumed = literal.Length;
 517
 504518            if (!span.StartsWith(literal))
 504519            {
 504520                int prevConsumed = _consumed;
 504521                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 bool CheckLiteralMultiSegment(ReadOnlySpan<byte> span, ReadOnlySpan<byte> literal, out int consumed)
 504539        {
 504540            Debug.Assert(span.Length > 0 && span[0] == literal[0] && literal.Length <= JsonConstants.MaximumLiteralLengt
 541
 504542            Span<byte> readSoFar = stackalloc byte[JsonConstants.MaximumLiteralLength];
 504543            int written = 0;
 544
 504545            long prevTotalConsumed = _totalConsumed;
 504546            SequencePosition copy = _currentPosition;
 504547            if (span.Length >= literal.Length || IsLastSpan)
 210548            {
 210549                _bytePositionInLine += FindMismatch(span, literal);
 550
 210551                int amountToWrite = AmountToWrite(span, _bytePositionInLine, readSoFar, written);
 210552                span.Slice(0, amountToWrite).CopyTo(readSoFar);
 210553                written += amountToWrite;
 210554                goto Throw;
 555            }
 556            else
 294557            {
 294558                if (!literal.StartsWith(span))
 42559                {
 42560                    _bytePositionInLine += FindMismatch(span, literal);
 42561                    int amountToWrite = AmountToWrite(span, _bytePositionInLine, readSoFar, written);
 42562                    span.Slice(0, amountToWrite).CopyTo(readSoFar);
 42563                    written += amountToWrite;
 42564                    goto Throw;
 565                }
 566
 252567                ReadOnlySpan<byte> leftToMatch = literal.Slice(span.Length);
 568
 252569                SequencePosition startPosition = _currentPosition;
 252570                int startConsumed = _consumed;
 252571                int alreadyMatched = literal.Length - leftToMatch.Length;
 252572                while (true)
 252573                {
 252574                    _totalConsumed += alreadyMatched;
 252575                    _bytePositionInLine += alreadyMatched;
 252576                    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
 252588                    int amountToWrite = Math.Min(span.Length, readSoFar.Length - written);
 252589                    span.Slice(0, amountToWrite).CopyTo(readSoFar.Slice(written));
 252590                    written += amountToWrite;
 591
 252592                    span = _buffer;
 593
 252594                    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
 252604                    if (!leftToMatch.StartsWith(span))
 252605                    {
 252606                        _bytePositionInLine += FindMismatch(span, leftToMatch);
 607
 252608                        amountToWrite = AmountToWrite(span, _bytePositionInLine, readSoFar, written);
 252609                        span.Slice(0, amountToWrite).CopyTo(readSoFar.Slice(written));
 252610                        written += amountToWrite;
 611
 252612                        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
 504621            {
 504622                return Math.Min(
 504623                    readSoFar.Length - written,
 504624                    Math.Min(span.Length, (int)bytePositionInLine + 1));
 504625            }
 504626        Throw:
 504627            _totalConsumed = prevTotalConsumed;
 504628            consumed = default;
 504629            _currentPosition = copy;
 504630            throw GetInvalidLiteralMultiSegment(readSoFar.Slice(0, written).ToArray());
 0631        }
 632
 633        private static int FindMismatch(ReadOnlySpan<byte> span, ReadOnlySpan<byte> literal)
 504634        {
 504635            Debug.Assert(span.Length > 0);
 636
 637            int indexOfFirstMismatch;
 638
 639#if NET
 504640            indexOfFirstMismatch = span.CommonPrefixLength(literal);
 641#else
 642            int minLength = Math.Min(span.Length, literal.Length);
 643            for (indexOfFirstMismatch = 0; indexOfFirstMismatch < minLength; indexOfFirstMismatch++)
 644            {
 645                if (span[indexOfFirstMismatch] != literal[indexOfFirstMismatch])
 646                {
 647                    break;
 648                }
 649            }
 650#endif
 651
 504652            Debug.Assert(indexOfFirstMismatch >= 0 && indexOfFirstMismatch < literal.Length);
 653
 504654            return indexOfFirstMismatch;
 504655        }
 656
 657        private JsonException GetInvalidLiteralMultiSegment(ReadOnlySpan<byte> span)
 504658        {
 504659            byte firstByte = span[0];
 660
 661            ExceptionResource resource;
 504662            switch (firstByte)
 663            {
 664                case (byte)'t':
 126665                    resource = ExceptionResource.ExpectedTrue;
 126666                    break;
 667                case (byte)'f':
 210668                    resource = ExceptionResource.ExpectedFalse;
 210669                    break;
 670                default:
 168671                    Debug.Assert(firstByte == 'n');
 168672                    resource = ExceptionResource.ExpectedNull;
 168673                    break;
 674            }
 504675            return ThrowHelper.GetJsonReaderException(ref this, resource, nextByte: default, bytes: span);
 504676        }
 677
 678        private bool ConsumeNumberMultiSegment()
 166679        {
 166680            if (!TryGetNumberMultiSegment(_buffer.Slice(_consumed), out int consumed))
 0681            {
 0682                return false;
 683            }
 684
 40685            _tokenType = JsonTokenType.Number;
 40686            _consumed += consumed;
 687
 40688            if (_consumed >= (uint)_buffer.Length)
 0689            {
 0690                Debug.Assert(IsLastSpan);
 691
 692                // If there is no more data, and the JSON is not a single value, throw.
 0693                if (_isNotPrimitive)
 0694                {
 0695                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, _buffer
 696                }
 0697            }
 698
 699            // If there is more data and the JSON is not a single value, assert that there is an end of number delimiter
 700            // Else, if either the JSON is a single value XOR if there is no more data, don't assert anything since ther
 40701            Debug.Assert(
 40702                ((_consumed < _buffer.Length) &&
 40703                !_isNotPrimitive &&
 40704                JsonConstants.Delimiters.Contains(_buffer[_consumed]))
 40705                || (_isNotPrimitive ^ (_consumed >= (uint)_buffer.Length)));
 706
 40707            return true;
 40708        }
 709
 710        private bool ConsumePropertyNameMultiSegment()
 8711        {
 8712            _trailingCommaBeforeComment = false;
 713
 8714            if (!ConsumeStringMultiSegment())
 0715            {
 0716                return false;
 717            }
 718
 0719            if (!HasMoreDataMultiSegment(ExceptionResource.ExpectedValueAfterPropertyNameNotFound))
 0720            {
 0721                return false;
 722            }
 723
 0724            byte first = _buffer[_consumed];
 725
 726            // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 727            // We do not validate if 'first' is an invalid JSON byte here (such as control characters).
 728            // Those cases are captured below where we only accept ':'.
 0729            if (first <= JsonConstants.Space)
 0730            {
 0731                SkipWhiteSpaceMultiSegment();
 0732                if (!HasMoreDataMultiSegment(ExceptionResource.ExpectedValueAfterPropertyNameNotFound))
 0733                {
 0734                    return false;
 735                }
 0736                first = _buffer[_consumed];
 0737            }
 738
 739            // The next character must be a key / value separator. Validate and skip.
 0740            if (first != JsonConstants.KeyValueSeparator)
 0741            {
 0742                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedSeparatorAfterPropertyNameNotFo
 743            }
 744
 0745            _consumed++;
 0746            _bytePositionInLine++;
 0747            _tokenType = JsonTokenType.PropertyName;
 0748            return true;
 0749        }
 750
 751        private bool ConsumeStringMultiSegment()
 6240752        {
 6240753            Debug.Assert(_buffer.Length >= _consumed + 1);
 6240754            Debug.Assert(_buffer[_consumed] == JsonConstants.Quote);
 755
 756            // Create local copy to avoid bounds checks.
 6240757            ReadOnlySpan<byte> localBuffer = _buffer.Slice(_consumed + 1);
 758
 759            // Vectorized search for either quote, backslash, or any control character.
 760            // If the first found byte is a quote, we have reached an end of string, and
 761            // can avoid validation.
 762            // Otherwise, in the uncommon case, iterate one character at a time and validate.
 6240763            int idx = localBuffer.IndexOfQuoteOrAnyControlOrBackSlash();
 764
 6240765            if (idx >= 0)
 2108766            {
 2108767                byte foundByte = localBuffer[idx];
 2108768                if (foundByte == JsonConstants.Quote)
 1974769                {
 1974770                    _bytePositionInLine += idx + 2; // Add 2 for the start and end quotes.
 1974771                    ValueSpan = localBuffer.Slice(0, idx);
 1974772                    HasValueSequence = false;
 1974773                    ValueIsEscaped = false;
 1974774                    _tokenType = JsonTokenType.String;
 1974775                    _consumed += idx + 2;
 1974776                    return true;
 777                }
 778                else
 134779                {
 134780                    return ConsumeStringAndValidateMultiSegment(localBuffer, idx);
 781                }
 782            }
 783            else
 4132784            {
 4132785                if (IsLastSpan)
 0786                {
 0787                    _bytePositionInLine += localBuffer.Length + 1;  // Account for the start quote
 0788                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound);
 789                }
 4132790                return ConsumeStringNextSegment();
 791            }
 5838792        }
 793
 794        private bool ConsumeStringNextSegment()
 4132795        {
 4132796            PartialStateForRollback rollBackState = CaptureState();
 797
 798            SequencePosition end;
 4132799            HasValueSequence = true;
 4132800            int leftOver = _buffer.Length - _consumed;
 801
 6080802            while (true)
 6080803            {
 6080804                if (!GetNextSpan())
 168805                {
 168806                    if (IsLastSpan)
 168807                    {
 168808                        _bytePositionInLine += leftOver;
 168809                        RollBackState(rollBackState, isError: true);
 168810                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound);
 811                    }
 0812                    RollBackState(rollBackState);
 0813                    return false;
 814                }
 815
 816                //Create local copy to avoid bounds checks.
 5912817                ReadOnlySpan<byte> localBuffer = _buffer;
 5912818                int idx = localBuffer.IndexOfQuoteOrAnyControlOrBackSlash();
 819
 5912820                if (idx >= 0)
 3964821                {
 3964822                    byte foundByte = localBuffer[idx];
 3964823                    if (foundByte == JsonConstants.Quote)
 3864824                    {
 3864825                        end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetInteger() + idx);
 3864826                        _bytePositionInLine += leftOver + idx + 1;  // Add 1 for the end quote of the string.
 3864827                        _totalConsumed += leftOver;
 3864828                        _consumed = idx + 1;    // Add 1 for the end quote of the string.
 3864829                        ValueIsEscaped = false;
 3864830                        break;
 831                    }
 832                    else
 100833                    {
 100834                        _bytePositionInLine += leftOver + idx;
 100835                        ValueIsEscaped = true;
 836
 100837                        bool nextCharEscaped = false;
 100838                        while (true)
 100839                        {
 100840                        StartOfLoop:
 100841                            for (; idx < localBuffer.Length; idx++)
 100842                            {
 100843                                byte currentByte = localBuffer[idx];
 100844                                if (currentByte == JsonConstants.Quote)
 0845                                {
 0846                                    if (!nextCharEscaped)
 0847                                    {
 0848                                        goto Done;
 849                                    }
 0850                                    nextCharEscaped = false;
 0851                                }
 100852                                else if (currentByte == JsonConstants.BackSlash)
 0853                                {
 0854                                    nextCharEscaped = !nextCharEscaped;
 0855                                }
 100856                                else if (nextCharEscaped)
 0857                                {
 0858                                    int index = JsonConstants.EscapableChars.IndexOf(currentByte);
 0859                                    if (index == -1)
 0860                                    {
 0861                                        RollBackState(rollBackState, isError: true);
 0862                                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacte
 863                                    }
 864
 0865                                    if (currentByte == 'u')
 0866                                    {
 867                                        // Expecting 4 hex digits to follow the escaped 'u'
 0868                                        _bytePositionInLine++;  // move past the 'u'
 869
 0870                                        int numberOfHexDigits = 0;
 0871                                        int j = idx + 1;
 0872                                        while (true)
 0873                                        {
 0874                                            for (; j < localBuffer.Length; j++)
 0875                                            {
 0876                                                byte nextByte = localBuffer[j];
 0877                                                if (!JsonReaderHelper.IsHexDigit(nextByte))
 0878                                                {
 0879                                                    RollBackState(rollBackState, isError: true);
 0880                                                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.Inv
 881                                                }
 0882                                                numberOfHexDigits++;
 0883                                                _bytePositionInLine++;
 0884                                                if (numberOfHexDigits >= 4)
 0885                                                {
 0886                                                    nextCharEscaped = false;
 0887                                                    idx = j + 1; // Skip the 4 hex digits, the for loop accounts for idx
 0888                                                    goto StartOfLoop;
 889                                                }
 0890                                            }
 891
 0892                                            if (!GetNextSpan())
 0893                                            {
 0894                                                if (IsLastSpan)
 0895                                                {
 0896                                                    RollBackState(rollBackState, isError: true);
 0897                                                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.End
 898                                                }
 899
 900                                                // We found less than 4 hex digits.
 0901                                                RollBackState(rollBackState);
 0902                                                return false;
 903                                            }
 904
 0905                                            _totalConsumed += localBuffer.Length;
 906
 0907                                            localBuffer = _buffer;
 0908                                            j = 0;
 0909                                        }
 910                                    }
 0911                                    nextCharEscaped = false;
 0912                                }
 100913                                else if (currentByte < JsonConstants.Space)
 100914                                {
 100915                                    RollBackState(rollBackState, isError: true);
 100916                                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterWit
 917                                }
 918
 0919                                _bytePositionInLine++;
 0920                            }
 921
 0922                            if (!GetNextSpan())
 0923                            {
 0924                                if (IsLastSpan)
 0925                                {
 0926                                    RollBackState(rollBackState, isError: true);
 0927                                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound
 928                                }
 0929                                RollBackState(rollBackState);
 0930                                return false;
 931                            }
 932
 0933                            _totalConsumed += localBuffer.Length;
 0934                            localBuffer = _buffer;
 0935                            idx = 0;
 0936                        }
 937
 0938                    Done:
 0939                        _bytePositionInLine++;  // Add 1 for the end quote of the string.
 0940                        _consumed = idx + 1;    // Add 1 for the end quote of the string.
 0941                        _totalConsumed += leftOver;
 0942                        end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetInteger() + idx);
 0943                        break;
 944                    }
 945                }
 946
 1948947                _totalConsumed += localBuffer.Length;
 1948948                _bytePositionInLine += localBuffer.Length;
 1948949            }
 950
 3864951            SequencePosition start = rollBackState.GetStartPosition(offset: 1); // Offset for the starting quote
 3864952            ValueSequence = _sequence.Slice(start, end);
 3864953            _tokenType = JsonTokenType.String;
 3864954            return true;
 3864955        }
 956
 957        // Found a backslash or control characters which are considered invalid within a string.
 958        // Search through the rest of the string one byte at a time.
 959        // https://tools.ietf.org/html/rfc8259#section-7
 960        private bool ConsumeStringAndValidateMultiSegment(ReadOnlySpan<byte> data, int idx)
 134961        {
 134962            Debug.Assert(idx >= 0 && idx < data.Length);
 134963            Debug.Assert(data[idx] != JsonConstants.Quote);
 134964            Debug.Assert(data[idx] == JsonConstants.BackSlash || data[idx] < JsonConstants.Space);
 965
 134966            PartialStateForRollback rollBackState = CaptureState();
 967
 968            SequencePosition end;
 134969            HasValueSequence = false;
 134970            int leftOverFromConsumed = _buffer.Length - _consumed;
 971
 134972            _bytePositionInLine += idx + 1; // Add 1 for the first quote
 973
 134974            bool nextCharEscaped = false;
 134975            while (true)
 134976            {
 134977            StartOfLoop:
 134978                for (; idx < data.Length; idx++)
 134979                {
 134980                    byte currentByte = data[idx];
 134981                    if (currentByte == JsonConstants.Quote)
 0982                    {
 0983                        if (!nextCharEscaped)
 0984                        {
 0985                            goto Done;
 986                        }
 0987                        nextCharEscaped = false;
 0988                    }
 134989                    else if (currentByte == JsonConstants.BackSlash)
 0990                    {
 0991                        nextCharEscaped = !nextCharEscaped;
 0992                    }
 134993                    else if (nextCharEscaped)
 0994                    {
 0995                        int index = JsonConstants.EscapableChars.IndexOf(currentByte);
 0996                        if (index == -1)
 0997                        {
 0998                            RollBackState(rollBackState, isError: true);
 0999                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterAfterEscape
 1000                        }
 1001
 01002                        if (currentByte == 'u')
 01003                        {
 1004                            // Expecting 4 hex digits to follow the escaped 'u'
 01005                            _bytePositionInLine++;  // move past the 'u'
 1006
 01007                            int numberOfHexDigits = 0;
 01008                            int j = idx + 1;
 01009                            while (true)
 01010                            {
 01011                                for (; j < data.Length; j++)
 01012                                {
 01013                                    byte nextByte = data[j];
 01014                                    if (!JsonReaderHelper.IsHexDigit(nextByte))
 01015                                    {
 01016                                        RollBackState(rollBackState, isError: true);
 01017                                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidHexChara
 1018                                    }
 01019                                    numberOfHexDigits++;
 01020                                    _bytePositionInLine++;
 01021                                    if (numberOfHexDigits >= 4)
 01022                                    {
 01023                                        nextCharEscaped = false;
 01024                                        idx = j + 1; // Skip the 4 hex digits, the for loop accounts for idx incrementin
 01025                                        goto StartOfLoop;
 1026                                    }
 01027                                }
 1028
 01029                                if (!GetNextSpan())
 01030                                {
 01031                                    if (IsLastSpan)
 01032                                    {
 01033                                        RollBackState(rollBackState, isError: true);
 01034                                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotF
 1035                                    }
 1036
 1037                                    // We found less than 4 hex digits.
 01038                                    RollBackState(rollBackState);
 01039                                    return false;
 1040                                }
 1041
 1042                                // Do not add the left over for the first segment to total consumed
 01043                                if (HasValueSequence)
 01044                                {
 01045                                    _totalConsumed += data.Length;
 01046                                }
 1047
 01048                                data = _buffer;
 01049                                j = 0;
 01050                                HasValueSequence = true;
 01051                            }
 1052                        }
 01053                        nextCharEscaped = false;
 01054                    }
 1341055                    else if (currentByte < JsonConstants.Space)
 1341056                    {
 1341057                        RollBackState(rollBackState, isError: true);
 1341058                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterWithinString, c
 1059                    }
 1060
 01061                    _bytePositionInLine++;
 01062                }
 1063
 01064                if (!GetNextSpan())
 01065                {
 01066                    if (IsLastSpan)
 01067                    {
 01068                        RollBackState(rollBackState, isError: true);
 01069                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.EndOfStringNotFound);
 1070                    }
 01071                    RollBackState(rollBackState);
 01072                    return false;
 1073                }
 1074
 1075                // Do not add the left over for the first segment to total consumed
 01076                if (HasValueSequence)
 01077                {
 01078                    _totalConsumed += data.Length;
 01079                }
 1080
 01081                data = _buffer;
 01082                idx = 0;
 01083                HasValueSequence = true;
 01084            }
 1085
 01086        Done:
 01087            if (HasValueSequence)
 01088            {
 01089                _bytePositionInLine++;  // Add 1 for the end quote of the string.
 01090                _consumed = idx + 1;    // Add 1 for the end quote of the string.
 01091                _totalConsumed += leftOverFromConsumed;
 01092                end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetInteger() + idx);
 01093                SequencePosition start = rollBackState.GetStartPosition(offset: 1); // Offset for the starting quote
 01094                ValueSequence = _sequence.Slice(start, end);
 01095            }
 1096            else
 01097            {
 01098                _bytePositionInLine++;  // Add 1 for the end quote
 01099                _consumed += idx + 2;
 01100                ValueSpan = data.Slice(0, idx);
 01101            }
 1102
 01103            ValueIsEscaped = true;
 01104            _tokenType = JsonTokenType.String;
 01105            return true;
 01106        }
 1107
 1108        private void RollBackState(scoped in PartialStateForRollback state, bool isError = false)
 17041109        {
 17041110            _totalConsumed = state._prevTotalConsumed;
 1111
 1112            // Don't roll back byte position in line for invalid JSON since that is provided
 1113            // to the user within the exception.
 17041114            if (!isError)
 01115            {
 01116                _bytePositionInLine = state._prevBytePositionInLine;
 01117            }
 1118
 17041119            _consumed = state._prevConsumed;
 17041120            _currentPosition = state._prevCurrentPosition;
 17041121        }
 1122
 1123        // https://tools.ietf.org/html/rfc7159#section-6
 1124        private bool TryGetNumberMultiSegment(ReadOnlySpan<byte> data, out int consumed)
 40301125        {
 1126            // TODO: https://github.com/dotnet/runtime/issues/27837
 40301127            Debug.Assert(data.Length > 0);
 1128
 40301129            PartialStateForRollback rollBackState = CaptureState();
 1130
 40301131            consumed = 0;
 40301132            int i = 0;
 1133
 40301134            ConsumeNumberResult signResult = ConsumeNegativeSignMultiSegment(ref data, ref i, rollBackState);
 39091135            if (signResult == ConsumeNumberResult.NeedMoreData)
 01136            {
 01137                RollBackState(rollBackState);
 01138                return false;
 1139            }
 1140
 39091141            Debug.Assert(signResult == ConsumeNumberResult.OperationIncomplete);
 1142
 39091143            byte nextByte = data[i];
 39091144            Debug.Assert(nextByte >= '0' && nextByte <= '9');
 1145
 39091146            if (nextByte == '0')
 2421147            {
 2421148                ConsumeNumberResult result = ConsumeZeroMultiSegment(ref data, ref i, rollBackState);
 01149                if (result == ConsumeNumberResult.NeedMoreData)
 01150                {
 01151                    RollBackState(rollBackState);
 01152                    return false;
 1153                }
 01154                if (result == ConsumeNumberResult.Success)
 01155                {
 01156                    goto Done;
 1157                }
 1158
 01159                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 01160                nextByte = data[i];
 01161            }
 1162            else
 36671163            {
 36671164                ConsumeNumberResult result = ConsumeIntegerDigitsMultiSegment(ref data, ref i);
 36671165                if (result == ConsumeNumberResult.NeedMoreData)
 01166                {
 01167                    RollBackState(rollBackState);
 01168                    return false;
 1169                }
 36671170                if (result == ConsumeNumberResult.Success)
 26021171                {
 26021172                    goto Done;
 1173                }
 1174
 10651175                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 10651176                nextByte = data[i];
 10651177                if (nextByte != '.' && nextByte != 'E' && nextByte != 'e')
 6031178                {
 6031179                    RollBackState(rollBackState, isError: true);
 6031180                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, nextByt
 1181                }
 4621182            }
 1183
 4621184            Debug.Assert(nextByte == '.' || nextByte == 'E' || nextByte == 'e');
 1185
 4621186            if (nextByte == '.')
 2521187            {
 2521188                i++;
 2521189                _bytePositionInLine++;
 2521190                ConsumeNumberResult result = ConsumeDecimalDigitsMultiSegment(ref data, ref i, rollBackState);
 2101191                if (result == ConsumeNumberResult.NeedMoreData)
 01192                {
 01193                    RollBackState(rollBackState);
 01194                    return false;
 1195                }
 2101196                if (result == ConsumeNumberResult.Success)
 841197                {
 841198                    goto Done;
 1199                }
 1200
 1261201                Debug.Assert(result == ConsumeNumberResult.OperationIncomplete);
 1261202                nextByte = data[i];
 1261203                if (nextByte != 'E' && nextByte != 'e')
 1261204                {
 1261205                    RollBackState(rollBackState, isError: true);
 1261206                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedNextDigitEValueNotFound, ne
 1207                }
 01208            }
 1209
 2101210            Debug.Assert(nextByte == 'E' || nextByte == 'e');
 2101211            i++;
 2101212            _bytePositionInLine++;
 1213
 2101214            signResult = ConsumeSignMultiSegment(ref data, ref i, rollBackState);
 1261215            if (signResult == ConsumeNumberResult.NeedMoreData)
 01216            {
 01217                RollBackState(rollBackState);
 01218                return false;
 1219            }
 1220
 1261221            Debug.Assert(signResult == ConsumeNumberResult.OperationIncomplete);
 1222
 1261223            i++;
 1261224            _bytePositionInLine++;
 1261225            ConsumeNumberResult resultExponent = ConsumeIntegerDigitsMultiSegment(ref data, ref i);
 1261226            if (resultExponent == ConsumeNumberResult.NeedMoreData)
 01227            {
 01228                RollBackState(rollBackState);
 01229                return false;
 1230            }
 1261231            if (resultExponent == ConsumeNumberResult.Success)
 421232            {
 421233                goto Done;
 1234            }
 1235
 841236            Debug.Assert(resultExponent == ConsumeNumberResult.OperationIncomplete);
 1237
 841238            RollBackState(rollBackState, isError: true);
 841239            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndOfDigitNotFound, data[i]);
 1240
 27281241        Done:
 27281242            if (HasValueSequence)
 16541243            {
 16541244                SequencePosition start = rollBackState.GetStartPosition();
 16541245                SequencePosition end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetInteger() 
 16541246                ValueSequence = _sequence.Slice(start, end);
 16541247                consumed = i;
 16541248            }
 1249            else
 10741250            {
 10741251                ValueSpan = data.Slice(0, i);
 10741252                consumed = i;
 10741253            }
 27281254            return true;
 27281255        }
 1256
 1257        private ConsumeNumberResult ConsumeNegativeSignMultiSegment(ref ReadOnlySpan<byte> data, scoped ref int i, scope
 40301258        {
 40301259            Debug.Assert(i == 0);
 40301260            byte nextByte = data[i];
 1261
 40301262            if (nextByte == '-')
 2031263            {
 2031264                i++;
 2031265                _bytePositionInLine++;
 2031266                if (i >= data.Length)
 661267                {
 661268                    if (IsLastSpan)
 01269                    {
 01270                        RollBackState(rollBackState, isError: true);
 01271                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1272                    }
 661273                    if (!GetNextSpan())
 01274                    {
 01275                        if (IsLastSpan)
 01276                        {
 01277                            RollBackState(rollBackState, isError: true);
 01278                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfD
 1279                        }
 01280                        return ConsumeNumberResult.NeedMoreData;
 1281                    }
 661282                    Debug.Assert(i == 1);
 661283                    _totalConsumed += i;
 661284                    HasValueSequence = true;
 661285                    i = 0;
 661286                    data = _buffer;
 661287                }
 1288
 2031289                nextByte = data[i];
 2031290                if (!JsonHelpers.IsDigit(nextByte))
 1211291                {
 1211292                    RollBackState(rollBackState, isError: true);
 1211293                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nex
 1294                }
 821295            }
 39091296            return ConsumeNumberResult.OperationIncomplete;
 39091297        }
 1298
 1299        private ConsumeNumberResult ConsumeZeroMultiSegment(ref ReadOnlySpan<byte> data, scoped ref int i, scoped in Par
 2421300        {
 2421301            Debug.Assert(data[i] == (byte)'0');
 2421302            Debug.Assert(i == 0 || i == 1);
 2421303            i++;
 2421304            _bytePositionInLine++;
 1305            byte nextByte;
 2421306            if (i < data.Length)
 1921307            {
 1921308                nextByte = data[i];
 1921309                if (JsonConstants.Delimiters.Contains(nextByte))
 01310                {
 01311                    return ConsumeNumberResult.Success;
 1312                }
 1921313            }
 1314            else
 501315            {
 501316                if (IsLastSpan)
 01317                {
 1318                    // A payload containing a single value: "0" is valid
 1319                    // If we are dealing with multi-value JSON,
 1320                    // ConsumeNumber will validate that we have a delimiter following the "0".
 01321                    return ConsumeNumberResult.Success;
 1322                }
 1323
 501324                if (!GetNextSpan())
 01325                {
 01326                    if (IsLastSpan)
 01327                    {
 01328                        return ConsumeNumberResult.Success;
 1329                    }
 01330                    return ConsumeNumberResult.NeedMoreData;
 1331                }
 1332
 501333                _totalConsumed += i;
 501334                HasValueSequence = true;
 501335                i = 0;
 501336                data = _buffer;
 501337                nextByte = data[i];
 501338                if (JsonConstants.Delimiters.Contains(nextByte))
 01339                {
 01340                    return ConsumeNumberResult.Success;
 1341                }
 501342            }
 2421343            nextByte = data[i];
 2421344            if (nextByte != '.' && nextByte != 'E' && nextByte != 'e')
 2421345            {
 2421346                RollBackState(rollBackState, isError: true);
 2421347                ThrowHelper.ThrowJsonReaderException(ref this,
 2421348                    JsonHelpers.IsInRangeInclusive(nextByte, '0', '9') ? ExceptionResource.InvalidLeadingZeroInNumber : 
 2421349                    nextByte);
 1350            }
 1351
 01352            return ConsumeNumberResult.OperationIncomplete;
 01353        }
 1354
 1355        private ConsumeNumberResult ConsumeIntegerDigitsMultiSegment(ref ReadOnlySpan<byte> data, scoped ref int i)
 40031356        {
 40031357            byte nextByte = default;
 40031358            int counter = 0;
 360271359            for (; i < data.Length; i++)
 175971360            {
 175971361                nextByte = data[i];
 175971362                if (!JsonHelpers.IsDigit(nextByte))
 15851363                {
 15851364                    break;
 1365                }
 160121366                counter++;
 160121367            }
 40031368            if (i >= data.Length)
 24181369            {
 24181370                if (IsLastSpan)
 01371                {
 1372                    // A payload containing a single value of integers (e.g. "12") is valid
 1373                    // If we are dealing with multi-value JSON,
 1374                    // ConsumeNumber will validate that we have a delimiter following the integer.
 01375                    _bytePositionInLine += counter;
 01376                    return ConsumeNumberResult.Success;
 1377                }
 1378
 38881379                while (true)
 38881380                {
 38881381                    if (!GetNextSpan())
 01382                    {
 01383                        if (IsLastSpan)
 01384                        {
 01385                            _bytePositionInLine += counter;
 01386                            return ConsumeNumberResult.Success;
 1387                        }
 01388                        return ConsumeNumberResult.NeedMoreData;
 1389                    }
 1390
 38881391                    _totalConsumed += i;
 38881392                    _bytePositionInLine += counter;
 38881393                    counter = 0;
 38881394                    HasValueSequence = true;
 38881395                    i = 0;
 38881396                    data = _buffer;
 242161397                    for (; i < data.Length; i++)
 122881398                    {
 122881399                        nextByte = data[i];
 122881400                        if (!JsonHelpers.IsDigit(nextByte))
 21241401                        {
 21241402                            break;
 1403                        }
 101641404                    }
 38881405                    _bytePositionInLine += i;
 38881406                    if (i >= data.Length)
 17641407                    {
 17641408                        if (IsLastSpan)
 2941409                        {
 2941410                            return ConsumeNumberResult.Success;
 1411                        }
 14701412                    }
 1413                    else
 21241414                    {
 21241415                        break;
 1416                    }
 14701417                }
 1418
 21241419            }
 1420            else
 15851421            {
 15851422                _bytePositionInLine += counter;
 15851423            }
 1424
 37091425            if (JsonConstants.Delimiters.Contains(nextByte))
 24341426            {
 24341427                return ConsumeNumberResult.Success;
 1428            }
 1429
 12751430            return ConsumeNumberResult.OperationIncomplete;
 40031431        }
 1432
 1433        private ConsumeNumberResult ConsumeDecimalDigitsMultiSegment(ref ReadOnlySpan<byte> data, scoped ref int i, scop
 2521434        {
 2521435            if (i >= data.Length)
 421436            {
 421437                if (IsLastSpan)
 01438                {
 01439                    RollBackState(rollBackState, isError: true);
 01440                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData);
 1441                }
 421442                if (!GetNextSpan())
 01443                {
 01444                    if (IsLastSpan)
 01445                    {
 01446                        RollBackState(rollBackState, isError: true);
 01447                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1448                    }
 01449                    return ConsumeNumberResult.NeedMoreData;
 1450                }
 421451                _totalConsumed += i;
 421452                HasValueSequence = true;
 421453                i = 0;
 421454                data = _buffer;
 421455            }
 2521456            byte nextByte = data[i];
 2521457            if (!JsonHelpers.IsDigit(nextByte))
 421458            {
 421459                RollBackState(rollBackState, isError: true);
 421460                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterDecimal, next
 1461            }
 2101462            i++;
 2101463            _bytePositionInLine++;
 2101464            return ConsumeIntegerDigitsMultiSegment(ref data, ref i);
 2101465        }
 1466
 1467        private ConsumeNumberResult ConsumeSignMultiSegment(ref ReadOnlySpan<byte> data, scoped ref int i, scoped in Par
 2101468        {
 2101469            if (i >= data.Length)
 421470            {
 421471                if (IsLastSpan)
 01472                {
 01473                    RollBackState(rollBackState, isError: true);
 01474                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData);
 1475                }
 1476
 421477                if (!GetNextSpan())
 01478                {
 01479                    if (IsLastSpan)
 01480                    {
 01481                        RollBackState(rollBackState, isError: true);
 01482                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1483                    }
 01484                    return ConsumeNumberResult.NeedMoreData;
 1485                }
 421486                _totalConsumed += i;
 421487                HasValueSequence = true;
 421488                i = 0;
 421489                data = _buffer;
 421490            }
 1491
 2101492            byte nextByte = data[i];
 2101493            if (nextByte == '+' || nextByte == '-')
 01494            {
 01495                i++;
 01496                _bytePositionInLine++;
 01497                if (i >= data.Length)
 01498                {
 01499                    if (IsLastSpan)
 01500                    {
 01501                        RollBackState(rollBackState, isError: true);
 01502                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfData)
 1503                    }
 1504
 01505                    if (!GetNextSpan())
 01506                    {
 01507                        if (IsLastSpan)
 01508                        {
 01509                            RollBackState(rollBackState, isError: true);
 01510                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundEndOfD
 1511                        }
 01512                        return ConsumeNumberResult.NeedMoreData;
 1513                    }
 01514                    _totalConsumed += i;
 01515                    HasValueSequence = true;
 01516                    i = 0;
 01517                    data = _buffer;
 01518                }
 01519                nextByte = data[i];
 01520            }
 1521
 2101522            if (!JsonHelpers.IsDigit(nextByte))
 841523            {
 841524                RollBackState(rollBackState, isError: true);
 841525                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nextByt
 1526            }
 1527
 1261528            return ConsumeNumberResult.OperationIncomplete;
 1261529        }
 1530
 1531        private bool ConsumeNextTokenOrRollbackMultiSegment(byte marker)
 24081532        {
 24081533            long prevTotalConsumed = _totalConsumed;
 24081534            int prevConsumed = _consumed;
 24081535            long prevPosition = _bytePositionInLine;
 24081536            long prevLineNumber = _lineNumber;
 24081537            JsonTokenType prevTokenType = _tokenType;
 24081538            SequencePosition prevSequencePosition = _currentPosition;
 24081539            bool prevTrailingCommaBeforeComment = _trailingCommaBeforeComment;
 24081540            ConsumeTokenResult result = ConsumeNextTokenMultiSegment(marker);
 01541            if (result == ConsumeTokenResult.Success)
 01542            {
 01543                return true;
 1544            }
 01545            if (result == ConsumeTokenResult.NotEnoughDataRollBackState)
 01546            {
 01547                _consumed = prevConsumed;
 01548                _tokenType = prevTokenType;
 01549                _bytePositionInLine = prevPosition;
 01550                _lineNumber = prevLineNumber;
 01551                _totalConsumed = prevTotalConsumed;
 01552                _currentPosition = prevSequencePosition;
 01553                _trailingCommaBeforeComment = prevTrailingCommaBeforeComment;
 01554            }
 01555            return false;
 01556        }
 1557
 1558        /// <summary>
 1559        /// This method consumes the next token regardless of whether we are inside an object or an array.
 1560        /// For an object, it reads the next property name token. For an array, it just reads the next value.
 1561        /// </summary>
 1562        private ConsumeTokenResult ConsumeNextTokenMultiSegment(byte marker)
 24081563        {
 24081564            if (_readerOptions.CommentHandling != JsonCommentHandling.Disallow)
 11701565            {
 11701566                if (_readerOptions.CommentHandling == JsonCommentHandling.Allow)
 01567                {
 01568                    if (marker == JsonConstants.Slash)
 01569                    {
 01570                        return SkipOrConsumeCommentMultiSegmentWithRollback() ? ConsumeTokenResult.Success : ConsumeToke
 1571                    }
 01572                    if (_tokenType == JsonTokenType.Comment)
 01573                    {
 01574                        return ConsumeNextTokenFromLastNonCommentTokenMultiSegment();
 1575                    }
 01576                }
 1577                else
 11701578                {
 11701579                    Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Skip);
 11701580                    return ConsumeNextTokenUntilAfterAllCommentsAreSkippedMultiSegment(marker);
 1581                }
 01582            }
 1583
 12381584            if (_bitStack.CurrentDepth == 0)
 11791585            {
 11791586                if (_readerOptions.AllowMultipleValues)
 01587                {
 01588                    return ReadFirstTokenMultiSegment(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoug
 1589                }
 1590
 11791591                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, marker);
 1592            }
 1593
 591594            if (marker == JsonConstants.ListSeparator)
 401595            {
 401596                _consumed++;
 401597                _bytePositionInLine++;
 1598
 401599                if (_consumed >= (uint)_buffer.Length)
 161600                {
 161601                    if (IsLastSpan)
 01602                    {
 01603                        _consumed--;
 01604                        _bytePositionInLine--;
 01605                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 1606                    }
 161607                    if (!GetNextSpan())
 01608                    {
 01609                        if (IsLastSpan)
 01610                        {
 01611                            _consumed--;
 01612                            _bytePositionInLine--;
 01613                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrVa
 1614                        }
 01615                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 1616                    }
 161617                }
 401618                byte first = _buffer[_consumed];
 1619
 1620                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 401621                if (first <= JsonConstants.Space)
 01622                {
 01623                    SkipWhiteSpaceMultiSegment();
 1624                    // The next character must be a start of a property name or value.
 01625                    if (!HasMoreDataMultiSegment(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 01626                    {
 01627                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 1628                    }
 01629                    first = _buffer[_consumed];
 01630                }
 1631
 401632                TokenStartIndex = BytesConsumed;
 1633
 401634                if (_readerOptions.CommentHandling == JsonCommentHandling.Allow && first == JsonConstants.Slash)
 01635                {
 01636                    _trailingCommaBeforeComment = true;
 01637                    return SkipOrConsumeCommentMultiSegmentWithRollback() ? ConsumeTokenResult.Success : ConsumeTokenRes
 1638                }
 1639
 401640                if (_inObject)
 01641                {
 01642                    if (first != JsonConstants.Quote)
 01643                    {
 01644                        if (first == JsonConstants.CloseBrace)
 01645                        {
 01646                            if (_readerOptions.AllowTrailingCommas)
 01647                            {
 01648                                EndObject();
 01649                                return ConsumeTokenResult.Success;
 1650                            }
 01651                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 1652                        }
 01653                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 1654                    }
 01655                    return ConsumePropertyNameMultiSegment() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnough
 1656                }
 1657                else
 401658                {
 401659                    if (first == JsonConstants.CloseBracket)
 01660                    {
 01661                        if (_readerOptions.AllowTrailingCommas)
 01662                        {
 01663                            EndArray();
 01664                            return ConsumeTokenResult.Success;
 1665                        }
 01666                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 1667                    }
 401668                    return ConsumeValueMultiSegment(first) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughDa
 1669                }
 1670            }
 191671            else if (marker == JsonConstants.CloseBrace)
 01672            {
 01673                EndObject();
 01674            }
 191675            else if (marker == JsonConstants.CloseBracket)
 01676            {
 01677                EndArray();
 01678            }
 1679            else
 191680            {
 191681                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.FoundInvalidCharacter, marker);
 1682            }
 01683            return ConsumeTokenResult.Success;
 01684        }
 1685
 1686        private ConsumeTokenResult ConsumeNextTokenFromLastNonCommentTokenMultiSegment()
 01687        {
 01688            Debug.Assert(_readerOptions.CommentHandling == JsonCommentHandling.Allow);
 01689            Debug.Assert(_tokenType == JsonTokenType.Comment);
 1690
 01691            if (JsonReaderHelper.IsTokenTypePrimitive(_previousTokenType))
 01692            {
 01693                _tokenType = _inObject ? JsonTokenType.StartObject : JsonTokenType.StartArray;
 01694            }
 1695            else
 01696            {
 01697                _tokenType = _previousTokenType;
 01698            }
 1699
 01700            Debug.Assert(_tokenType != JsonTokenType.Comment);
 1701
 01702            if (!HasMoreDataMultiSegment())
 01703            {
 01704                goto RollBack;
 1705            }
 1706
 01707            byte first = _buffer[_consumed];
 1708
 1709            // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01710            if (first <= JsonConstants.Space)
 01711            {
 01712                SkipWhiteSpaceMultiSegment();
 01713                if (!HasMoreDataMultiSegment())
 01714                {
 01715                    goto RollBack;
 1716                }
 01717                first = _buffer[_consumed];
 01718            }
 1719
 01720            if (_bitStack.CurrentDepth == 0 && _tokenType != JsonTokenType.None)
 01721            {
 01722                if (_readerOptions.AllowMultipleValues)
 01723                {
 01724                    return ReadFirstTokenMultiSegment(first) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnough
 1725                }
 1726
 01727                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, first);
 1728            }
 1729
 01730            Debug.Assert(first != JsonConstants.Slash);
 1731
 01732            TokenStartIndex = BytesConsumed;
 1733
 01734            if (first == JsonConstants.ListSeparator)
 01735            {
 1736                // A comma without some JSON value preceding it is invalid
 01737                if (_previousTokenType <= JsonTokenType.StartObject || _previousTokenType == JsonTokenType.StartArray ||
 01738                {
 01739                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueAfter
 1740                }
 1741
 01742                _consumed++;
 01743                _bytePositionInLine++;
 1744
 01745                if (_consumed >= (uint)_buffer.Length)
 01746                {
 01747                    if (IsLastSpan)
 01748                    {
 01749                        _consumed--;
 01750                        _bytePositionInLine--;
 01751                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 1752                    }
 01753                    if (!GetNextSpan())
 01754                    {
 01755                        if (IsLastSpan)
 01756                        {
 01757                            _consumed--;
 01758                            _bytePositionInLine--;
 01759                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrVa
 1760                        }
 01761                        goto RollBack;
 1762                    }
 01763                }
 01764                first = _buffer[_consumed];
 1765
 1766                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01767                if (first <= JsonConstants.Space)
 01768                {
 01769                    SkipWhiteSpaceMultiSegment();
 1770                    // The next character must be a start of a property name or value.
 01771                    if (!HasMoreDataMultiSegment(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 01772                    {
 01773                        goto RollBack;
 1774                    }
 01775                    first = _buffer[_consumed];
 01776                }
 1777
 01778                TokenStartIndex = BytesConsumed;
 1779
 01780                if (first == JsonConstants.Slash)
 01781                {
 01782                    _trailingCommaBeforeComment = true;
 01783                    if (SkipOrConsumeCommentMultiSegmentWithRollback())
 01784                    {
 01785                        goto Done;
 1786                    }
 1787                    else
 01788                    {
 01789                        goto RollBack;
 1790                    }
 1791                }
 1792
 01793                if (_inObject)
 01794                {
 01795                    if (first != JsonConstants.Quote)
 01796                    {
 01797                        if (first == JsonConstants.CloseBrace)
 01798                        {
 01799                            if (_readerOptions.AllowTrailingCommas)
 01800                            {
 01801                                EndObject();
 01802                                goto Done;
 1803                            }
 01804                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 1805                        }
 1806
 01807                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 1808                    }
 01809                    if (ConsumePropertyNameMultiSegment())
 01810                    {
 01811                        goto Done;
 1812                    }
 1813                    else
 01814                    {
 01815                        goto RollBack;
 1816                    }
 1817                }
 1818                else
 01819                {
 01820                    if (first == JsonConstants.CloseBracket)
 01821                    {
 01822                        if (_readerOptions.AllowTrailingCommas)
 01823                        {
 01824                            EndArray();
 01825                            goto Done;
 1826                        }
 01827                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 1828                    }
 1829
 01830                    if (ConsumeValueMultiSegment(first))
 01831                    {
 01832                        goto Done;
 1833                    }
 1834                    else
 01835                    {
 01836                        goto RollBack;
 1837                    }
 1838                }
 1839            }
 01840            else if (first == JsonConstants.CloseBrace)
 01841            {
 01842                EndObject();
 01843            }
 01844            else if (first == JsonConstants.CloseBracket)
 01845            {
 01846                EndArray();
 01847            }
 01848            else if (_tokenType == JsonTokenType.None)
 01849            {
 01850                if (ReadFirstTokenMultiSegment(first))
 01851                {
 01852                    goto Done;
 1853                }
 1854                else
 01855                {
 01856                    goto RollBack;
 1857                }
 1858            }
 01859            else if (_tokenType == JsonTokenType.StartObject)
 01860            {
 01861                Debug.Assert(first != JsonConstants.CloseBrace);
 01862                if (first != JsonConstants.Quote)
 01863                {
 01864                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound, fi
 1865                }
 1866
 01867                long prevTotalConsumed = _totalConsumed;
 01868                int prevConsumed = _consumed;
 01869                long prevPosition = _bytePositionInLine;
 01870                long prevLineNumber = _lineNumber;
 01871                if (!ConsumePropertyNameMultiSegment())
 01872                {
 1873                    // roll back potential changes
 01874                    _consumed = prevConsumed;
 01875                    _tokenType = JsonTokenType.StartObject;
 01876                    _bytePositionInLine = prevPosition;
 01877                    _lineNumber = prevLineNumber;
 01878                    _totalConsumed = prevTotalConsumed;
 01879                    goto RollBack;
 1880                }
 01881                goto Done;
 1882            }
 01883            else if (_tokenType == JsonTokenType.StartArray)
 01884            {
 01885                Debug.Assert(first != JsonConstants.CloseBracket);
 01886                if (!ConsumeValueMultiSegment(first))
 01887                {
 01888                    goto RollBack;
 1889                }
 01890                goto Done;
 1891            }
 01892            else if (_tokenType == JsonTokenType.PropertyName)
 01893            {
 01894                if (!ConsumeValueMultiSegment(first))
 01895                {
 01896                    goto RollBack;
 1897                }
 01898                goto Done;
 1899            }
 1900            else
 01901            {
 01902                Debug.Assert(_tokenType == JsonTokenType.EndArray || _tokenType == JsonTokenType.EndObject);
 01903                if (_inObject)
 01904                {
 01905                    Debug.Assert(first != JsonConstants.CloseBrace);
 01906                    if (first != JsonConstants.Quote)
 01907                    {
 01908                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 1909                    }
 1910
 01911                    if (ConsumePropertyNameMultiSegment())
 01912                    {
 01913                        goto Done;
 1914                    }
 1915                    else
 01916                    {
 01917                        goto RollBack;
 1918                    }
 1919                }
 1920                else
 01921                {
 01922                    Debug.Assert(first != JsonConstants.CloseBracket);
 1923
 01924                    if (ConsumeValueMultiSegment(first))
 01925                    {
 01926                        goto Done;
 1927                    }
 1928                    else
 01929                    {
 01930                        goto RollBack;
 1931                    }
 1932                }
 1933            }
 1934
 01935        Done:
 01936            return ConsumeTokenResult.Success;
 1937
 01938        RollBack:
 01939            return ConsumeTokenResult.NotEnoughDataRollBackState;
 01940        }
 1941
 1942        private bool SkipAllCommentsMultiSegment(scoped ref byte marker)
 11701943        {
 11701944            while (marker == JsonConstants.Slash)
 5071945            {
 5071946                if (SkipOrConsumeCommentMultiSegmentWithRollback())
 01947                {
 01948                    if (!HasMoreDataMultiSegment())
 01949                    {
 01950                        goto IncompleteNoRollback;
 1951                    }
 1952
 01953                    marker = _buffer[_consumed];
 1954
 1955                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01956                    if (marker <= JsonConstants.Space)
 01957                    {
 01958                        SkipWhiteSpaceMultiSegment();
 01959                        if (!HasMoreDataMultiSegment())
 01960                        {
 01961                            goto IncompleteNoRollback;
 1962                        }
 01963                        marker = _buffer[_consumed];
 01964                    }
 01965                }
 1966                else
 01967                {
 01968                    goto IncompleteNoRollback;
 1969                }
 01970            }
 6631971            return true;
 1972
 01973        IncompleteNoRollback:
 01974            return false;
 6631975        }
 1976
 1977        private bool SkipAllCommentsMultiSegment(scoped ref byte marker, ExceptionResource resource)
 01978        {
 01979            while (marker == JsonConstants.Slash)
 01980            {
 01981                if (SkipOrConsumeCommentMultiSegmentWithRollback())
 01982                {
 1983                    // The next character must be a start of a property name or value.
 01984                    if (!HasMoreDataMultiSegment(resource))
 01985                    {
 01986                        goto IncompleteRollback;
 1987                    }
 1988
 01989                    marker = _buffer[_consumed];
 1990
 1991                    // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 01992                    if (marker <= JsonConstants.Space)
 01993                    {
 01994                        SkipWhiteSpaceMultiSegment();
 1995                        // The next character must be a start of a property name or value.
 01996                        if (!HasMoreDataMultiSegment(resource))
 01997                        {
 01998                            goto IncompleteRollback;
 1999                        }
 02000                        marker = _buffer[_consumed];
 02001                    }
 02002                }
 2003                else
 02004                {
 02005                    goto IncompleteRollback;
 2006                }
 02007            }
 02008            return true;
 2009
 02010        IncompleteRollback:
 02011            return false;
 02012        }
 2013
 2014        private ConsumeTokenResult ConsumeNextTokenUntilAfterAllCommentsAreSkippedMultiSegment(byte marker)
 11702015        {
 11702016            if (!SkipAllCommentsMultiSegment(ref marker))
 02017            {
 02018                goto IncompleteNoRollback;
 2019            }
 2020
 6632021            TokenStartIndex = BytesConsumed;
 2022
 6632023            if (_tokenType == JsonTokenType.StartObject)
 02024            {
 02025                if (marker == JsonConstants.CloseBrace)
 02026                {
 02027                    EndObject();
 02028                }
 2029                else
 02030                {
 02031                    if (marker != JsonConstants.Quote)
 02032                    {
 02033                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 2034                    }
 2035
 02036                    long prevTotalConsumed = _totalConsumed;
 02037                    int prevConsumed = _consumed;
 02038                    long prevPosition = _bytePositionInLine;
 02039                    long prevLineNumber = _lineNumber;
 02040                    SequencePosition copy = _currentPosition;
 02041                    if (!ConsumePropertyNameMultiSegment())
 02042                    {
 2043                        // roll back potential changes
 02044                        _consumed = prevConsumed;
 02045                        _tokenType = JsonTokenType.StartObject;
 02046                        _bytePositionInLine = prevPosition;
 02047                        _lineNumber = prevLineNumber;
 02048                        _totalConsumed = prevTotalConsumed;
 02049                        _currentPosition = copy;
 02050                        goto IncompleteNoRollback;
 2051                    }
 02052                    goto Done;
 2053                }
 02054            }
 6632055            else if (_tokenType == JsonTokenType.StartArray)
 02056            {
 02057                if (marker == JsonConstants.CloseBracket)
 02058                {
 02059                    EndArray();
 02060                }
 2061                else
 02062                {
 02063                    if (!ConsumeValueMultiSegment(marker))
 02064                    {
 02065                        goto IncompleteNoRollback;
 2066                    }
 02067                    goto Done;
 2068                }
 02069            }
 6632070            else if (_tokenType == JsonTokenType.PropertyName)
 02071            {
 02072                if (!ConsumeValueMultiSegment(marker))
 02073                {
 02074                    goto IncompleteNoRollback;
 2075                }
 02076                goto Done;
 2077            }
 6632078            else if (_bitStack.CurrentDepth == 0)
 6632079            {
 6632080                if (_readerOptions.AllowMultipleValues)
 02081                {
 02082                    return ReadFirstTokenMultiSegment(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoug
 2083                }
 2084
 6632085                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedEndAfterSingleJson, marker);
 2086            }
 02087            else if (marker == JsonConstants.ListSeparator)
 02088            {
 02089                _consumed++;
 02090                _bytePositionInLine++;
 2091
 02092                if (_consumed >= (uint)_buffer.Length)
 02093                {
 02094                    if (IsLastSpan)
 02095                    {
 02096                        _consumed--;
 02097                        _bytePositionInLine--;
 02098                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrValueN
 2099                    }
 02100                    if (!GetNextSpan())
 02101                    {
 02102                        if (IsLastSpan)
 02103                        {
 02104                            _consumed--;
 02105                            _bytePositionInLine--;
 02106                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyOrVa
 2107                        }
 02108                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 2109                    }
 02110                }
 02111                marker = _buffer[_consumed];
 2112
 2113                // This check is done as an optimization to avoid calling SkipWhiteSpace when not necessary.
 02114                if (marker <= JsonConstants.Space)
 02115                {
 02116                    SkipWhiteSpaceMultiSegment();
 2117                    // The next character must be a start of a property name or value.
 02118                    if (!HasMoreDataMultiSegment(ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 02119                    {
 02120                        return ConsumeTokenResult.NotEnoughDataRollBackState;
 2121                    }
 02122                    marker = _buffer[_consumed];
 02123                }
 2124
 02125                if (!SkipAllCommentsMultiSegment(ref marker, ExceptionResource.ExpectedStartOfPropertyOrValueNotFound))
 02126                {
 02127                    goto IncompleteRollback;
 2128                }
 2129
 02130                TokenStartIndex = BytesConsumed;
 2131
 02132                if (_inObject)
 02133                {
 02134                    if (marker != JsonConstants.Quote)
 02135                    {
 02136                        if (marker == JsonConstants.CloseBrace)
 02137                        {
 02138                            if (_readerOptions.AllowTrailingCommas)
 02139                            {
 02140                                EndObject();
 02141                                goto Done;
 2142                            }
 02143                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBefo
 2144                        }
 2145
 02146                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.ExpectedStartOfPropertyNotFound
 2147                    }
 02148                    return ConsumePropertyNameMultiSegment() ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnough
 2149                }
 2150                else
 02151                {
 02152                    if (marker == JsonConstants.CloseBracket)
 02153                    {
 02154                        if (_readerOptions.AllowTrailingCommas)
 02155                        {
 02156                            EndArray();
 02157                            goto Done;
 2158                        }
 02159                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.TrailingCommaNotAllowedBeforeAr
 2160                    }
 02161                    return ConsumeValueMultiSegment(marker) ? ConsumeTokenResult.Success : ConsumeTokenResult.NotEnoughD
 2162                }
 2163            }
 02164            else if (marker == JsonConstants.CloseBrace)
 02165            {
 02166                EndObject();
 02167            }
 02168            else if (marker == JsonConstants.CloseBracket)
 02169            {
 02170                EndArray();
 02171            }
 2172            else
 02173            {
 02174                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.FoundInvalidCharacter, marker);
 2175            }
 2176
 02177        Done:
 02178            return ConsumeTokenResult.Success;
 02179        IncompleteNoRollback:
 02180            return ConsumeTokenResult.IncompleteNoRollBackNecessary;
 02181        IncompleteRollback:
 02182            return ConsumeTokenResult.NotEnoughDataRollBackState;
 02183        }
 2184
 2185        private bool SkipOrConsumeCommentMultiSegmentWithRollback()
 5072186        {
 5072187            long prevTotalConsumed = BytesConsumed;
 5072188            SequencePosition start = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetInteger() + 
 5072189            bool skipSucceeded = SkipCommentMultiSegment(out int tailBytesToIgnore);
 2190
 02191            if (skipSucceeded)
 02192            {
 02193                Debug.Assert(
 02194                    _readerOptions.CommentHandling == JsonCommentHandling.Allow ||
 02195                    _readerOptions.CommentHandling == JsonCommentHandling.Skip);
 2196
 02197                if (_readerOptions.CommentHandling == JsonCommentHandling.Allow)
 02198                {
 02199                    SequencePosition end = new SequencePosition(_currentPosition.GetObject(), _currentPosition.GetIntege
 2200
 02201                    ReadOnlySequence<byte> commentSequence = _sequence.Slice(start, end);
 02202                    commentSequence = commentSequence.Slice(2, commentSequence.Length - 2 - tailBytesToIgnore);
 02203                    HasValueSequence = !commentSequence.IsSingleSegment;
 2204
 02205                    if (HasValueSequence)
 02206                    {
 02207                        ValueSequence = commentSequence;
 02208                    }
 2209                    else
 02210                    {
 02211                        ValueSpan = commentSequence.First.Span;
 02212                    }
 2213
 02214                    if (_tokenType != JsonTokenType.Comment)
 02215                    {
 02216                        _previousTokenType = _tokenType;
 02217                    }
 2218
 02219                    _tokenType = JsonTokenType.Comment;
 02220                }
 02221            }
 2222            else
 02223            {
 02224                _totalConsumed = prevTotalConsumed;
 2225                // Note: BytesConsumed = _totalConsumed + _consumed
 2226                // Changing _consumed and _totalConsumed to original values might not work correctly
 2227                // since _consumed is tracking position in the current sequence
 2228                // and current sequence might not be the same as we could've called GetNextSpan.
 2229                // Since we return false we do not expect these APIs to be called again
 2230                // so the values are ok to be slightly incorrect as long as the sum remains the same
 2231                // if we don't reset this value to zero the BytesConsumed might be reported incorrectly.
 02232                _consumed = 0;
 02233            }
 2234
 02235            return skipSucceeded;
 02236        }
 2237
 2238        private bool SkipCommentMultiSegment(out int tailBytesToIgnore)
 10812239        {
 10812240            _consumed++;
 10812241            _bytePositionInLine++;
 2242            // Create local copy to avoid bounds checks.
 10812243            ReadOnlySpan<byte> localBuffer = _buffer.Slice(_consumed);
 2244
 10812245            if (localBuffer.Length == 0)
 3742246            {
 3742247                if (IsLastSpan)
 02248                {
 02249                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileReadingComm
 2250                }
 2251
 3742252                if (!GetNextSpan())
 02253                {
 02254                    if (IsLastSpan)
 02255                    {
 02256                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileReading
 2257                    }
 2258
 02259                    tailBytesToIgnore = 0;
 02260                    return false;
 2261                }
 2262
 3742263                localBuffer = _buffer;
 3742264            }
 2265
 10812266            byte marker = localBuffer[0];
 10812267            if (marker != JsonConstants.Slash && marker != JsonConstants.Asterisk)
 5892268            {
 5892269                ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.InvalidCharacterAtStartOfComment, marke
 2270            }
 2271
 4922272            bool multiLine = marker == JsonConstants.Asterisk;
 2273
 4922274            _consumed++;
 4922275            _bytePositionInLine++;
 4922276            localBuffer = localBuffer.Slice(1);
 2277
 4922278            if (localBuffer.Length == 0)
 412279            {
 412280                if (IsLastSpan)
 02281                {
 02282                    tailBytesToIgnore = 0;
 2283
 02284                    if (multiLine)
 02285                    {
 02286                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileReading
 2287                    }
 2288
 02289                    return true;
 2290                }
 2291
 412292                if (!GetNextSpan())
 02293                {
 02294                    tailBytesToIgnore = 0;
 2295
 02296                    if (IsLastSpan)
 02297                    {
 02298                        if (multiLine)
 02299                        {
 02300                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileRea
 2301                        }
 2302
 02303                        return true;
 2304                    }
 2305
 02306                    return false;
 2307                }
 2308
 412309                localBuffer = _buffer;
 412310            }
 2311
 4922312            if (multiLine)
 02313            {
 02314                tailBytesToIgnore = 2;
 02315                return SkipMultiLineCommentMultiSegment(localBuffer);
 2316            }
 2317            else
 4922318            {
 4922319                return SkipSingleLineCommentMultiSegment(localBuffer, out tailBytesToIgnore);
 2320            }
 4922321        }
 2322
 2323        private bool SkipSingleLineCommentMultiSegment(ReadOnlySpan<byte> localBuffer, out int tailBytesToSkip)
 4922324        {
 4922325            bool expectLF = false;
 4922326            int dangerousLineSeparatorBytesConsumed = 0;
 4922327            tailBytesToSkip = 0;
 2328
 17632329            while (true)
 17632330            {
 17632331                if (expectLF)
 02332                {
 02333                    if (localBuffer[0] == JsonConstants.LineFeed)
 02334                    {
 02335                        tailBytesToSkip++;
 02336                        _consumed++;
 02337                    }
 2338
 02339                    break;
 2340                }
 2341
 17632342                int idx = FindLineSeparatorMultiSegment(localBuffer, ref dangerousLineSeparatorBytesConsumed);
 17632343                Debug.Assert(dangerousLineSeparatorBytesConsumed >= 0 && dangerousLineSeparatorBytesConsumed <= 2);
 2344
 17632345                if (idx != -1)
 1232346                {
 1232347                    tailBytesToSkip++;
 1232348                    _consumed += idx + 1;
 1232349                    _bytePositionInLine += idx + 1;
 2350
 1232351                    if (localBuffer[idx] == JsonConstants.LineFeed)
 822352                    {
 822353                        break;
 2354                    }
 2355
 2356                    // If we are here, we have definintely found a \r. So now to check if \n follows.
 412357                    Debug.Assert(localBuffer[idx] == JsonConstants.CarriageReturn);
 2358
 412359                    if (idx < localBuffer.Length - 1)
 412360                    {
 412361                        if (localBuffer[idx + 1] == JsonConstants.LineFeed)
 02362                        {
 02363                            tailBytesToSkip++;
 02364                            _consumed++;
 02365                            _bytePositionInLine++;
 02366                        }
 2367
 412368                        break;
 2369                    }
 2370
 02371                    expectLF = true;
 02372                }
 2373                else
 16402374                {
 16402375                    _consumed += localBuffer.Length;
 16402376                    _bytePositionInLine += localBuffer.Length;
 16402377                }
 2378
 16402379                if (IsLastSpan)
 3692380                {
 3692381                    if (expectLF)
 02382                    {
 02383                        break;
 2384                    }
 2385
 3692386                    return true;
 2387                }
 2388
 12712389                if (!GetNextSpan())
 02390                {
 02391                    if (IsLastSpan)
 02392                    {
 02393                        if (expectLF)
 02394                        {
 02395                            break;
 2396                        }
 2397
 02398                        return true;
 2399                    }
 2400                    else
 02401                    {
 02402                        return false;
 2403                    }
 2404                }
 2405
 12712406                localBuffer = _buffer;
 12712407            }
 2408
 1232409            _bytePositionInLine = 0;
 1232410            _lineNumber++;
 2411
 1232412            return true;
 4922413        }
 2414
 2415        private int FindLineSeparatorMultiSegment(ReadOnlySpan<byte> localBuffer, scoped ref int dangerousLineSeparatorB
 17632416        {
 17632417            Debug.Assert(dangerousLineSeparatorBytesConsumed >= 0 && dangerousLineSeparatorBytesConsumed <= 2);
 2418
 17632419            if (dangerousLineSeparatorBytesConsumed != 0)
 02420            {
 02421                ThrowOnDangerousLineSeparatorMultiSegment(localBuffer, ref dangerousLineSeparatorBytesConsumed);
 2422
 02423                if (dangerousLineSeparatorBytesConsumed != 0)
 02424                {
 2425                    // this can only happen if localBuffer size is 1 and we have previously only consumed 1 byte
 2426                    // or localBuffer is 0
 02427                    Debug.Assert(dangerousLineSeparatorBytesConsumed >= 1 && dangerousLineSeparatorBytesConsumed <= 2 &&
 02428                    return -1;
 2429                }
 02430            }
 2431
 17632432            int totalIdx = 0;
 17632433            while (true)
 17632434            {
 17632435                int idx = localBuffer.IndexOfAny(JsonConstants.LineFeed, JsonConstants.CarriageReturn, JsonConstants.Sta
 17632436                dangerousLineSeparatorBytesConsumed = 0;
 2437
 17632438                if (idx == -1)
 16402439                {
 16402440                    return -1;
 2441                }
 2442
 1232443                if (localBuffer[idx] != JsonConstants.StartingByteOfNonStandardSeparator)
 1232444                {
 1232445                    return totalIdx + idx;
 2446                }
 2447
 02448                int p = idx + 1;
 02449                localBuffer = localBuffer.Slice(p);
 02450                totalIdx += p;
 2451
 02452                dangerousLineSeparatorBytesConsumed++;
 02453                ThrowOnDangerousLineSeparatorMultiSegment(localBuffer, ref dangerousLineSeparatorBytesConsumed);
 2454
 02455                if (dangerousLineSeparatorBytesConsumed != 0)
 02456                {
 2457                    // this can only happen in the end of the local buffer
 02458                    Debug.Assert(localBuffer.Length < 2);
 02459                    return -1;
 2460                }
 02461            }
 17632462        }
 2463
 2464        // assumes first byte (JsonConstants.UnexpectedEndOfLineSeparator) is already read
 2465        private void ThrowOnDangerousLineSeparatorMultiSegment(ReadOnlySpan<byte> localBuffer, scoped ref int dangerousL
 02466        {
 02467            Debug.Assert(dangerousLineSeparatorBytesConsumed == 1 || dangerousLineSeparatorBytesConsumed == 2);
 2468
 2469            // \u2028 and \u2029 are considered respectively line and paragraph separators
 2470            // UTF-8 representation for them is E2, 80, A8/A9
 2471            // we have already read E2 and maybe 80 we need to check for remaining 1 or 2 bytes
 2472
 02473            if (localBuffer.IsEmpty)
 02474            {
 02475                return;
 2476            }
 2477
 02478            if (dangerousLineSeparatorBytesConsumed == 1)
 02479            {
 02480                if (localBuffer[0] == 0x80)
 02481                {
 02482                    localBuffer = localBuffer.Slice(1);
 02483                    dangerousLineSeparatorBytesConsumed++;
 2484
 02485                    if (localBuffer.IsEmpty)
 02486                    {
 02487                        return;
 2488                    }
 02489                }
 2490                else
 02491                {
 2492                    // no match
 02493                    dangerousLineSeparatorBytesConsumed = 0;
 02494                    return;
 2495                }
 02496            }
 2497
 02498            if (dangerousLineSeparatorBytesConsumed == 2)
 02499            {
 02500                byte lastByte = localBuffer[0];
 02501                if (lastByte == 0xA8 || lastByte == 0xA9)
 02502                {
 02503                    ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfLineSeparator);
 2504                }
 2505                else
 02506                {
 2507                    // no match
 02508                    dangerousLineSeparatorBytesConsumed = 0;
 02509                    return;
 2510                }
 2511            }
 02512        }
 2513
 2514        private bool SkipMultiLineCommentMultiSegment(ReadOnlySpan<byte> localBuffer)
 02515        {
 02516            bool expectSlash = false;
 02517            bool ignoreNextLfForLineTracking = false;
 2518
 02519            while (true)
 02520            {
 02521                Debug.Assert(localBuffer.Length > 0);
 2522
 02523                if (expectSlash)
 02524                {
 02525                    if (localBuffer[0] == JsonConstants.Slash)
 02526                    {
 02527                        _consumed++;
 02528                        _bytePositionInLine++;
 02529                        return true;
 2530                    }
 2531
 02532                    expectSlash = false;
 02533                }
 2534
 02535                if (ignoreNextLfForLineTracking)
 02536                {
 02537                    if (localBuffer[0] == JsonConstants.LineFeed)
 02538                    {
 02539                        _consumed++;
 02540                        localBuffer = localBuffer.Slice(1);
 02541                    }
 2542
 02543                    ignoreNextLfForLineTracking = false;
 02544                }
 2545
 02546                int idx = localBuffer.IndexOfAny(JsonConstants.Asterisk, JsonConstants.LineFeed, JsonConstants.CarriageR
 2547
 02548                if (idx != -1)
 02549                {
 02550                    int nextIdx = idx + 1;
 02551                    byte marker = localBuffer[idx];
 02552                    localBuffer = localBuffer.Slice(nextIdx);
 2553
 02554                    _consumed += nextIdx;
 2555
 02556                    switch (marker)
 2557                    {
 2558                        case JsonConstants.Asterisk:
 02559                            expectSlash = true;
 02560                            _bytePositionInLine += nextIdx;
 02561                            break;
 2562                        case JsonConstants.LineFeed:
 02563                            _bytePositionInLine = 0;
 02564                            _lineNumber++;
 02565                            break;
 2566                        default:
 02567                            Debug.Assert(marker == JsonConstants.CarriageReturn);
 02568                            _bytePositionInLine = 0;
 02569                            _lineNumber++;
 02570                            ignoreNextLfForLineTracking = true;
 02571                            break;
 2572                    }
 02573                }
 2574                else
 02575                {
 02576                    _consumed += localBuffer.Length;
 02577                    _bytePositionInLine += localBuffer.Length;
 02578                    localBuffer = ReadOnlySpan<byte>.Empty;
 02579                }
 2580
 02581                if (localBuffer.IsEmpty)
 02582                {
 02583                    if (IsLastSpan)
 02584                    {
 02585                        ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileReading
 2586                    }
 2587
 02588                    if (!GetNextSpan())
 02589                    {
 02590                        if (IsLastSpan)
 02591                        {
 02592                            ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.UnexpectedEndOfDataWhileRea
 2593                        }
 2594                        else
 02595                        {
 02596                            return false;
 2597                        }
 2598                    }
 2599
 02600                    localBuffer = _buffer;
 02601                    Debug.Assert(!localBuffer.IsEmpty);
 02602                }
 02603            }
 02604        }
 2605
 2606        private PartialStateForRollback CaptureState()
 82962607        {
 82962608            return new PartialStateForRollback(_totalConsumed, _bytePositionInLine, _consumed, _currentPosition);
 82962609        }
 2610
 2611        private readonly struct PartialStateForRollback
 2612        {
 2613            public readonly long _prevTotalConsumed;
 2614            public readonly long _prevBytePositionInLine;
 2615            public readonly int _prevConsumed;
 2616            public readonly SequencePosition _prevCurrentPosition;
 2617
 2618            public PartialStateForRollback(long totalConsumed, long bytePositionInLine, int consumed, SequencePosition c
 82962619            {
 82962620                _prevTotalConsumed = totalConsumed;
 82962621                _prevBytePositionInLine = bytePositionInLine;
 82962622                _prevConsumed = consumed;
 82962623                _prevCurrentPosition = currentPosition;
 82962624            }
 2625
 2626            public SequencePosition GetStartPosition(int offset = 0)
 55182627            {
 55182628                return new SequencePosition(_prevCurrentPosition.GetObject(), _prevCurrentPosition.GetInteger() + _prevC
 55182629            }
 2630        }
 2631    }
 2632}

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\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()
 157228        {
 157229            if (TokenType == JsonTokenType.Null)
 030            {
 031                return null;
 32            }
 33
 157234            if (TokenType != JsonTokenType.String && TokenType != JsonTokenType.PropertyName)
 73035            {
 73036                ThrowHelper.ThrowInvalidOperationException_ExpectedString(TokenType);
 37            }
 38
 84239            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 40
 84241            if (ValueIsEscaped)
 042            {
 043                return JsonReaderHelper.GetUnescapedString(span);
 44            }
 45
 84246            Debug.Assert(!span.Contains(JsonConstants.BackSlash));
 84247            return JsonReaderHelper.TranscodeHelper(span);
 53248        }
 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)
 64570        {
 64571            if (_tokenType is not (JsonTokenType.String or JsonTokenType.PropertyName))
 072            {
 073                ThrowHelper.ThrowInvalidOperationException_ExpectedString(_tokenType);
 74            }
 75
 64576            return CopyValue(utf8Destination);
 37377        }
 78
 79        internal readonly int CopyValue(Span<byte> utf8Destination)
 154780        {
 154781            Debug.Assert(_tokenType is JsonTokenType.String or JsonTokenType.PropertyName or JsonTokenType.Number);
 154782            Debug.Assert(_tokenType != JsonTokenType.Number || !ValueIsEscaped, "Numbers can't contain escape characters
 83
 84            int bytesWritten;
 85
 154786            if (ValueIsEscaped)
 087            {
 088                if (!TryCopyEscapedString(utf8Destination, out bytesWritten))
 089                {
 090                    utf8Destination.Slice(0, bytesWritten).Clear();
 091                    ThrowHelper.ThrowArgumentException_DestinationTooShort();
 92                }
 093            }
 94            else
 154795            {
 154796                if (HasValueSequence)
 54497                {
 54498                    ReadOnlySequence<byte> valueSequence = ValueSequence;
 54499                    valueSequence.CopyTo(utf8Destination);
 544100                    bytesWritten = (int)valueSequence.Length;
 544101                }
 102                else
 1003103                {
 1003104                    ReadOnlySpan<byte> valueSpan = ValueSpan;
 1003105                    valueSpan.CopyTo(utf8Destination);
 1003106                    bytesWritten = valueSpan.Length;
 1003107                }
 1547108            }
 109
 1547110            JsonReaderHelper.ValidateUtf8(utf8Destination.Slice(0, bytesWritten));
 1131111            return bytesWritten;
 1131112        }
 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)
 542134        {
 542135            if (_tokenType is not (JsonTokenType.String or JsonTokenType.PropertyName))
 0136            {
 0137                ThrowHelper.ThrowInvalidOperationException_ExpectedString(_tokenType);
 138            }
 139
 542140            return CopyValue(destination);
 296141        }
 142
 143        internal readonly int CopyValue(Span<char> destination)
 542144        {
 542145            Debug.Assert(_tokenType is JsonTokenType.String or JsonTokenType.PropertyName or JsonTokenType.Number);
 542146            Debug.Assert(_tokenType != JsonTokenType.Number || !ValueIsEscaped, "Numbers can't contain escape characters
 147
 148            scoped ReadOnlySpan<byte> unescapedSource;
 542149            byte[]? rentedBuffer = null;
 150            int valueLength;
 151
 542152            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
 542165            {
 542166                if (HasValueSequence)
 175167                {
 175168                    ReadOnlySequence<byte> valueSequence = ValueSequence;
 175169                    valueLength = checked((int)valueSequence.Length);
 170
 175171                    Span<byte> intermediate = valueLength <= JsonConstants.StackallocByteThreshold ?
 175172                        stackalloc byte[JsonConstants.StackallocByteThreshold] :
 175173                        (rentedBuffer = ArrayPool<byte>.Shared.Rent(valueLength));
 174
 175175                    valueSequence.CopyTo(intermediate);
 175176                    unescapedSource = intermediate.Slice(0, valueLength);
 175177                }
 178                else
 367179                {
 367180                    unescapedSource = ValueSpan;
 367181                }
 542182            }
 183
 542184            int charsWritten = JsonReaderHelper.TranscodeHelper(unescapedSource, destination);
 185
 296186            if (rentedBuffer != null)
 0187            {
 0188                new Span<byte>(rentedBuffer, 0, unescapedSource.Length).Clear();
 0189                ArrayPool<byte>.Shared.Return(rentedBuffer);
 0190            }
 191
 296192            return charsWritten;
 296193        }
 194
 195        private readonly 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 != 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()
 644258        {
 644259            JsonTokenType type = TokenType;
 644260            if (type == JsonTokenType.True)
 0261            {
 0262                Debug.Assert((HasValueSequence ? ValueSequence.ToArray() : ValueSpan).Length == 4);
 0263                return true;
 264            }
 644265            else if (type != JsonTokenType.False)
 644266            {
 644267                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()
 1902287        {
 1902288            if (!TryGetBytesFromBase64(out byte[]? value))
 474289            {
 474290                ThrowHelper.ThrowFormatException(DataType.Base64String);
 291            }
 360292            return value;
 360293        }
 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()
 538311        {
 538312            if (!TryGetByte(out byte value))
 96313            {
 96314                ThrowHelper.ThrowFormatException(NumericType.Byte);
 0315            }
 52316            return value;
 52317        }
 318
 319        internal byte GetByteWithQuotes()
 150320        {
 150321            ReadOnlySpan<byte> span = GetUnescapedSpan();
 150322            if (!TryGetByteCore(out byte value, span))
 138323            {
 138324                ThrowHelper.ThrowFormatException(NumericType.Byte);
 0325            }
 12326            return value;
 12327        }
 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()
 494346        {
 494347            if (!TryGetSByte(out sbyte value))
 80348            {
 80349                ThrowHelper.ThrowFormatException(NumericType.SByte);
 0350            }
 48351            return value;
 48352        }
 353
 354        internal sbyte GetSByteWithQuotes()
 140355        {
 140356            ReadOnlySpan<byte> span = GetUnescapedSpan();
 140357            if (!TryGetSByteCore(out sbyte value, span))
 128358            {
 128359                ThrowHelper.ThrowFormatException(NumericType.SByte);
 0360            }
 12361            return value;
 12362        }
 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()
 494380        {
 494381            if (!TryGetInt16(out short value))
 70382            {
 70383                ThrowHelper.ThrowFormatException(NumericType.Int16);
 0384            }
 58385            return value;
 58386        }
 387
 388        internal short GetInt16WithQuotes()
 140389        {
 140390            ReadOnlySpan<byte> span = GetUnescapedSpan();
 140391            if (!TryGetInt16Core(out short value, span))
 128392            {
 128393                ThrowHelper.ThrowFormatException(NumericType.Int16);
 0394            }
 12395            return value;
 12396        }
 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()
 778414        {
 778415            if (!TryGetInt32(out int value))
 86416            {
 86417                ThrowHelper.ThrowFormatException(NumericType.Int32);
 0418            }
 94419            return value;
 94420        }
 421
 422        internal int GetInt32WithQuotes()
 194423        {
 194424            ReadOnlySpan<byte> span = GetUnescapedSpan();
 194425            if (!TryGetInt32Core(out int value, span))
 180426            {
 180427                ThrowHelper.ThrowFormatException(NumericType.Int32);
 0428            }
 14429            return value;
 14430        }
 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()
 510448        {
 510449            if (!TryGetInt64(out long value))
 16450            {
 16451                ThrowHelper.ThrowFormatException(NumericType.Int64);
 0452            }
 122453            return value;
 122454        }
 455
 456        internal long GetInt64WithQuotes()
 142457        {
 142458            ReadOnlySpan<byte> span = GetUnescapedSpan();
 142459            if (!TryGetInt64Core(out long value, span))
 130460            {
 130461                ThrowHelper.ThrowFormatException(NumericType.Int64);
 0462            }
 12463            return value;
 12464        }
 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()
 494483        {
 494484            if (!TryGetUInt16(out ushort value))
 66485            {
 66486                ThrowHelper.ThrowFormatException(NumericType.UInt16);
 0487            }
 62488            return value;
 62489        }
 490
 491        internal ushort GetUInt16WithQuotes()
 140492        {
 140493            ReadOnlySpan<byte> span = GetUnescapedSpan();
 140494            if (!TryGetUInt16Core(out ushort value, span))
 128495            {
 128496                ThrowHelper.ThrowFormatException(NumericType.UInt16);
 0497            }
 12498            return value;
 12499        }
 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()
 494518        {
 494519            if (!TryGetUInt32(out uint value))
 56520            {
 56521                ThrowHelper.ThrowFormatException(NumericType.UInt32);
 0522            }
 72523            return value;
 72524        }
 525
 526        internal uint GetUInt32WithQuotes()
 140527        {
 140528            ReadOnlySpan<byte> span = GetUnescapedSpan();
 140529            if (!TryGetUInt32Core(out uint value, span))
 128530            {
 128531                ThrowHelper.ThrowFormatException(NumericType.UInt32);
 0532            }
 12533            return value;
 12534        }
 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()
 494553        {
 494554            if (!TryGetUInt64(out ulong value))
 16555            {
 16556                ThrowHelper.ThrowFormatException(NumericType.UInt64);
 0557            }
 112558            return value;
 112559        }
 560
 561        internal ulong GetUInt64WithQuotes()
 140562        {
 140563            ReadOnlySpan<byte> span = GetUnescapedSpan();
 140564            if (!TryGetUInt64Core(out ulong value, span))
 128565            {
 128566                ThrowHelper.ThrowFormatException(NumericType.UInt64);
 0567            }
 12568            return value;
 12569        }
 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()
 494586        {
 494587            if (!TryGetSingle(out float value))
 0588            {
 0589                ThrowHelper.ThrowFormatException(NumericType.Single);
 0590            }
 128591            return value;
 128592        }
 593
 594        internal float GetSingleWithQuotes()
 140595        {
 140596            ReadOnlySpan<byte> span = GetUnescapedSpan();
 597
 140598            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.
 140606            if (!(Utf8Parser.TryParse(span, out value, out int bytesConsumed)
 140607                  && span.Length == bytesConsumed
 140608                  && JsonHelpers.IsFinite(value)))
 128609            {
 128610                ThrowHelper.ThrowFormatException(NumericType.Single);
 0611            }
 612
 12613            return value;
 12614        }
 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);
 0623            }
 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()
 522643        {
 522644            if (!TryGetDouble(out double value))
 0645            {
 0646                ThrowHelper.ThrowFormatException(NumericType.Double);
 0647            }
 136648            return value;
 136649        }
 650
 651        internal double GetDoubleWithQuotes()
 160652        {
 160653            ReadOnlySpan<byte> span = GetUnescapedSpan();
 654
 160655            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.
 160663            if (!(Utf8Parser.TryParse(span, out value, out int bytesConsumed)
 160664                  && span.Length == bytesConsumed
 160665                  && JsonHelpers.IsFinite(value)))
 148666            {
 148667                ThrowHelper.ThrowFormatException(NumericType.Double);
 0668            }
 669
 12670            return value;
 12671        }
 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);
 0680            }
 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()
 508700        {
 508701            if (!TryGetDecimal(out decimal value))
 4702            {
 4703                ThrowHelper.ThrowFormatException(NumericType.Decimal);
 0704            }
 128705            return value;
 128706        }
 707
 708        internal decimal GetDecimalWithQuotes()
 148709        {
 148710            ReadOnlySpan<byte> span = GetUnescapedSpan();
 148711            if (!TryGetDecimalCore(out decimal value, span))
 136712            {
 136713                ThrowHelper.ThrowFormatException(NumericType.Decimal);
 0714            }
 12715            return value;
 12716        }
 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()
 652732        {
 652733            if (!TryGetDateTime(out DateTime value))
 294734            {
 294735                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()
 680765        {
 680766            if (!TryGetDateTimeOffset(out DateTimeOffset value))
 306767            {
 306768                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()
 690798        {
 690799            if (!TryGetGuid(out Guid value))
 312800            {
 312801                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)
 1902828        {
 1902829            if (TokenType != JsonTokenType.String)
 1068830            {
 1068831                ThrowHelper.ThrowInvalidOperationException_ExpectedString(TokenType);
 832            }
 833
 834834            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 835
 834836            if (ValueIsEscaped)
 0837            {
 0838                return JsonReaderHelper.TryGetUnescapedBase64Bytes(span, out value);
 839            }
 840
 834841            Debug.Assert(!span.Contains(JsonConstants.BackSlash));
 834842            return JsonReaderHelper.TryDecodeBase64(span, out value);
 834843        }
 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)
 676856        {
 676857            if (TokenType != JsonTokenType.Number)
 390858            {
 390859                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 860            }
 861
 286862            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 286863            return TryGetByteCore(out value, span);
 286864        }
 865
 866        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 867        internal static bool TryGetByteCore(out byte value, ReadOnlySpan<byte> span)
 436868        {
 436869            if (Utf8Parser.TryParse(span, out byte tmp, out int bytesConsumed)
 436870                && span.Length == bytesConsumed)
 112871            {
 112872                value = tmp;
 112873                return true;
 874            }
 875
 324876            value = 0;
 324877            return false;
 436878        }
 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)
 632892        {
 632893            if (TokenType != JsonTokenType.Number)
 366894            {
 366895                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 896            }
 897
 266898            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 266899            return TryGetSByteCore(out value, span);
 266900        }
 901
 902        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 903        internal static bool TryGetSByteCore(out sbyte value, ReadOnlySpan<byte> span)
 406904        {
 406905            if (Utf8Parser.TryParse(span, out sbyte tmp, out int bytesConsumed)
 406906                && span.Length == bytesConsumed)
 118907            {
 118908                value = tmp;
 118909                return true;
 910            }
 911
 288912            value = 0;
 288913            return false;
 406914        }
 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)
 632927        {
 632928            if (TokenType != JsonTokenType.Number)
 366929            {
 366930                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 931            }
 932
 266933            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 266934            return TryGetInt16Core(out value, span);
 266935        }
 936
 937        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 938        internal static bool TryGetInt16Core(out short value, ReadOnlySpan<byte> span)
 406939        {
 406940            if (Utf8Parser.TryParse(span, out short tmp, out int bytesConsumed)
 406941                && span.Length == bytesConsumed)
 138942            {
 138943                value = tmp;
 138944                return true;
 945            }
 946
 268947            value = 0;
 268948            return false;
 406949        }
 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)
 1212962        {
 1212963            if (TokenType != JsonTokenType.Number)
 598964            {
 598965                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 966            }
 967
 614968            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 614969            return TryGetInt32Core(out value, span);
 614970        }
 971
 972        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 973        internal static bool TryGetInt32Core(out int value, ReadOnlySpan<byte> span)
 808974        {
 808975            if (Utf8Parser.TryParse(span, out int tmp, out int bytesConsumed)
 808976                && span.Length == bytesConsumed)
 354977            {
 354978                value = tmp;
 354979                return true;
 980            }
 981
 454982            value = 0;
 454983            return false;
 808984        }
 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)
 648997        {
 648998            if (TokenType != JsonTokenType.Number)
 372999            {
 3721000                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1001            }
 1002
 2761003            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 2761004            return TryGetInt64Core(out value, span);
 2761005        }
 1006
 1007        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1008        internal static bool TryGetInt64Core(out long value, ReadOnlySpan<byte> span)
 4181009        {
 4181010            if (Utf8Parser.TryParse(span, out long tmp, out int bytesConsumed)
 4181011                && span.Length == bytesConsumed)
 2581012            {
 2581013                value = tmp;
 2581014                return true;
 1015            }
 1016
 1601017            value = 0;
 1601018            return false;
 4181019        }
 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)
 4941033        {
 4941034            if (TokenType != JsonTokenType.Number)
 3661035            {
 3661036                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1037            }
 1038
 1281039            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 1281040            return TryGetUInt16Core(out value, span);
 1281041        }
 1042
 1043        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1044        internal static bool TryGetUInt16Core(out ushort value, ReadOnlySpan<byte> span)
 2681045        {
 2681046            if (Utf8Parser.TryParse(span, out ushort tmp, out int bytesConsumed)
 2681047                && span.Length == bytesConsumed)
 741048            {
 741049                value = tmp;
 741050                return true;
 1051            }
 1052
 1941053            value = 0;
 1941054            return false;
 2681055        }
 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)
 4941069        {
 4941070            if (TokenType != JsonTokenType.Number)
 3661071            {
 3661072                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1073            }
 1074
 1281075            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 1281076            return TryGetUInt32Core(out value, span);
 1281077        }
 1078
 1079        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1080        internal static bool TryGetUInt32Core(out uint value, ReadOnlySpan<byte> span)
 2681081        {
 2681082            if (Utf8Parser.TryParse(span, out uint tmp, out int bytesConsumed)
 2681083                && span.Length == bytesConsumed)
 841084            {
 841085                value = tmp;
 841086                return true;
 1087            }
 1088
 1841089            value = 0;
 1841090            return false;
 2681091        }
 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)
 4941105        {
 4941106            if (TokenType != JsonTokenType.Number)
 3661107            {
 3661108                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1109            }
 1110
 1281111            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 1281112            return TryGetUInt64Core(out value, span);
 1281113        }
 1114
 1115        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1116        internal static bool TryGetUInt64Core(out ulong value, ReadOnlySpan<byte> span)
 2681117        {
 2681118            if (Utf8Parser.TryParse(span, out ulong tmp, out int bytesConsumed)
 2681119                && span.Length == bytesConsumed)
 1241120            {
 1241121                value = tmp;
 1241122                return true;
 1123            }
 1124
 1441125            value = 0;
 1441126            return false;
 2681127        }
 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)
 6321140        {
 6321141            if (TokenType != JsonTokenType.Number)
 3661142            {
 3661143                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1144            }
 1145
 2661146            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 1147
 2661148            if (Utf8Parser.TryParse(span, out float tmp, out int bytesConsumed)
 2661149                && span.Length == bytesConsumed)
 2661150            {
 2661151                value = tmp;
 2661152                return true;
 1153            }
 1154
 01155            value = 0;
 01156            return false;
 2661157        }
 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)
 6601170        {
 6601171            if (TokenType != JsonTokenType.Number)
 3861172            {
 3861173                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1174            }
 1175
 2741176            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 1177
 2741178            if (Utf8Parser.TryParse(span, out double tmp, out int bytesConsumed)
 2741179                && span.Length == bytesConsumed)
 2741180            {
 2741181                value = tmp;
 2741182                return true;
 1183            }
 1184
 01185            value = 0;
 01186            return false;
 2741187        }
 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)
 6461200        {
 6461201            if (TokenType != JsonTokenType.Number)
 3761202            {
 3761203                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(TokenType);
 1204            }
 1205
 2701206            ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
 2701207            return TryGetDecimalCore(out value, span);
 2701208        }
 1209
 1210        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1211        internal static bool TryGetDecimalCore(out decimal value, ReadOnlySpan<byte> span)
 4181212        {
 4181213            if (Utf8Parser.TryParse(span, out decimal tmp, out int bytesConsumed)
 4181214                && span.Length == bytesConsumed)
 2741215            {
 2741216                value = tmp;
 2741217                return true;
 1218            }
 1219
 1441220            value = 0;
 1441221            return false;
 4181222        }
 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)
 9301235        {
 9301236            if (TokenType != JsonTokenType.String)
 3581237            {
 3581238                ThrowHelper.ThrowInvalidOperationException_ExpectedString(TokenType);
 1239            }
 1240
 5721241            return TryGetDateTimeCore(out value);
 5721242        }
 1243
 1244        internal bool TryGetDateTimeCore(out DateTime value)
 5721245        {
 1246            scoped ReadOnlySpan<byte> span;
 1247
 5721248            if (HasValueSequence)
 1881249            {
 1881250                long sequenceLength = ValueSequence.Length;
 1881251                if (!JsonHelpers.IsInRangeInclusive(sequenceLength, JsonConstants.MinimumDateTimeParseLength, JsonConsta
 1721252                {
 1721253                    value = default;
 1721254                    return false;
 1255                }
 1256
 161257                Span<byte> stackSpan = stackalloc byte[JsonConstants.MaximumEscapedDateTimeOffsetParseLength];
 161258                ValueSequence.CopyTo(stackSpan);
 161259                span = stackSpan.Slice(0, (int)sequenceLength);
 161260            }
 1261            else
 3841262            {
 3841263                span = ValueSpan;
 3841264            }
 1265
 4001266            return JsonReaderHelper.TryGetValue(span, ValueIsEscaped, out value);
 5721267        }
 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)
 6801280        {
 6801281            if (TokenType != JsonTokenType.String)
 3741282            {
 3741283                ThrowHelper.ThrowInvalidOperationException_ExpectedString(TokenType);
 1284            }
 1285
 3061286            return TryGetDateTimeOffsetCore(out value);
 3061287        }
 1288
 1289        internal bool TryGetDateTimeOffsetCore(out DateTimeOffset value)
 3061290        {
 1291            scoped ReadOnlySpan<byte> span;
 1292
 3061293            if (HasValueSequence)
 1031294            {
 1031295                long sequenceLength = ValueSequence.Length;
 1031296                if (!JsonHelpers.IsInRangeInclusive(sequenceLength, JsonConstants.MinimumDateTimeParseLength, JsonConsta
 961297                {
 961298                    value = default;
 961299                    return false;
 1300                }
 1301
 71302                Span<byte> stackSpan = stackalloc byte[JsonConstants.MaximumEscapedDateTimeOffsetParseLength];
 71303                ValueSequence.CopyTo(stackSpan);
 71304                span = stackSpan.Slice(0, (int)sequenceLength);
 71305            }
 1306            else
 2031307            {
 2031308                span = ValueSpan;
 2031309            }
 1310
 2101311            return JsonReaderHelper.TryGetValue(span, ValueIsEscaped, out value);
 3061312        }
 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)
 6901326        {
 6901327            if (TokenType != JsonTokenType.String)
 3781328            {
 3781329                ThrowHelper.ThrowInvalidOperationException_ExpectedString(TokenType);
 1330            }
 1331
 3121332            return TryGetGuidCore(out value);
 3121333        }
 1334
 1335        internal bool TryGetGuidCore(out Guid value)
 3121336        {
 1337            scoped ReadOnlySpan<byte> span;
 1338
 3121339            if (HasValueSequence)
 1051340            {
 1051341                long sequenceLength = ValueSequence.Length;
 1051342                if (sequenceLength > JsonConstants.MaximumEscapedGuidLength)
 01343                {
 01344                    value = default;
 01345                    return false;
 1346                }
 1347
 1051348                Span<byte> stackSpan = stackalloc byte[JsonConstants.MaximumEscapedGuidLength];
 1051349                ValueSequence.CopyTo(stackSpan);
 1051350                span = stackSpan.Slice(0, (int)sequenceLength);
 1051351            }
 1352            else
 2071353            {
 2071354                span = ValueSpan;
 2071355            }
 1356
 3121357            return JsonReaderHelper.TryGetValue(span, ValueIsEscaped, out value);
 3121358        }
 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&)