Skip to content

Instantly share code, notes, and snippets.

@juliusfriedman
Last active July 19, 2020 21:56
Show Gist options
  • Save juliusfriedman/90ea5a5c8555dc89a2eb0b4025264d21 to your computer and use it in GitHub Desktop.
Save juliusfriedman/90ea5a5c8555dc89a2eb0b4025264d21 to your computer and use it in GitHub Desktop.
39601
// 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