VecStreamWriter.cs (8685B)
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 // Write-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 BeginWrite and EndWrite. 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 VecStreamWriter: MemoryStream, IDisposable, IAsyncDisposable { 19 20 #region Type-level Constructors 21 #endregion 22 23 #region Instance Constructors 24 public VecStreamWriter() : base(Array.Empty<byte>(), 0, 0, false, false) => _buffer = new Vec<byte>(); 25 public VecStreamWriter(uint capacity) : base(Array.Empty<byte>(), 0, 0, false, false) => _buffer = Vec<byte>.WithCapacity(capacity); 26 #endregion 27 28 #region Type-level Fields 29 #endregion 30 31 #region Instance Fields 32 Vec<byte> _buffer; 33 #endregion 34 35 #region Type-level Properties 36 #endregion 37 38 #region Instance Properties 39 public sealed override bool CanRead => false; 40 public sealed override bool CanSeek => false; 41 public sealed override bool CanTimeout => false; 42 public sealed override bool CanWrite => true; 43 public sealed override int Capacity => (int)_buffer.Capacity; 44 public ReadOnlySpan<byte> Data => _buffer.AsSlice(); 45 public uint Len => _buffer.Len; 46 public sealed override long Length => Len; 47 // The .NET SDK is littered with many terrible design decisions. 48 // Instead of having dedicated interfaces, non-sealed classes, and non-sealed records that guarantee certain invariants, 49 // many types have functions that are only sometimes valid. This in turn requires 50 // many subtypes to throw exceptions for inapplicable functions. 51 // The getter of this property should be fine to return, but the API documentation states that only seekable streams are allowed to return anything. 52 public sealed override long Position { 53 get => throw new NotSupportedException(); 54 set => throw new NotSupportedException(); 55 } 56 public sealed override int ReadTimeout => throw new InvalidOperationException(); 57 public sealed override int WriteTimeout => throw new InvalidOperationException(); 58 #endregion 59 60 #region Type-level Functions 61 public static VecStreamWriter New() => new(); 62 public static VecStreamWriter NewWithCapacity(uint capacity) => new(capacity); 63 #endregion 64 65 #region Instance Functions 66 public sealed override IAsyncResult BeginRead(byte[] _, int _1, int _2, AsyncCallback? _3, object? _4) => throw new NotSupportedException(); 67 // Due to complexity of doing this correctly, we defer to the base implementation. 68 public sealed override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => base.BeginWrite(buffer, offset, count, callback, state); 69 public sealed override void Close() => Dispose(); 70 public sealed override void CopyTo(Stream _, int _1) => throw new NotSupportedException(); 71 public sealed override Task CopyToAsync(Stream _, int _1, CancellationToken _2) => throw new NotSupportedException(); 72 [Obsolete("System.Threading.ManualResetEvent should be used instead.", true)] 73 protected sealed override WaitHandle CreateWaitHandle() => new ManualResetEvent(false); 74 [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "We don't want Dispose to do anything.")] 75 public new void Dispose() => GC.SuppressFinalize(this); 76 [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2215:Dispose methods should call base class dispose", Justification = "We don't want Dispose to do anything.")] 77 protected sealed override void Dispose(bool disposing) { 78 // This should mean Dispose on StreamIter or MemoryStream was called, so we redirect to Dispose which suppresses the finalizer. 79 if (disposing) { 80 Dispose(); 81 } 82 } 83 [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2215:Dispose methods should call base class dispose", Justification = "We don't want DisposeAsync to do anything.")] 84 public sealed override ValueTask DisposeAsync() { 85 86 Dispose(); 87 return ValueTask.CompletedTask; 88 } 89 public sealed override int EndRead(IAsyncResult _) => throw new NotSupportedException(); 90 // Due to complexity of doing this correctly, we defer to the base implementation. 91 public sealed override void EndWrite(IAsyncResult asyncResult) => base.EndWrite(asyncResult); 92 public sealed override bool Equals(object? _) => false; 93 public sealed override void Flush() { } 94 public sealed override Task FlushAsync(CancellationToken _) => Task.CompletedTask; 95 public sealed override int GetHashCode() => 0; 96 public Unit Reset() => _buffer.Clear(); 97 public Vec<byte> GetVecBuffer() => _buffer; 98 public sealed override byte[] GetBuffer() => _buffer.AsArray(); 99 [Obsolete("Platform does not support this. A System.PlatformNotSupportedException will be thrown.", true)] 100 public sealed override object InitializeLifetimeService() => throw new PlatformNotSupportedException(); 101 [Obsolete("Do not call this method.", true)] 102 protected sealed override void ObjectInvariant() { } 103 public sealed override int Read(byte[] _, int _1, int _2) => throw new NotSupportedException(); 104 public sealed override int Read(Span<byte> _) => throw new NotSupportedException(); 105 public sealed override Task<int> ReadAsync(byte[] _, int _1, int _2, CancellationToken _3) => throw new NotSupportedException(); 106 public sealed override ValueTask<int> ReadAsync(Memory<byte> _, CancellationToken _1) => throw new NotSupportedException(); 107 public sealed override int ReadByte() => throw new NotSupportedException(); 108 public sealed override long Seek(long _, SeekOrigin _1) => throw new NotSupportedException(); 109 public sealed override void SetLength(long _) => throw new NotSupportedException(); 110 public sealed override byte[] ToArray() { 111 112 var arr = new byte[_buffer.Len]; 113 _buffer.AsSlice().CopyTo(arr.AsSpan()); 114 return arr; 115 } 116 public sealed override string ToString() => "VecStreamWriter"; 117 public Unit Truncate(uint len) => _buffer.Truncate(len); 118 public sealed override bool TryGetBuffer(out ArraySegment<byte> buffer) { 119 120 buffer = new(_buffer.AsArray(), 0, (int)_buffer.Len); 121 return true; 122 } 123 public sealed override void Write(byte[] buffer, int offset, int count) => Write(buffer.AsSpan(offset, count)); 124 public sealed override void Write(ReadOnlySpan<byte> buffer) => _buffer.ExtendFromSlice(buffer); 125 public sealed override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken _) { Write(buffer.AsSpan(offset, count)); return Task.CompletedTask; } 126 public sealed override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken _1) { Write(buffer.Span); return ValueTask.CompletedTask; } 127 public sealed override void WriteByte(byte value) => _buffer.Push(value); 128 public sealed override void WriteTo(Stream stream) => stream.Write(_buffer.AsSlice()); 129 #endregion 130 131 #region Operators 132 #endregion 133 134 #region Types 135 #endregion 136 } 137 #endregion 138 139 #region Namespaces 140 #endregion 141 } 142 #endregion