DotNext by .NET Foundation and Contributors

<PackageReference Include="DotNext" Version="4.0.0-beta.1" />

 SpanReader<T>

public struct SpanReader<T>
Represents simple memory reader backed by ReadOnlySpan<T>.
using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DotNext.Buffers { [StructLayout(LayoutKind.Auto)] [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public ref struct SpanReader<[System.Runtime.CompilerServices.Nullable(2)] T> { [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] private readonly ReadOnlySpan<T> span; private int position; [IsReadOnly] public ref T Current { [IsReadOnly] [return: IsReadOnly] get { if (position >= span.Length) throw new InvalidOperationException(); return ref Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>(span), position); } } public int ConsumedCount { [IsReadOnly] get { return position; } } public int RemainingCount { [IsReadOnly] get { return span.Length - position; } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ReadOnlySpan<T> Span { [IsReadOnly] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { return span; } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ReadOnlySpan<T> ConsumedSpan { [IsReadOnly] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { return span.Slice(0, position); } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ReadOnlySpan<T> RemainingSpan { [IsReadOnly] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { return span.Slice(position); } } public SpanReader([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] ReadOnlySpan<T> span) { this.span = span; position = 0; } public SpanReader(ref T reference, int length) { if (Unsafe.IsNullRef<T>(ref reference)) throw new ArgumentNullException("reference"); span = MemoryMarshal.CreateReadOnlySpan<T>(ref reference, length); position = 0; } public void Advance(int count) { int num = checked(position + count); if (num > span.Length) throw new ArgumentOutOfRangeException("count"); position = num; } public void Rewind(int count) { if (count < 0 || count > position) throw new ArgumentOutOfRangeException("count"); position -= count; } public void Reset() { position = 0; } public bool TryRead([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] Span<T> output) { if (TryRead(output.Length, out ReadOnlySpan<T> result)) return result.TryCopyTo(output); return false; } public bool TryRead(int count, [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] out ReadOnlySpan<T> result) { if (count < 0) throw new ArgumentOutOfRangeException("count"); int num = checked(position + count); if (num <= span.Length) { result = span.Slice(position, count); position = num; return true; } result = default(ReadOnlySpan<T>); return false; } public bool TryRead([MaybeNullWhen(false)] out T result) { int num = checked(position + 1); if (num <= span.Length) { result = Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>(span), position); position = num; return true; } result = default(T); return false; } public int Read([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] Span<T> output) { DotNext.Span.CopyTo<T>(RemainingSpan, output, out int writtenCount); position += writtenCount; return writtenCount; } public T Read() { if (!TryRead(out T result)) throw new InternalBufferOverflowException(); return result; } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ReadOnlySpan<T> Read(int count) { if (!TryRead(count, out ReadOnlySpan<T> result)) throw new InternalBufferOverflowException(); return result; } [CLSCompliant(false)] public unsafe TResult Read<[System.Runtime.CompilerServices.Nullable(2)] TResult>([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 0, 1 })] IntPtr reader, int count) { if (reader == (IntPtr)(void*)null) throw new ArgumentNullException("reader"); if (!this.TryRead(count, out ReadOnlySpan<T> result)) throw new InternalBufferOverflowException(); return (TResult); } [CLSCompliant(false)] public unsafe bool TryRead<[System.Runtime.CompilerServices.Nullable(2)] TResult>([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 0, 1 })] IntPtr reader, int count, [MaybeNullWhen(false)] out TResult result) { if (reader == (IntPtr)(void*)null) throw new ArgumentNullException("reader"); if (this.TryRead(count, out ReadOnlySpan<T> result2)) { result = (TResult); return true; } result = default(TResult); return false; } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public ReadOnlySpan<T> ReadToEnd() { ReadOnlySpan<T> remainingSpan = RemainingSpan; position = span.Length; return remainingSpan; } [IsReadOnly] public override string ToString() { return ConsumedSpan.ToString(); } } }