DotNext by Roman Sakno

<PackageReference Include="DotNext" Version="3.2.0" />

 SpanWriter<T>

public struct SpanWriter<T>
Represents simple memory writer backed by Span<T>.
using System; 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 SpanWriter<[System.Runtime.CompilerServices.Nullable(2)] T> { [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] private readonly Span<T> span; private int position; public ref T Current { [IsReadOnly] get { if (position >= span.Length) throw new InvalidOperationException(); return ref Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>(span), position); } } public int FreeCapacity { [IsReadOnly] get { return span.Length - position; } } public int WrittenCount { [IsReadOnly] get { return position; } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public Span<T> RemainingSpan { [IsReadOnly] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { return span.Slice(position); } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public Span<T> WrittenSpan { [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 Span<T> Span { [IsReadOnly] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { return span; } } public SpanWriter([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] Span<T> span) { this.span = span; position = 0; } public SpanWriter(ref T reference, int length) { if (Unsafe.IsNullRef<T>(ref reference)) throw new ArgumentNullException("reference"); span = MemoryMarshal.CreateSpan<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 TryWrite([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] ReadOnlySpan<T> input) { if (!input.TryCopyTo(span.Slice(position))) return false; position += input.Length; return true; } public int Write([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] ReadOnlySpan<T> input) { DotNext.Span.CopyTo<T>(input, RemainingSpan, out int writtenCount); position += writtenCount; return writtenCount; } public bool TryAdd(T item) { int num = checked(position + 1); if (num > span.Length) return false; Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>(span), position) = item; position = num; return true; } public void Add(T item) { if (!TryAdd(item)) throw new EndOfStreamException(ExceptionMessages.NotEnoughMemory); } public bool TrySlide(int count, [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] out Span<T> segment) { if (count < 0) throw new ArgumentOutOfRangeException("count"); int num = checked(position + count); if (num <= span.Length) { segment = span.Slice(position, count); position = num; return true; } segment = default(Span<T>); return false; } [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public Span<T> Slide(int count) { if (!TrySlide(count, out Span<T> segment)) throw new EndOfStreamException(ExceptionMessages.NotEnoughMemory); return segment; } [CLSCompliant(false)] public unsafe void Write<[System.Runtime.CompilerServices.Nullable(2)] TArg>([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 0, 1, 1 })] IntPtr action, TArg arg, int count) { if (action == (IntPtr)(void*)null) throw new ArgumentNullException("action"); if (!this.TrySlide(count, out Span<T> segment)) throw new EndOfStreamException(ExceptionMessages.NotEnoughMemory); ; } [CLSCompliant(false)] public unsafe bool TryWrite<[System.Runtime.CompilerServices.Nullable(2)] TArg>([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 0, 1 })] IntPtr action, TArg arg) { if (action == (IntPtr)(void*)null) throw new ArgumentNullException("action"); int num2 = (int); if (num2 != 0) { int num = default(int); this.position += num; } return (byte)num2 != 0; } [IsReadOnly] public override string ToString() { return WrittenSpan.ToString(); } } }