File: System\Net\Quic\Internal\ReceiveBuffers.cs
Web Access
Project: src\src\libraries\System.Net.Quic\src\System.Net.Quic.csproj (System.Net.Quic)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.Quic;
 
namespace System.Net.Quic;
 
internal struct ReceiveBuffers
{
    private const int MaxBufferedBytes = 64 * 1024;
 
    private readonly object _syncRoot;
    private MultiArrayBuffer _buffer;
    private bool _final;
 
    public ReceiveBuffers()
    {
        _syncRoot = new object();
        _buffer = default;
        _final = default;
    }
 
    public void SetFinal()
    {
        lock (_syncRoot)
        {
            _final = true;
        }
    }
 
    public bool HasCapacity()
    {
        lock (_syncRoot)
        {
            return _buffer.ActiveMemory.Length < MaxBufferedBytes;
        }
    }
 
    public int CopyFrom(ReadOnlySpan<QUIC_BUFFER> quicBuffers, int totalLength, bool final)
    {
        lock (_syncRoot)
        {
            if (_buffer.ActiveMemory.Length > MaxBufferedBytes - totalLength)
            {
                totalLength = MaxBufferedBytes - _buffer.ActiveMemory.Length;
                final = false;
            }
 
            _final = final;
            _buffer.EnsureAvailableSpace(totalLength);
 
            int totalCopied = 0;
            for (int i = 0; i < quicBuffers.Length; ++i)
            {
                Span<byte> quicBuffer = quicBuffers[i].Span;
                if (totalLength < quicBuffer.Length)
                {
                    quicBuffer = quicBuffer.Slice(0, totalLength);
                }
                _buffer.AvailableMemory.CopyFrom(quicBuffer);
                _buffer.Commit(quicBuffer.Length);
                totalCopied += quicBuffer.Length;
                totalLength -= quicBuffer.Length;
            }
            return totalCopied;
        }
    }
 
    public int CopyTo(Memory<byte> buffer, out bool completed, out bool empty)
    {
        lock (_syncRoot)
        {
            int copied = 0;
            if (!_buffer.IsEmpty)
            {
                MultiMemory activeBuffer = _buffer.ActiveMemory;
                copied = Math.Min(buffer.Length, activeBuffer.Length);
                activeBuffer.Slice(0, copied).CopyTo(buffer.Span);
                _buffer.Discard(copied);
            }
 
            completed = _buffer.IsEmpty && _final;
            empty = _buffer.IsEmpty;
 
            return copied;
        }
    }
}