< Summary

Information
Line coverage
76%
Covered lines: 68
Uncovered lines: 21
Coverable lines: 89
Total lines: 153
Line coverage: 76.4%
Branch coverage
76%
Covered branches: 23
Total branches: 30
Branch coverage: 76.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
Advance(...)100%22100%
ReadAsync()50%4478.57%
Read(...)100%110%
GetReader(...)50%2240%
ProcessReadBytes()85%202082.85%
Dispose()50%2271.42%

File(s)

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\PipeReadBufferState.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.IO.Pipelines;
 7using System.Runtime.InteropServices;
 8using System.Threading;
 9using System.Threading.Tasks;
 10
 11namespace System.Text.Json.Serialization
 12{
 13    [StructLayout(LayoutKind.Auto)]
 14    internal struct PipeReadBufferState : IReadBufferState<PipeReadBufferState, PipeReader>
 15    {
 16        private readonly PipeReader _utf8Json;
 17
 2796218        private ReadOnlySequence<byte> _sequence = ReadOnlySequence<byte>.Empty;
 19        private bool _isFinalBlock;
 2796220        private bool _isFirstBlock = true;
 21        private int _unsuccessfulReadBytes;
 22
 23        public PipeReadBufferState(PipeReader utf8Json)
 2796224        {
 2796225            _utf8Json = utf8Json;
 2796226        }
 27
 2804928        public readonly bool IsFinalBlock => _isFinalBlock;
 29
 30#if DEBUG
 17431        public readonly ReadOnlySequence<byte> Bytes => _sequence;
 32#endif
 33
 34        public void Advance(long bytesConsumed)
 2796235        {
 2796236            _unsuccessfulReadBytes = 0;
 2796237            if (bytesConsumed == 0)
 1402238            {
 1402239                long leftOver = _sequence.Length;
 40                // Cap at int.MaxValue as PipeReader.ReadAtLeastAsync uses an int as the minimum size argument.
 1402241                _unsuccessfulReadBytes = (int)Math.Min(int.MaxValue, leftOver * 2);
 1402242            }
 43
 2796244            _utf8Json.AdvanceTo(_sequence.Slice(bytesConsumed).Start, _sequence.End);
 2796245            _sequence = ReadOnlySequence<byte>.Empty;
 2796246        }
 47
 48        /// <summary>
 49        /// Read from the PipeReader until either our buffer limit is filled or we hit EOF.
 50        /// Calling ReadCore is relatively expensive, so we minimize the number of times
 51        /// we need to call it.
 52        /// </summary>
 53        public async ValueTask<PipeReadBufferState> ReadAsync(PipeReader utf8Json, CancellationToken cancellationToken, 
 2796254        {
 2796255            Debug.Assert(_sequence.Equals(ReadOnlySequence<byte>.Empty), "ReadAsync should only be called when the buffe
 56
 57            // Since mutable structs don't work well with async state machines,
 58            // make all updates on a copy which is returned once complete.
 2796259            PipeReadBufferState bufferState = this;
 60
 2796261            int minBufferSize = _unsuccessfulReadBytes > 0 ? _unsuccessfulReadBytes : 0;
 2796262            ReadResult readResult = await _utf8Json.ReadAtLeastAsync(minBufferSize, cancellationToken).ConfigureAwait(fa
 63
 2796264            bufferState._sequence = readResult.Buffer;
 2796265            bufferState._isFinalBlock = readResult.IsCompleted;
 2796266            bufferState.ProcessReadBytes();
 67
 2796268            if (readResult.IsCanceled)
 069            {
 070                ThrowHelper.ThrowOperationCanceledException_PipeReadCanceled();
 071            }
 72
 2796273            return bufferState;
 2796274        }
 75
 076        public void Read(PipeReader utf8Json) => throw new NotImplementedException();
 77
 78        public void GetReader(JsonReaderState jsonReaderState, out Utf8JsonReader reader)
 2796279        {
 2796280            if (_sequence.IsSingleSegment)
 081            {
 082                reader = new Utf8JsonReader(
 083#if NET
 084                    _sequence.FirstSpan,
 085#else
 086                    _sequence.First.Span,
 087#endif
 088                    IsFinalBlock, jsonReaderState);
 089            }
 90            else
 2796291            {
 2796292                reader = new Utf8JsonReader(_sequence, IsFinalBlock, jsonReaderState);
 2796293            }
 2796294        }
 95
 96        private void ProcessReadBytes()
 2796297        {
 2796298            if (_isFirstBlock)
 2796299            {
 27962100                _isFirstBlock = false;
 101
 102                // Handle the UTF-8 BOM if present
 27962103                if (_sequence.Length > 0)
 27962104                {
 27962105                    if (_sequence.First.Length >= JsonConstants.Utf8Bom.Length)
 14678106                    {
 14678107                        if (_sequence.First.Span.StartsWith(JsonConstants.Utf8Bom))
 0108                        {
 0109                            _sequence = _sequence.Slice((byte)JsonConstants.Utf8Bom.Length);
 0110                        }
 14678111                    }
 112                    else
 13284113                    {
 114                        // BOM spans multiple segments
 13284115                        SequencePosition pos = _sequence.Start;
 13284116                        int matched = 0;
 54858117                        while (matched < JsonConstants.Utf8Bom.Length && _sequence.TryGet(ref pos, out ReadOnlyMemory<by
 41574118                        {
 41574119                            ReadOnlySpan<byte> span = mem.Span;
 83271120                            for (int i = 0; i < span.Length && matched < JsonConstants.Utf8Bom.Length; i++, matched++)
 41574121                            {
 41574122                                if (span[i] != JsonConstants.Utf8Bom[matched])
 41533123                                {
 41533124                                    matched = 0;
 41533125                                    break;
 126                                }
 41127                            }
 41574128                        }
 129
 13284130                        if (matched == JsonConstants.Utf8Bom.Length)
 0131                        {
 0132                            _sequence = _sequence.Slice(JsonConstants.Utf8Bom.Length);
 0133                        }
 13284134                    }
 27962135                }
 27962136            }
 27962137        }
 138
 139        public void Dispose()
 27962140        {
 27962141            if (_sequence.Equals(ReadOnlySequence<byte>.Empty))
 27962142            {
 27962143                return;
 144            }
 145
 146            // If we have a sequence, that likely means an Exception was thrown during deserialization.
 147            // We should make sure to call AdvanceTo so that future reads on the PipeReader can be done without throwing
 148            // We'll advance to the start of the sequence as we don't know how many bytes were consumed.
 0149            _utf8Json.AdvanceTo(_sequence.Start);
 0150            _sequence = ReadOnlySequence<byte>.Empty;
 27962151        }
 152    }
 153}