Std

Mainly a port of Rust's std.
git clone https://git.philomathiclife.com/repos/Std
Log | Files | Refs | README

VecStreamReader.cs (9287B)


      1 using Std.Vec;
      2 using System;
      3 using System.IO;
      4 using System.Threading;
      5 using System.Threading.Tasks;
      6 #region Namespaces
      7 namespace Std.IO {
      8     #region Types
      9     // Read-only, non-seekable, stream based on Std.Vec.Vec<byte>.
     10     // This type is an even lighter-weight alternative to the default MemoryStream and has more strictly enforced behavior.
     11     // This type only implements I(Async)Disposable because it has to by virtue of being a subtype of System.IO.StreamIter.
     12     // This type does not dispose of anything, however, and calling dispose only suppresses the finalizer.
     13     // This type is a subtype of MemoryStream purely for performance reasons. There is a lot of code in the .NET SDK
     14     // that uses reflection to detect more specific subtypes to influence the behavior of a type or function.
     15     // We want this type to enjoy any potential benefits such code may have.
     16     // Note this type does not use the underlying data or implementation of MemoryStream in any way with exceptions of BeginRead and EndRead.
     17     [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1063:Implement IDisposable Correctly", Justification = "This type should not implement IDisposable to begin with, but it has to by being a subtype of StreamIter. We have it do nothing.")]
     18     public sealed class VecStreamReader: MemoryStream, IDisposable, IAsyncDisposable {
     19 
     20         #region Type-level Constructors
     21         #endregion
     22 
     23         #region Instance Constructors
     24         public VecStreamReader(Vec<byte> data, uint position) : base(Array.Empty<byte>(), 0, 0, false, false) {
     25 
     26             if (position <= data.Len) {
     27                 (_buffer, _originalPosition, _pos) = (data, position, position);
     28             } else {
     29                 throw new ArgumentOutOfRangeException(nameof(position), "Position must be less than or equal to the length of data.");
     30             }
     31         }
     32         #endregion
     33 
     34         #region Type-level Fields
     35         #endregion
     36 
     37         #region Instance Fields
     38         readonly Vec<byte> _buffer;
     39         readonly uint _originalPosition;
     40         uint _pos;
     41         #endregion
     42 
     43         #region Type-level Properties
     44         #endregion
     45 
     46         #region Instance Properties
     47         public sealed override bool CanRead => true;
     48         public sealed override bool CanSeek => false;
     49         public sealed override bool CanTimeout => false;
     50         public sealed override bool CanWrite => false;
     51         public sealed override int Capacity => (int)_buffer.Capacity;
     52         public uint CurrentPosition => _pos;
     53         public ReadOnlySpan<byte> ReadData => _buffer.AsSlice()[(int)_originalPosition..(int)_pos];
     54         public ReadOnlySpan<byte> UnreadData => _buffer.AsSlice()[(int)_pos..];
     55         public uint Len => _buffer.Len - _originalPosition;
     56         public sealed override long Length => Len;
     57         // The .NET SDK is littered with many terrible design decisions.
     58         // Instead of having dedicated interfaces, non-sealed classes, and non-sealed records that guarantee certain invariants,
     59         // many types have functions that are only sometimes valid. This in turn requires
     60         // many subtypes to throw exceptions for inapplicable functions.
     61         // The getter of this property should be fine to return, but the API documentation states that only seekable streams are allowed to return anything.
     62         public sealed override long Position {
     63             get => throw new NotSupportedException();
     64             set => throw new NotSupportedException();
     65         }
     66         public sealed override int ReadTimeout => throw new InvalidOperationException();
     67         public sealed override int WriteTimeout => throw new InvalidOperationException();
     68         #endregion
     69 
     70         #region Type-level Functions
     71         public static VecStreamReader New(Vec<byte> data, uint position) => new(data, position);
     72         #endregion
     73 
     74         #region Instance Functions
     75         // Due to complexity of doing this correctly, we defer to the base implementation.
     76         public sealed override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => base.BeginRead(buffer, offset, count, callback, state);
     77         public sealed override IAsyncResult BeginWrite(byte[] _, int _1, int _2, AsyncCallback? _3, object? _4) => throw new NotSupportedException();
     78         public sealed override void Close() => Dispose();
     79         public sealed override void CopyTo(Stream stream, int _) {
     80 
     81             stream.Write(_buffer.AsSlice()[(int)_pos..]);
     82             _pos = _buffer.Len;
     83         }
     84         public sealed override Task CopyToAsync(Stream stream, int bufferSize, CancellationToken _2) { CopyTo(stream, bufferSize); return Task.CompletedTask; }
     85         [Obsolete("System.Threading.ManualResetEvent should be used instead.", true)]
     86         protected sealed override WaitHandle CreateWaitHandle() => new ManualResetEvent(false);
     87         public new void Dispose() => GC.SuppressFinalize(this);
     88         [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2215:Dispose methods should call base class dispose", Justification = "We don't want Dispose to do anything.")]
     89         protected sealed override void Dispose(bool disposing) {
     90             // This should mean Dispose on StreamIter or MemoryStream was called, so we redirect to Dispose which suppresses the finalizer.
     91             if (disposing) {
     92                 Dispose();
     93             }
     94         }
     95         [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2215:Dispose methods should call base class dispose", Justification = "We don't want DisposeAsync to do anything.")]
     96         public sealed override ValueTask DisposeAsync() { 
     97         
     98             Dispose();
     99             return ValueTask.CompletedTask;
    100         }
    101         // Due to complexity of doing this correctly, we defer to the base implementation.
    102         public sealed override int EndRead(IAsyncResult asyncResult) => base.EndRead(asyncResult);
    103         public sealed override void EndWrite(IAsyncResult asyncResult) => throw new NotSupportedException();
    104         public sealed override bool Equals(object? _) => false;
    105         public sealed override void Flush() { }
    106         public sealed override Task FlushAsync(CancellationToken _) => Task.CompletedTask;
    107         public sealed override int GetHashCode() => 0;
    108         public Unit Reset() {
    109 
    110             _pos = _originalPosition;
    111             return new Unit();
    112         }
    113         public Vec<byte> GetVecBuffer() => _buffer;
    114         public sealed override byte[] GetBuffer() => _buffer.AsArray();
    115         [Obsolete("Platform does not support this. A System.PlatformNotSupportedException will be thrown.", true)]
    116         public sealed override object InitializeLifetimeService() => throw new PlatformNotSupportedException();
    117         [Obsolete("Do not call this method.", true)]
    118         protected sealed override void ObjectInvariant() { }
    119         public sealed override int Read(byte[] buffer, int offset, int count) => Read(buffer.AsSpan(offset, count));
    120         public sealed override int Read(Span<byte> buffer) {
    121 
    122             var count = (int)Math.Min(buffer.Length, _buffer.Len - _pos);
    123             _buffer.AsArray().AsSpan((int)_pos, count).CopyTo(buffer);
    124             _pos += (uint)count;
    125             return count;
    126         }
    127         public sealed override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken _) => Task.FromResult(Read(buffer.AsSpan(offset, count)));
    128         public sealed override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken _1) => ValueTask.FromResult(Read(buffer.Span));
    129         public sealed override int ReadByte() => _pos < _buffer.Len ? _buffer[_pos++] : -1;
    130         public sealed override long Seek(long _, SeekOrigin _1) => throw new NotSupportedException();
    131         public sealed override void SetLength(long _) => throw new NotSupportedException();
    132         public sealed override byte[] ToArray() {
    133 
    134             var arr = new byte[_buffer.Len - _originalPosition];
    135             Array.Copy(_buffer.AsArray(), _originalPosition, arr, 0, arr.Length);
    136             return arr;
    137         }
    138         public sealed override string ToString() => "VecStreamReader";
    139         public sealed override bool TryGetBuffer(out ArraySegment<byte> buffer) {
    140             
    141             buffer = new(_buffer.AsArray(), (int)_originalPosition, (int)(_buffer.Len - _originalPosition));
    142             return true;
    143         }
    144         public sealed override void Write(byte[] _, int _1, int _2) => throw new NotSupportedException();
    145         public sealed override void Write(ReadOnlySpan<byte> _) => throw new NotSupportedException();
    146         public sealed override Task WriteAsync(byte[] _, int _1, int _2, CancellationToken _3) => throw new NotSupportedException();
    147         public sealed override ValueTask WriteAsync(ReadOnlyMemory<byte> _, CancellationToken _1) => throw new NotSupportedException();
    148         public sealed override void WriteByte(byte _) => throw new NotSupportedException();
    149         public sealed override void WriteTo(Stream stream) => stream.Write(_buffer.AsSlice()[(int)_originalPosition..]);
    150         #endregion
    151 
    152         #region Operators
    153         #endregion
    154 
    155         #region Types
    156         #endregion
    157     }
    158     #endregion
    159 
    160     #region Namespaces
    161     #endregion
    162 }
    163 #endregion