Last active
July 19, 2020 21:56
-
-
Save juliusfriedman/90ea5a5c8555dc89a2eb0b4025264d21 to your computer and use it in GitHub Desktop.
39601
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Discussions @ | |
// https://github.com/dotnet/runtime/issues/39601 | |
// https://discord.com/channels/734490970309001236/734490970309001239 | |
//----------------------------------------------------- | |
namespace System.IO | |
{ | |
public interface IDisposed : IDisposable { bool ShouldDispose { get; } bool IsDisposed { get; } } | |
public interface IStream | |
{ | |
public Stream Stream { get; } | |
public Stream Null { get; } | |
public Stream Empty { get; } | |
public Stream Default { get; } | |
} | |
public class BaseStream : Stream, IStream, IDisposed | |
{ | |
#region Statics | |
public static readonly Stream DefaultStream = new BaseStream(); | |
public static readonly Stream EmptyStream = new BaseStream(null, 0, false, false, false); | |
#endregion | |
#region Fields | |
protected bool m_CanRead, m_CanSeek, m_CanWrite; | |
protected long m_Length, m_Position; | |
#endregion | |
#region Properties | |
public override bool CanRead => m_CanRead; | |
public override bool CanSeek => m_CanSeek; | |
public override bool CanWrite => m_CanWrite; | |
public override long Length => m_Length; | |
public override long Position { get => m_Position; set => m_Position = value; } | |
#endregion | |
#region IStream | |
public virtual Stream Stream => this; | |
public new virtual Stream Null => Stream.Null; | |
public virtual Stream Empty => EmptyStream; | |
public virtual Stream Default => DefaultStream; | |
#endregion | |
#region IDisposed | |
public virtual bool ShouldDispose {get; protected set; } = true; | |
public virtual bool IsDisposed { get; protected set; } = false; | |
#endregion | |
#region Constructor | |
public BaseStream() : base() { } | |
public BaseStream(BaseStream other, long length, bool canRead, bool canSeek, bool canWrite) : this() | |
{ | |
m_CanRead = canRead; | |
m_CanSeek = canSeek; | |
m_CanWrite = canWrite; | |
m_Length = length; | |
} | |
#endregion | |
#region Stream | |
public override void Flush() | |
{ | |
base.FlushAsync().Wait(); | |
} | |
public override int Read(byte[] buffer, int offset, int count) | |
{ | |
return base.ReadAsync(buffer, offset, count).Result; | |
} | |
public override long Seek(long offset, SeekOrigin origin) | |
{ | |
return SeekAsync(offset, origin).Result; | |
} | |
public override void SetLength(long value) | |
{ | |
if (value < 0) value = 0; | |
m_Length = value; | |
} | |
public override void Write(byte[] buffer, int offset, int count) | |
{ | |
base.WriteAsync(buffer, offset, count).Wait(); | |
} | |
public override ValueTask DisposeAsync() | |
{ | |
IsDisposed = true; | |
return new ValueTask(Task.CompletedTask); | |
} | |
#endregion | |
public virtual async System.Threading.Tasks.ValueTask<long> SeekAsync(long offset, SeekOrigin origin) | |
{ | |
switch (origin) | |
{ | |
case SeekOrigin.Begin: return await System.Threading.Tasks.Task.FromResult(m_Position = offset); | |
case SeekOrigin.Current: return await System.Threading.Tasks.Task.FromResult(m_Position += offset); | |
case SeekOrigin.End: return await System.Threading.Tasks.Task.FromResult(m_Position = m_Length - offset); | |
default: return await System.Threading.Tasks.Task.FromResult(-1); | |
} | |
} | |
} | |
public abstract class ManagedStream : BaseStream | |
{ | |
#region Constructor | |
public ManagedStream() : base() { } | |
public ManagedStream(BaseStream other, long length, bool canRead, bool canSeek, bool canWrite) : | |
this() {} | |
#endregion | |
} | |
public abstract class IndirectStream : ManagedStream { } | |
} | |
//----------------------------------------------------- | |
namespace System.IO.Concurrent | |
{ | |
public abstract class ReadOnlyStream : System.IO.ManagedStream | |
{ | |
public ReadOnlyStream() : base(null, 0, true, true, false) { } | |
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) | |
=> System.Threading.Tasks.Task.FromResult(-1); | |
public override void Write(byte[] buffer, int offset, int count) { } | |
} | |
public abstract class WriteOnlyStream : System.IO.ManagedStream | |
{ | |
public WriteOnlyStream() : base(null, 0, false, true, true) { } | |
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) | |
=> System.Threading.Tasks.Task.FromResult(-1); | |
public override int Read(byte[] buffer, int offset, int count) { return -1; } | |
} | |
public abstract class SeekableStream : System.IO.ManagedStream | |
{ | |
public SeekableStream() : base(null, 0, false, true, false) { } | |
} | |
public abstract class ConcurrentStream : System.IO.ManagedStream | |
{ | |
#region Nested Types | |
public interface IConcurrentStreamOptions | |
{ | |
public Guid Configuration {get;} | |
} | |
#endregion | |
#region Fields | |
protected ushort m_CurrentReaders, m_CurrentSeekers, m_CurrentWriters, | |
m_MaxReaders, m_MaxSeekers, m_MaxWriters, | |
m_Reserved1, m_Reserved2; | |
protected IConcurrentStreamOptions m_Options; | |
#endregion | |
#region Properties | |
public int CurrentReaders => m_CurrentReaders; | |
public int CurrentSeekers => m_CurrentSeekers; | |
public int CurrentWriters => m_CurrentWriters; | |
public int MaxReaders => m_MaxReaders; | |
public int MaxSeekers => m_MaxSeekers; | |
public int MaxWriters => m_MaxWriters; | |
#endregion | |
public ConcurrentStream(IConcurrentStreamOptions options, BaseStream @base, long length = -1, bool canRead = true, bool canSeek = true, bool canWrite = true) | |
: base(@base, length, canRead, canSeek, canWrite) | |
{ | |
if (null == options) throw new ArgumentNullException(nameof(options)); | |
m_Options = options; | |
} | |
internal ConcurrentStream(Guid options, Stream stream = null) : base() | |
{ | |
ref byte guidBytes = ref System.Runtime.CompilerServices.Unsafe.As<Guid, byte>(ref options); | |
m_Options = System.Runtime.CompilerServices.Unsafe.As<byte, IConcurrentStreamOptions>(ref guidBytes); | |
m_CanRead = m_Reserved1 > 0; | |
m_CanSeek = m_Reserved1 > 1; | |
m_CanWrite = m_Reserved1 > 2; | |
//---- | |
m_Length = m_Reserved1 << 3; | |
if (m_Reserved2 <= short.MaxValue) m_Position = m_Reserved2; | |
else | |
{ | |
m_Position += stream.Position + m_Reserved2; | |
} | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment