< Summary

Information
Class: System.Text.Json.Serialization.PipeReadBufferState
Assembly: System.Text.Json
File(s): D:\runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\PipeReadBufferState.cs
Line coverage
77%
Covered lines: 66
Uncovered lines: 19
Coverable lines: 85
Total lines: 149
Line coverage: 77.6%
Branch coverage
63%
Covered branches: 19
Total branches: 30
Branch coverage: 63.3%
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%2254.54%
ProcessReadBytes()65%202080%
Dispose()50%2271.42%

File(s)

D:\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
 434618        private ReadOnlySequence<byte> _sequence = ReadOnlySequence<byte>.Empty;
 19        private bool _isFinalBlock;
 434620        private bool _isFirstBlock = true;
 21        private int _unsuccessfulReadBytes;
 22
 23        public PipeReadBufferState(PipeReader utf8Json)
 434624        {
 434625            _utf8Json = utf8Json;
 434626        }
 27
 434628        public readonly bool IsFinalBlock => _isFinalBlock;
 29
 30#if DEBUG
 031        public readonly ReadOnlySequence<byte> Bytes => _sequence;
 32#endif
 33
 34        public void Advance(long bytesConsumed)
 434635        {
 434636            _unsuccessfulReadBytes = 0;
 434637            if (bytesConsumed == 0)
 426438            {
 426439                long leftOver = _sequence.Length;
 40                // Cap at int.MaxValue as PipeReader.ReadAtLeastAsync uses an int as the minimum size argument.
 426441                _unsuccessfulReadBytes = (int)Math.Min(int.MaxValue, leftOver * 2);
 426442            }
 43
 434644            _utf8Json.AdvanceTo(_sequence.Slice(bytesConsumed).Start, _sequence.End);
 434645            _sequence = ReadOnlySequence<byte>.Empty;
 434646        }
 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, 
 434654        {
 434655            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.
 434659            PipeReadBufferState bufferState = this;
 60
 434661            int minBufferSize = _unsuccessfulReadBytes > 0 ? _unsuccessfulReadBytes : 0;
 434662            ReadResult readResult = await _utf8Json.ReadAtLeastAsync(minBufferSize, cancellationToken).ConfigureAwait(fa
 63
 434664            bufferState._sequence = readResult.Buffer;
 434665            bufferState._isFinalBlock = readResult.IsCompleted;
 434666            bufferState.ProcessReadBytes();
 67
 434668            if (readResult.IsCanceled)
 069            {
 070                ThrowHelper.ThrowOperationCanceledException_PipeReadCanceled();
 071            }
 72
 434673            return bufferState;
 434674        }
 75
 076        public void Read(PipeReader utf8Json) => throw new NotImplementedException();
 77
 78        public void GetReader(JsonReaderState jsonReaderState, out Utf8JsonReader reader)
 434679        {
 434680            if (_sequence.IsSingleSegment)
 081            {
 082                reader = new Utf8JsonReader(
 083                    _sequence.FirstSpan,
 084                    IsFinalBlock, jsonReaderState);
 085            }
 86            else
 434687            {
 434688                reader = new Utf8JsonReader(_sequence, IsFinalBlock, jsonReaderState);
 434689            }
 434690        }
 91
 92        private void ProcessReadBytes()
 434693        {
 434694            if (_isFirstBlock)
 434695            {
 434696                _isFirstBlock = false;
 97
 98                // Handle the UTF-8 BOM if present
 434699                if (_sequence.Length > 0)
 4346100                {
 4346101                    if (_sequence.First.Length >= JsonConstants.Utf8Bom.Length)
 2173102                    {
 2173103                        if (_sequence.FirstSpan.StartsWith(JsonConstants.Utf8Bom))
 0104                        {
 0105                            _sequence = _sequence.Slice((byte)JsonConstants.Utf8Bom.Length);
 0106                        }
 2173107                    }
 108                    else
 2173109                    {
 110                        // BOM spans multiple segments
 2173111                        SequencePosition pos = _sequence.Start;
 2173112                        int matched = 0;
 11193113                        while (matched < JsonConstants.Utf8Bom.Length && _sequence.TryGet(ref pos, out ReadOnlyMemory<by
 9020114                        {
 9020115                            ReadOnlySpan<byte> span = mem.Span;
 18040116                            for (int i = 0; i < span.Length && matched < JsonConstants.Utf8Bom.Length; i++, matched++)
 9020117                            {
 9020118                                if (span[i] != JsonConstants.Utf8Bom[matched])
 9020119                                {
 9020120                                    matched = 0;
 9020121                                    break;
 122                                }
 0123                            }
 9020124                        }
 125
 2173126                        if (matched == JsonConstants.Utf8Bom.Length)
 0127                        {
 0128                            _sequence = _sequence.Slice(JsonConstants.Utf8Bom.Length);
 0129                        }
 2173130                    }
 4346131                }
 4346132            }
 4346133        }
 134
 135        public void Dispose()
 4346136        {
 4346137            if (_sequence.Equals(ReadOnlySequence<byte>.Empty))
 4346138            {
 4346139                return;
 140            }
 141
 142            // If we have a sequence, that likely means an Exception was thrown during deserialization.
 143            // We should make sure to call AdvanceTo so that future reads on the PipeReader can be done without throwing
 144            // We'll advance to the start of the sequence as we don't know how many bytes were consumed.
 0145            _utf8Json.AdvanceTo(_sequence.Start);
 0146            _sequence = ReadOnlySequence<byte>.Empty;
 4346147        }
 148    }
 149}