• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bjornharrtell / Utf8JsonStreamReader / 22690068897

04 Mar 2026 09:25PM UTC coverage: 94.853% (-5.1%) from 100.0%
22690068897

Pull #23

github

web-flow
Merge 49de46541 into 737b91290
Pull Request #23: Optimizations

28 of 33 new or added lines in 1 file covered. (84.85%)

2 existing lines in 1 file now uncovered.

129 of 136 relevant lines covered (94.85%)

0.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.17
/Utf8JsonStreamReader/Utf8JsonStreamReader.cs
1
using System.Buffers;
2
using System.Runtime.CompilerServices;
3
using System.Text.Json;
4

5
namespace Wololo.Text.Json;
6

7
public sealed partial class Utf8JsonStreamReader(
1✔
8
    int bufferSize = Utf8JsonStreamReader.DefaultBufferSize,
1✔
9
    int maxBufferSize = Utf8JsonStreamReader.DefaultMaxBufferSize
1✔
10
) : IDisposable
1✔
11
{
12
    bool done = false;
1✔
13
    bool disposed = false;
1✔
14
    byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
1✔
15
    int bufferSize = bufferSize;
1✔
16
    readonly int maxBufferSize = maxBufferSize;
1✔
17
    int bufferLength = 0;
1✔
18
    int offset = 0;
1✔
19
    int remaining = 0;
1✔
20
    int readLength = 0;
1✔
21
    JsonReaderState jsonReaderState = new();
1✔
22

23
    const int DefaultBufferSize = 1024 * 32;
24
    const int DefaultMaxBufferSize = 1024 * 1024 * 1024;
25

26
    public delegate void OnRead(ref Utf8JsonReader reader);
27

28
    public void Dispose()
UNCOV
29
    {
×
NEW
30
        if (!disposed)
×
NEW
31
        {
×
NEW
32
            ArrayPool<byte>.Shared.Return(buffer);
×
NEW
33
            disposed = true;
×
NEW
34
        }
×
UNCOV
35
    }
×
36

37
    void CopyRemaining()
38
    {
1✔
39
        remaining = bufferLength - offset;
1✔
40
        if (remaining > 0)
1✔
41
            buffer.AsSpan(offset, remaining).CopyTo(buffer);
1✔
42
    }
1✔
43

44
    bool TryGrowBuffer()
45
    {
1✔
46
        var newBufferSize = bufferSize * 2;
1✔
47
        if (newBufferSize > maxBufferSize)
1✔
48
        {
1✔
49
            if (bufferSize < maxBufferSize)
1✔
50
                newBufferSize = maxBufferSize;
1✔
51
            else
52
                return false;
1✔
53
        }
1✔
54
        var newBuffer = ArrayPool<byte>.Shared.Rent(newBufferSize);
1✔
55
        buffer.AsSpan(0, bufferLength).CopyTo(newBuffer);
1✔
56
        ArrayPool<byte>.Shared.Return(buffer);
1✔
57
        buffer = newBuffer;
1✔
58
        bufferSize = newBufferSize;
1✔
59
        return true;
1✔
60
    }
1✔
61

62
    void ReadStream(Stream stream, OnRead onRead)
63
    {
1✔
64
        do
65
        {
1✔
66
            CopyRemaining();
1✔
67
            readLength = stream.ReadAtLeast(
1✔
68
                buffer.AsSpan(remaining, bufferSize - remaining),
1✔
69
                bufferSize - remaining,
1✔
70
                false
1✔
71
            );
1✔
72
        } while (!ReadBuffer(onRead, default));
1✔
73
    }
1✔
74

75
    public void Read(Stream stream, OnRead onRead)
76
    {
1✔
77
        while (!done)
1✔
78
            ReadStream(stream, onRead);
1✔
79
    }
1✔
80

81
    async ValueTask ReadStreamAsync(Stream stream, OnRead onRead, CancellationToken token = default)
82
    {
1✔
83
        while (true)
1✔
84
        {
1✔
85
            CopyRemaining();
1✔
86
            readLength = await stream.ReadAtLeastAsync(
1✔
87
                buffer.AsMemory(remaining, bufferSize - remaining),
1✔
88
                bufferSize - remaining,
1✔
89
                false,
1✔
90
                token
1✔
91
            );
1✔
92
            if (ReadBuffer(onRead, token))
1✔
93
                break;
1✔
94
        }
1✔
95
    }
1✔
96

97
    public async ValueTask ReadAsync(Stream stream, OnRead onRead, CancellationToken token = default)
98
    {
1✔
99
        while (!done && !token.IsCancellationRequested)
1✔
100
            await ReadStreamAsync(stream, onRead, token);
1✔
101
    }
1✔
102

103
    static void AccumulateResults(ref Utf8JsonReader reader, List<JsonResult> results) =>
104
        results.Add(new JsonResult(reader.TokenType, Utf8JsonHelpers.GetValue(ref reader)));
1✔
105

106
    public IEnumerable<JsonResult> ToEnumerable(Stream stream)
107
    {
1✔
108
        var results = new List<JsonResult>();
1✔
109
        void onRead(ref Utf8JsonReader r) => AccumulateResults(ref r, results);
1✔
110
        while (!done)
1✔
111
        {
1✔
112
            ReadStream(stream, onRead);
1✔
113
            foreach (var item in results)
1✔
114
                yield return item;
1✔
115
            results.Clear();
1✔
116
        }
1✔
117
    }
1✔
118

119
    public async IAsyncEnumerable<JsonResult> ToAsyncEnumerable(
120
        Stream stream,
121
        [EnumeratorCancellation] CancellationToken token = default
122
    )
123
    {
1✔
124
        var results = new List<JsonResult>();
1✔
125
        void onRead(ref Utf8JsonReader r) => AccumulateResults(ref r, results);
1✔
126
        while (!done && !token.IsCancellationRequested)
1✔
127
        {
1✔
128
            await ReadStreamAsync(stream, onRead, token);
1✔
129
            foreach (var item in results)
1✔
130
            {
1✔
131
                if (token.IsCancellationRequested)
1✔
132
                    yield break;
1✔
133
                yield return item;
1✔
134
            }
1✔
135
            results.Clear();
1✔
136
        }
1✔
137
    }
1✔
138

139
    private bool ReadBuffer(OnRead onRead, CancellationToken token = default)
140
    {
1✔
141
        bufferLength = readLength + remaining;
1✔
142
        offset = 0;
1✔
143
        done = bufferLength < bufferSize;
1✔
144
        var reader = new Utf8JsonReader(buffer.AsSpan(0, bufferLength), done, jsonReaderState);
1✔
145
        while (reader.Read() && !token.IsCancellationRequested)
1✔
146
            onRead(ref reader);
1✔
147
        if (token.IsCancellationRequested)
1✔
148
        {
1✔
149
            done = true;
1✔
150
            return true;
1✔
151
        }
152
        jsonReaderState = reader.CurrentState;
1✔
153
        offset = (int)reader.BytesConsumed;
1✔
154
        if (offset == 0)
1✔
155
        {
1✔
156
            if (!done && TryGrowBuffer())
1✔
157
                return false;
1✔
158
            throw new JsonException("Failure to parse JSON token buffer is too small");
1✔
159
        }
160
        return true;
1✔
161
    }
1✔
162
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc