aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Net.Http/src/Core/Buffering/ContextLockedBufferManager.cs42
-rw-r--r--lib/Net.Http/src/Core/Buffering/HttpBufferElement.cs7
-rw-r--r--lib/Net.Http/src/Core/HttpContext.cs68
-rw-r--r--lib/Net.Http/src/Core/HttpServerBase.cs23
-rw-r--r--lib/Net.Http/src/Core/HttpServerProcessing.cs24
-rw-r--r--lib/Net.Http/src/Core/PerfCounter/HttpPerfCounterState.cs6
-rw-r--r--lib/Net.Http/src/Core/TransportReader.cs26
-rw-r--r--lib/Net.Http/src/HttpConfig.cs59
-rw-r--r--lib/Net.Rest.Client/src/Construction/RestSiteAdapterBase.cs2
-rw-r--r--lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs4
-rw-r--r--lib/Utils/src/IO/IVnTextReader.cs7
-rw-r--r--lib/Utils/src/IO/VnTextReaderExtensions.cs4
-rw-r--r--lib/Utils/src/Memory/MemoryUtil.cs6
13 files changed, 183 insertions, 95 deletions
diff --git a/lib/Net.Http/src/Core/Buffering/ContextLockedBufferManager.cs b/lib/Net.Http/src/Core/Buffering/ContextLockedBufferManager.cs
index d8def92..b99e3ff 100644
--- a/lib/Net.Http/src/Core/Buffering/ContextLockedBufferManager.cs
+++ b/lib/Net.Http/src/Core/Buffering/ContextLockedBufferManager.cs
@@ -53,8 +53,6 @@ namespace VNLib.Net.Http.Core.Buffering
private IMemoryOwner<byte>? _handle;
private HttpBufferSegments<byte> _segments;
- #region LifeCycle
-
///<inheritdoc/>
public void AllocateBuffer(IHttpMemoryPool allocator)
{
@@ -68,24 +66,21 @@ namespace VNLib.Net.Http.Core.Buffering
Memory<byte> full = _handle.Memory;
//Header parse buffer is a special case as it will be double the size due to the char buffer
- int headerParseBufferSize = GetMaxHeaderBufferSize(in Config);
-
+ int headerParseBufferSize = GetMaxHeaderBufferSize(in Config);
int responseAndFormDataSize = ComputeResponseAndFormDataBuffer(in Config);
-
- _segments = new()
- {
- //Shared header buffer
- HeaderAccumulator = GetNextSegment(ref full, headerParseBufferSize),
- //Shared response and form data buffer
- ResponseAndFormData = GetNextSegment(ref full, responseAndFormDataSize),
+ //Shared header buffer
+ _segments.HeaderAccumulator = GetNextSegment(ref full, headerParseBufferSize);
+ _segments.ResponseAndFormData = GetNextSegment(ref full, responseAndFormDataSize);
- /*
- * The chunk accumulator buffer cannot be shared. It is also only
- * stored if chunking is enabled.
- */
- ChunkedResponseAccumulator = _chunkingEnabled ? GetNextSegment(ref full, Config.ChunkedResponseAccumulatorSize) : default
- };
+ /*
+ * The chunk accumulator buffer cannot be shared. It is also only
+ * stored if chunking is enabled.
+ */
+ _segments.ChunkedResponseAccumulator = _chunkingEnabled
+ ? GetNextSegment(ref full, Config.ChunkedResponseAccumulatorSize)
+ : default;
+
/*
* ************* WARNING ****************
@@ -133,8 +128,7 @@ namespace VNLib.Net.Http.Core.Buffering
//Clear segments
_segments = default;
-
- //Free buffer
+
if (_handle != null)
{
_handle.Dispose();
@@ -142,8 +136,6 @@ namespace VNLib.Net.Http.Core.Buffering
}
}
- #endregion
-
///<inheritdoc/>
public IHttpHeaderParseBuffer RequestHeaderParseBuffer => _requestHeaderBuffer;
@@ -212,11 +204,11 @@ namespace VNLib.Net.Http.Core.Buffering
}
- readonly struct HttpBufferSegments<T>
+ struct HttpBufferSegments<T>
{
- public readonly Memory<T> HeaderAccumulator { get; init; }
- public readonly Memory<T> ChunkedResponseAccumulator { get; init; }
- public readonly Memory<T> ResponseAndFormData { get; init; }
+ public Memory<T> HeaderAccumulator;
+ public Memory<T> ChunkedResponseAccumulator;
+ public Memory<T> ResponseAndFormData;
}
diff --git a/lib/Net.Http/src/Core/Buffering/HttpBufferElement.cs b/lib/Net.Http/src/Core/Buffering/HttpBufferElement.cs
index 774ed6a..173048a 100644
--- a/lib/Net.Http/src/Core/Buffering/HttpBufferElement.cs
+++ b/lib/Net.Http/src/Core/Buffering/HttpBufferElement.cs
@@ -76,7 +76,9 @@ namespace VNLib.Net.Http.Core.Buffering
///<inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual Span<byte> GetBinSpan(int offset, int size)
- => (offset + size) < _handle.Size ? _handle.GetSpan(offset, size) : throw new ArgumentOutOfRangeException(nameof(offset));
+ => (offset + size) < _handle.Size
+ ? _handle.GetSpan(offset, size)
+ : throw new ArgumentOutOfRangeException(nameof(offset));
private struct HandleState
@@ -87,6 +89,7 @@ namespace VNLib.Net.Http.Core.Buffering
public readonly int Size;
public readonly Memory<byte> Memory;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public HandleState(Memory<byte> mem)
{
Memory = mem;
@@ -97,12 +100,14 @@ namespace VNLib.Net.Http.Core.Buffering
public readonly void Unpin() => _handle.Dispose();
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Span<byte> GetSpan(int offset, int size)
{
Debug.Assert((offset + size) < Size, "Call to GetSpan failed because the offset/size was out of valid range");
return MemoryUtil.GetSpan<byte>(IntPtr.Add(_pointer, offset), size);
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ref byte GetRef() => ref MemoryUtil.GetRef<byte>(_pointer);
}
}
diff --git a/lib/Net.Http/src/Core/HttpContext.cs b/lib/Net.Http/src/Core/HttpContext.cs
index dc857b8..bd553e3 100644
--- a/lib/Net.Http/src/Core/HttpContext.cs
+++ b/lib/Net.Http/src/Core/HttpContext.cs
@@ -25,6 +25,7 @@
using System;
using System.IO;
using System.Text;
+using System.Threading;
using System.Diagnostics;
using System.Threading.Tasks;
@@ -129,14 +130,73 @@ namespace VNLib.Net.Http.Core
HttpVersion IHttpContextInformation.CurrentVersion => Request.State.HttpVersion;
///<inheritdoc/>
- public ref readonly HttpEncodedSegment CrlfSegment => ref ParentServer.CrlfBytes;
+ public ref readonly HttpEncodedSegment CrlfSegment => ref ParentServer.Config.CrlfBytes;
///<inheritdoc/>
- public ref readonly HttpEncodedSegment FinalChunkSegment => ref ParentServer.FinalChunkBytes;
+ public ref readonly HttpEncodedSegment FinalChunkSegment => ref ParentServer.Config.FinalChunkBytes;
///<inheritdoc/>
public Stream GetTransport() => _ctx!.ConnectionStream;
+ int _bytesRead;
+
+ /*
+ * The following functions operate in tandem. Data should be buffered
+ * by a call to BufferTransportAsync() and then made availbe by a call to
+ * GetReader(). This set of functions only happens once per request/response
+ * cycle. This allows a async buffer filling before a syncronous transport
+ * read.
+ */
+
+ public void GetReader(out TransportReader reader)
+ {
+ Debug.Assert(_ctx != null, "Request to transport reader was called by the connection context was null");
+
+ reader = new(
+ _ctx!.ConnectionStream,
+ Buffers.RequestHeaderParseBuffer,
+ ParentServer.Config.HttpEncoding,
+ ParentServer.Config.HeaderLineTermination
+ );
+
+ /*
+ * Specal function to set available data
+ * NOTE: this can be dangerous as the buffer is
+ */
+ reader.SetAvailableData(_bytesRead);
+
+ Debug.Assert(reader.Available == _bytesRead);
+ }
+
+ public async ValueTask BufferTransportAsync(CancellationToken cancellation)
+ {
+ /*
+ * This function allows for pre-buffering of the transport
+ * before parsing the response. It also allows waiting for more data async
+ * when an http1 request is in keep-alive mode waiting for more data.
+ *
+ * We can asynchronously read data when its available and preload
+ * the transport reader. The only catch is we need to access the
+ * raw Memory<byte> structure within the buffer. So the binary
+ * buffer size MUST be respected.
+ */
+
+ Debug.Assert(_ctx != null, "Request to buffer transport was called by the connection context was null");
+
+ _bytesRead = 0;
+
+ Memory<byte> dataBuffer = Buffers.ResponseHeaderBuffer.GetMemory();
+
+ /*
+ * Since this buffer must be shared with char buffers, size
+ * must be respected. Remember that split buffesr store binary
+ * data at the head of the buffer and char data at the tail
+ */
+ dataBuffer = dataBuffer[..Buffers.ResponseHeaderBuffer.BinSize];
+
+ _bytesRead = await _ctx!.ConnectionStream.ReadAsync(dataBuffer, cancellation);
+ }
+
#endregion
#region LifeCycle Hooks
@@ -173,6 +233,8 @@ namespace VNLib.Net.Http.Core
///<inheritdoc/>
public void EndRequest()
{
+ _bytesRead = 0; //Must reset after every request
+
Request.OnComplete();
Response.OnComplete();
ResponseBody.OnComplete();
@@ -203,4 +265,4 @@ namespace VNLib.Net.Http.Core
#endregion
}
-} \ No newline at end of file
+}
diff --git a/lib/Net.Http/src/Core/HttpServerBase.cs b/lib/Net.Http/src/Core/HttpServerBase.cs
index f5f3563..ec6e73d 100644
--- a/lib/Net.Http/src/Core/HttpServerBase.cs
+++ b/lib/Net.Http/src/Core/HttpServerBase.cs
@@ -89,11 +89,7 @@ namespace VNLib.Net.Http
/// Reusable store for obtaining <see cref="HttpContext"/>
/// </summary>
private readonly ObjectRental<HttpContext> ContextStore;
-
- /// <summary>
- /// The cached header-line termination value
- /// </summary>
- private readonly ReadOnlyMemory<byte> HeaderLineTermination;
+
#endregion
/// <summary>
@@ -111,16 +107,6 @@ namespace VNLib.Net.Http
/// </summary>
internal readonly CompressionMethod SupportedCompressionMethods;
- /// <summary>
- /// Pre-encoded CRLF bytes
- /// </summary>
- internal readonly HttpEncodedSegment CrlfBytes;
-
- /// <summary>
- /// Pre-encoded HTTP chunking final chunk segment
- /// </summary>
- internal readonly HttpEncodedSegment FinalChunkBytes;
-
private CancellationTokenSource? StopToken;
/// <summary>
@@ -153,13 +139,6 @@ namespace VNLib.Net.Http
//Cache wildcard root
_wildcardRoot = ServerRoots.GetValueOrDefault(WILDCARD_KEY);
-
- //Init pre-encded segments
- CrlfBytes = HttpEncodedSegment.FromString(HttpHelpers.CRLF, config.HttpEncoding);
- FinalChunkBytes = HttpEncodedSegment.FromString("0\r\n\r\n", config.HttpEncoding);
-
- //Store a ref to the crlf memory segment
- HeaderLineTermination = CrlfBytes.Buffer.AsMemory();
}
private static void ValidateConfig(in HttpConfig conf)
diff --git a/lib/Net.Http/src/Core/HttpServerProcessing.cs b/lib/Net.Http/src/Core/HttpServerProcessing.cs
index b6dbfef..2116341 100644
--- a/lib/Net.Http/src/Core/HttpServerProcessing.cs
+++ b/lib/Net.Http/src/Core/HttpServerProcessing.cs
@@ -36,7 +36,6 @@ using VNLib.Utils.Memory;
using VNLib.Utils.Logging;
using VNLib.Utils.Extensions;
using VNLib.Net.Http.Core;
-using VNLib.Net.Http.Core.Buffering;
using VNLib.Net.Http.Core.Response;
using VNLib.Net.Http.Core.PerfCounter;
@@ -60,8 +59,14 @@ namespace VNLib.Net.Http
{
Stream stream = transportContext.ConnectionStream;
- //Set write timeout
+ /*
+ * Write timeout is constant for the duration of an HTTP
+ * connection. Read timeout must be set to active on initial
+ * loop because a fresh connection is assumed to have data
+ * ready.
+ */
stream.WriteTimeout = _config.SendTimeout;
+ stream.ReadTimeout = _config.ActiveConnectionRecvTimeout;
//Init stream
context.InitializeContext(transportContext);
@@ -69,6 +74,9 @@ namespace VNLib.Net.Http
//Keep the transport open and listen for messages as long as keepalive is enabled
do
{
+ //Attempt to buffer a new (or keepalive) connection async
+ await context.BufferTransportAsync(StopToken!.Token);
+
//Set rx timeout low for initial reading
stream.ReadTimeout = _config.ActiveConnectionRecvTimeout;
@@ -84,9 +92,6 @@ namespace VNLib.Net.Http
//Reset inactive keeaplive timeout, when expired the following read will throw a cancealltion exception
stream.ReadTimeout = (int)_config.ConnectionKeepAlive.TotalMilliseconds;
- //"Peek" or wait for more data to begin another request (may throw timeout exception when timmed out)
- await stream.ReadAsync(Memory<byte>.Empty, StopToken!.Token);
-
} while (true);
//Check if an alternate protocol was specified
@@ -276,17 +281,14 @@ namespace VNLib.Net.Http
//TODO: future support for http2 and http3 over tls
}
- //Get the parse buffer
- IHttpHeaderParseBuffer parseBuffer = ctx.Buffers.RequestHeaderParseBuffer;
-
- TransportReader reader = new (ctx.GetTransport(), parseBuffer, _config.HttpEncoding, HeaderLineTermination);
+ ctx.GetReader(out TransportReader reader);
HttpStatusCode code;
try
{
//Get the char span
- Span<char> lineBuf = parseBuffer.GetCharSpan();
+ Span<char> lineBuf = ctx.Buffers.RequestHeaderParseBuffer.GetCharSpan();
Http11ParseExtensions.Http1ParseState parseState = new();
@@ -476,4 +478,4 @@ namespace VNLib.Net.Http
}
}
-} \ No newline at end of file
+}
diff --git a/lib/Net.Http/src/Core/PerfCounter/HttpPerfCounterState.cs b/lib/Net.Http/src/Core/PerfCounter/HttpPerfCounterState.cs
index a86ac40..89b622d 100644
--- a/lib/Net.Http/src/Core/PerfCounter/HttpPerfCounterState.cs
+++ b/lib/Net.Http/src/Core/PerfCounter/HttpPerfCounterState.cs
@@ -3,10 +3,10 @@
*
* Library: VNLib
* Package: VNLib.Net.Http
-* File: ConnectionInfo.cs
+* File: HttpPerfCounterState.cs
*
-* ConnectionInfo.cs is part of VNLib.Net.Http which is part of the larger
-* VNLib collection of libraries and utilities.
+* HttpPerfCounterState.cs is part of VNLib.Net.Http which is part of the
+* larger VNLib collection of libraries and utilities.
*
* VNLib.Net.Http is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
diff --git a/lib/Net.Http/src/Core/TransportReader.cs b/lib/Net.Http/src/Core/TransportReader.cs
index 0b38121..7cd8b8b 100644
--- a/lib/Net.Http/src/Core/TransportReader.cs
+++ b/lib/Net.Http/src/Core/TransportReader.cs
@@ -45,16 +45,14 @@ namespace VNLib.Net.Http.Core
/// <param name="buffer">The shared binary buffer</param>
/// <param name="encoding">The encoding to use when reading bianry</param>
/// <param name="lineTermination">The line delimiter to search for</param>
- internal struct TransportReader(Stream transport, IHttpHeaderParseBuffer buffer, Encoding encoding, ReadOnlyMemory<byte> lineTermination) : IVnTextReader
+ internal struct TransportReader(Stream transport, IHttpHeaderParseBuffer buffer, Encoding encoding, ReadOnlyMemory<byte> lineTermination)
+ : IVnTextReader
{
///<inheritdoc/>
public readonly Encoding Encoding => encoding;
///<inheritdoc/>
- public readonly ReadOnlyMemory<byte> LineTermination => lineTermination;
-
- ///<inheritdoc/>
- public readonly Stream BaseStream => transport;
+ public readonly ReadOnlyMemory<byte> LineTermination => lineTermination;
private readonly uint MaxBufferSize = (uint)buffer.BinSize;
@@ -79,15 +77,23 @@ namespace VNLib.Net.Http.Core
///<inheritdoc/>
public void Advance(int count)
{
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count), "Count must be positive");
- }
+ ArgumentOutOfRangeException.ThrowIfNegative(count);
//Advance the window start by the count and set the position
_position = _position.AdvanceStart(count);
}
+ /// <summary>
+ /// Sets the number of bytes to read from the transport stream
+ /// </summary>
+ /// <param name="start">The number of bytes to make available within the buffer window</param>
+ public void SetAvailableData(int start)
+ {
+ Debug.Assert(start <= MaxBufferSize, "Stream buffer would overflow");
+
+ _position = _position.AdvanceEnd(start);
+ }
+
///<inheritdoc/>
public void FillBuffer()
{
@@ -110,7 +116,7 @@ namespace VNLib.Net.Http.Core
{
//Get a ref to the entire buffer segment, then do an in-place move to shift the data to the start of the buffer
ref byte ptr = ref buffer.DangerousGetBinRef(0);
- MemoryUtil.Memmove(ref ptr, _position.WindowStart, ref ptr, 0, windowSize);
+ MemoryUtil.Memmove(ref ptr, _position.WindowStart, ref ptr, dstOffset: 0, windowSize);
/*
* Now that data has been shifted, update the position to
diff --git a/lib/Net.Http/src/HttpConfig.cs b/lib/Net.Http/src/HttpConfig.cs
index c74bdbb..ff0434f 100644
--- a/lib/Net.Http/src/HttpConfig.cs
+++ b/lib/Net.Http/src/HttpConfig.cs
@@ -25,6 +25,7 @@
using System;
using System.Text;
+using VNLib.Net.Http.Core;
using VNLib.Utils.Logging;
namespace VNLib.Net.Http
@@ -32,15 +33,57 @@ namespace VNLib.Net.Http
/// <summary>
/// Represents configration variables used to create the instance and manage http connections
/// </summary>
- /// <param name="ServerLog">
- /// A log provider that all server related log entiries will be written to
- /// </param>
- /// <param name="MemoryPool">
- /// Server memory pool to use for allocating buffers
- /// </param>
- public readonly record struct HttpConfig(ILogProvider ServerLog, IHttpMemoryPool MemoryPool)
+ public readonly record struct HttpConfig
{
-
+ /// <summary>
+ /// Pre-encoded CRLF bytes
+ /// </summary>
+ internal readonly HttpEncodedSegment CrlfBytes;
+
+ /// <summary>
+ /// Pre-encoded HTTP chunking final chunk segment
+ /// </summary>
+ internal readonly HttpEncodedSegment FinalChunkBytes;
+
+ /// <summary>
+ /// The cached header-line termination value
+ /// </summary>
+ internal readonly ReadOnlyMemory<byte> HeaderLineTermination;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HttpConfig"/> struct
+ /// </summary>
+ /// <param name="serverLog"></param>
+ /// <param name="memoryPool"></param>
+ /// <param name="httpEncoding"></param>
+ public HttpConfig(ILogProvider serverLog, IHttpMemoryPool memoryPool, Encoding httpEncoding)
+ {
+ ArgumentNullException.ThrowIfNull(serverLog);
+ ArgumentNullException.ThrowIfNull(memoryPool);
+ ArgumentNullException.ThrowIfNull(httpEncoding);
+
+ ServerLog = serverLog;
+ MemoryPool = memoryPool;
+ HttpEncoding = httpEncoding;
+
+ //Init pre-encded segments
+ CrlfBytes = HttpEncodedSegment.FromString(HttpHelpers.CRLF, httpEncoding);
+ FinalChunkBytes = HttpEncodedSegment.FromString("0\r\n\r\n", httpEncoding);
+
+ //Store a ref to the crlf memory segment
+ HeaderLineTermination = CrlfBytes.Buffer.AsMemory();
+ }
+
+ /// <summary>
+ /// A log provider that all server related log entiries will be written to
+ /// </summary>
+ public ILogProvider ServerLog { get; init; }
+
+ /// <summary>
+ /// Server memory pool to use for allocating buffers
+ /// </summary>
+ public IHttpMemoryPool MemoryPool { get; init; }
+
/// <summary>
/// The absolute request entity body size limit in bytes
/// </summary>
diff --git a/lib/Net.Rest.Client/src/Construction/RestSiteAdapterBase.cs b/lib/Net.Rest.Client/src/Construction/RestSiteAdapterBase.cs
index 4383d51..a200a95 100644
--- a/lib/Net.Rest.Client/src/Construction/RestSiteAdapterBase.cs
+++ b/lib/Net.Rest.Client/src/Construction/RestSiteAdapterBase.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Rest.Client
diff --git a/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs b/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs
index cb3486f..e47dd37 100644
--- a/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs
+++ b/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs
@@ -380,11 +380,11 @@ namespace VNLib.Net.Transport.Tcp
return new(AwaitFlushTask(result, timer));
}
}
- catch
+ catch(Exception ex)
{
//Stop timer on exception
timer.Stop();
- throw;
+ return ValueTask.FromException(ex);
}
}
diff --git a/lib/Utils/src/IO/IVnTextReader.cs b/lib/Utils/src/IO/IVnTextReader.cs
index 625ba78..93de2d1 100644
--- a/lib/Utils/src/IO/IVnTextReader.cs
+++ b/lib/Utils/src/IO/IVnTextReader.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -23,7 +23,6 @@
*/
using System;
-using System.IO;
using System.Text;
namespace VNLib.Utils.IO
@@ -34,10 +33,6 @@ namespace VNLib.Utils.IO
public interface IVnTextReader
{
/// <summary>
- /// The base stream to read data from
- /// </summary>
- Stream BaseStream { get; }
- /// <summary>
/// The character encoding used by the TextReader
/// </summary>
Encoding Encoding { get; }
diff --git a/lib/Utils/src/IO/VnTextReaderExtensions.cs b/lib/Utils/src/IO/VnTextReaderExtensions.cs
index 9ca5ae5..5dc6117 100644
--- a/lib/Utils/src/IO/VnTextReaderExtensions.cs
+++ b/lib/Utils/src/IO/VnTextReaderExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -66,6 +66,7 @@ namespace VNLib.Utils.IO
/// <remarks>Allows reading lines of data from the stream without allocations</remarks>
public static ERRNO ReadLine<T>(this T reader, Span<char> charBuffer) where T : class, IVnTextReader
{
+ ArgumentNullException.ThrowIfNull(reader);
return ReadLineInternal(ref reader, charBuffer);
}
@@ -118,6 +119,7 @@ namespace VNLib.Utils.IO
/// <remarks>You should use the <see cref="IVnTextReader.Available"/> property to know how much remaining data is buffered</remarks>
public static int ReadRemaining<T>(this T reader, Span<byte> buffer) where T : class, IVnTextReader
{
+ ArgumentNullException.ThrowIfNull(reader);
return ReadRemainingInternal(ref reader, buffer);
}
diff --git a/lib/Utils/src/Memory/MemoryUtil.cs b/lib/Utils/src/Memory/MemoryUtil.cs
index 7ce7c81..d10efc8 100644
--- a/lib/Utils/src/Memory/MemoryUtil.cs
+++ b/lib/Utils/src/Memory/MemoryUtil.cs
@@ -964,7 +964,8 @@ namespace VNLib.Utils.Memory
/// <summary>
/// Optimized memmove for known small memory blocks. This method is faster than
/// <see cref="Memmove{T}(ref readonly T, nuint, ref T, nuint, nuint)"/> when the
- /// number of elements to copy is known to be small.
+ /// number of elements to copy is known to be small. Pointers to src and dst may be
+ /// overlapping regions of memory.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="src">A readonly reference to the first element in the source memory sequence</param>
@@ -999,7 +1000,7 @@ namespace VNLib.Utils.Memory
/// <summary>
/// Low level api for copying data from source memory to destination memory of an
- /// umanged data type.
+ /// umanged data type. Pointers to src and dst may be overlapping regions of memory.
/// </summary>
/// <remarks>
/// WARNING: It's not possible to do bounds checking when using references. Be sure you
@@ -1034,6 +1035,7 @@ namespace VNLib.Utils.Memory
/// <summary>
/// Low level api for copying data from source memory to destination memory of an
/// umanged data type. This call attempts to force hadrware acceleration if supported.
+ /// Pointers to src and dst may be overlapping regions of memory.
/// <para>
/// Understand that using this function attempts to force hardware acceleration, which
/// may hurt performance if the data is not large enough to justify the overhead.