ReadBufferState
using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace System.Text.Json.Serialization
{
[StructLayout(LayoutKind.Auto)]
internal struct ReadBufferState : IDisposable
{
private byte[] _buffer;
private byte _offset;
private int _count;
private int _maxCount;
private bool _isFirstBlock;
private bool _isFinalBlock;
private const int UnsuccessfulReadCountThreshold = 5;
private int _unsuccessfulReadCount;
public bool IsFinalBlock {
[System.Runtime.CompilerServices.IsReadOnly]
get {
return _isFinalBlock;
}
}
public ReadOnlySpan<byte> Bytes {
[System.Runtime.CompilerServices.IsReadOnly]
get {
return _buffer.AsSpan(_offset, _count);
}
}
public ReadBufferState(int initialBufferSize)
{
_unsuccessfulReadCount = 0;
_buffer = ArrayPool<byte>.Shared.Rent(Math.Max(initialBufferSize, JsonConstants.Utf8Bom.Length));
_maxCount = (_count = (_offset = 0));
_isFirstBlock = true;
_isFinalBlock = false;
}
[System.Runtime.CompilerServices.IsReadOnly]
[AsyncStateMachine(typeof(<ReadFromStreamAsync>d__13))]
public ValueTask<ReadBufferState> ReadFromStreamAsync(Stream utf8Json, CancellationToken cancellationToken, bool fillBuffer = true)
{
<ReadFromStreamAsync>d__13 stateMachine = default(<ReadFromStreamAsync>d__13);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder<ReadBufferState>.Create();
stateMachine.<>4__this = this;
stateMachine.utf8Json = utf8Json;
stateMachine.cancellationToken = cancellationToken;
stateMachine.fillBuffer = fillBuffer;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
public void ReadFromStream(Stream utf8Json)
{
do {
int num = utf8Json.Read(_buffer, _count, _buffer.Length - _count);
if (num == 0) {
_isFinalBlock = true;
break;
}
_count += num;
} while (_count < _buffer.Length);
ProcessReadBytes();
}
public void AdvanceBuffer(int bytesConsumed)
{
_unsuccessfulReadCount = ((bytesConsumed == 0) ? (_unsuccessfulReadCount + 1) : 0);
_count -= bytesConsumed;
if (!_isFinalBlock) {
if ((uint)_count > (uint)_buffer.Length / 2) {
byte[] buffer = _buffer;
int maxCount = _maxCount;
byte[] array = ArrayPool<byte>.Shared.Rent((_buffer.Length < 1073741823) ? (_buffer.Length * 2) : 2147483647);
Buffer.BlockCopy(buffer, _offset + bytesConsumed, array, 0, _count);
_buffer = array;
_maxCount = _count;
new Span<byte>(buffer, 0, maxCount).Clear();
ArrayPool<byte>.Shared.Return(buffer, false);
} else if (_count != 0) {
Buffer.BlockCopy(_buffer, _offset + bytesConsumed, _buffer, 0, _count);
}
}
_offset = 0;
}
private void ProcessReadBytes()
{
if (_count > _maxCount)
_maxCount = _count;
if (_isFirstBlock) {
_isFirstBlock = false;
if (_buffer.AsSpan(0, _count).StartsWith(JsonConstants.Utf8Bom)) {
ReadOnlySpan<byte> utf8Bom = JsonConstants.Utf8Bom;
_offset = (byte)utf8Bom.Length;
int count = _count;
utf8Bom = JsonConstants.Utf8Bom;
_count = count - utf8Bom.Length;
}
}
}
public void Dispose()
{
new Span<byte>(_buffer, 0, _maxCount).Clear();
byte[] buffer = _buffer;
_buffer = null;
ArrayPool<byte>.Shared.Return(buffer, false);
}
}
}