AsyncStream everything

This commit is contained in:
Adam Hathcock
2021-02-13 16:16:03 +00:00
parent 949e90351f
commit 1f37ced35a
24 changed files with 205 additions and 242 deletions

View File

@@ -101,8 +101,8 @@ namespace SharpCompress.Archives
{
if (!disposed)
{
await lazyVolumes.ForEachAsync(v => v.Dispose());
lazyEntries.GetLoaded().Cast<Entry>().ForEach(x => x.Close());
await lazyVolumes.ForEachAsync(async v => await v.DisposeAsync());
await lazyEntries.GetLoaded().Cast<Entry>().ForEachAsync(async x => await x.CloseAsync());
disposed = true;
}
}

View File

@@ -168,9 +168,9 @@ namespace SharpCompress.Archives
public override async ValueTask DisposeAsync()
{
await base.DisposeAsync();
newEntries.Cast<Entry>().ForEach(x => x.Close());
removedEntries.Cast<Entry>().ForEach(x => x.Close());
modifiedEntries.Cast<Entry>().ForEach(x => x.Close());
await newEntries.Cast<Entry>().ForEachAsync(async x => await x.CloseAsync());
await removedEntries.Cast<Entry>().ForEachAsync(async x => await x.CloseAsync());
await modifiedEntries.Cast<Entry>().ForEachAsync(async x => await x.CloseAsync());
}
}
}

View File

@@ -59,11 +59,11 @@ namespace SharpCompress.Archives.GZip
return new(new NonDisposingStream(stream));
}
internal override void Close()
internal override async ValueTask CloseAsync()
{
if (closeStream)
{
stream.Dispose();
await stream.DisposeAsync();
}
}
}

View File

@@ -58,11 +58,11 @@ namespace SharpCompress.Archives.Tar
return new(new NonDisposingStream(stream));
}
internal override void Close()
internal override async ValueTask CloseAsync()
{
if (closeStream)
{
stream.Dispose();
await stream.DisposeAsync();
}
}
}

View File

@@ -58,11 +58,11 @@ namespace SharpCompress.Archives.Zip
return new(new NonDisposingStream(stream));
}
internal override void Close()
internal override async ValueTask CloseAsync()
{
if (closeStream && !isDisposed)
{
stream.Dispose();
await stream.DisposeAsync();
isDisposed = true;
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace SharpCompress.Common
{
@@ -77,8 +78,9 @@ namespace SharpCompress.Common
internal bool IsSolid { get; set; }
internal virtual void Close()
internal virtual ValueTask CloseAsync()
{
return new ();
}
/// <summary>

View File

@@ -2,11 +2,12 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common
{
public class EntryStream : Stream
public class EntryStream : AsyncStream
{
private readonly IReader _reader;
private readonly Stream _stream;
@@ -42,21 +43,11 @@ namespace SharpCompress.Common
await _stream.DisposeAsync();
}
protected override void Dispose(bool disposing)
{
throw new NotImplementedException();
}
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override void Flush()
{
}
public override long Length => _stream.Length;
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
@@ -71,14 +62,14 @@ namespace SharpCompress.Common
return read;
}
public override int Read(byte[] buffer, int offset, int count)
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
public override int ReadByte()
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
@@ -90,10 +81,5 @@ namespace SharpCompress.Common
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
}
}

View File

@@ -2,7 +2,7 @@
namespace SharpCompress.Common
{
public interface IVolume : IDisposable
public interface IVolume : IAsyncDisposable
{
}
}

View File

@@ -38,11 +38,6 @@ namespace SharpCompress.Common.Tar
}
}
protected override void Dispose(bool disposing)
{
throw new NotImplementedException();
}
private long BytesLeftToRead { get; set; }
public override bool CanRead => true;
@@ -51,11 +46,6 @@ namespace SharpCompress.Common.Tar
public override bool CanWrite => false;
public override void Flush()
{
throw new NotSupportedException();
}
public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
@@ -76,17 +66,6 @@ namespace SharpCompress.Common.Tar
return read;
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
public override int ReadByte()
{
throw new NotImplementedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
@@ -96,10 +75,5 @@ namespace SharpCompress.Common.Tar
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
}
}

View File

@@ -1,5 +1,5 @@
using System;
using System.IO;
using System.IO;
using System.Threading.Tasks;
using SharpCompress.IO;
using SharpCompress.Readers;
@@ -33,19 +33,10 @@ namespace SharpCompress.Common
/// RarArchive is part of a multi-part archive.
/// </summary>
public virtual bool IsMultiVolume => true;
protected virtual void Dispose(bool disposing)
public ValueTask DisposeAsync()
{
if (disposing)
{
_actualStream.Dispose();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
return _actualStream.DisposeAsync();
}
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Buffers;
using System.Buffers.Binary;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Crypto;
using SharpCompress.IO;
@@ -59,15 +60,15 @@ namespace SharpCompress.Compressors.LZMA
return lzip;
}
public void Finish()
public async ValueTask FinishAsync()
{
if (!_finished)
{
if (Mode == CompressionMode.Compress)
{
var crc32Stream = (Crc32Stream)_stream;
crc32Stream.WrappedStream.Dispose();
crc32Stream.Dispose();
await crc32Stream.WrappedStream.DisposeAsync();
await crc32Stream.DisposeAsync();
var compressedCount = _countingWritableSubStream!.Count;
byte[] intBuf = new byte[8];
@@ -87,17 +88,22 @@ namespace SharpCompress.Compressors.LZMA
#region Stream methods
protected override void Dispose(bool disposing)
public override async ValueTask DisposeAsync()
{
if (_disposed)
{
return;
}
_disposed = true;
await FinishAsync();
await _stream.DisposeAsync();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Finish();
_stream.Dispose();
throw new NotSupportedException();
}
}
@@ -120,41 +126,40 @@ namespace SharpCompress.Compressors.LZMA
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public override int Read(byte[] buffer, int offset, int count) => _stream.Read(buffer, offset, count);
public override int Read(byte[] buffer, int offset, int count) => throw new NotImplementedException();
public override int ReadByte() => _stream.ReadByte();
public override int ReadByte() => throw new NotSupportedException();
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = new CancellationToken())
{
return _stream.ReadAsync(buffer, cancellationToken);
}
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotImplementedException();
#if !NET461 && !NETSTANDARD2_0
public override int Read(Span<byte> buffer)
{
return _stream.Read(buffer);
}
public override void Write(ReadOnlySpan<byte> buffer)
{
_stream.Write(buffer);
_writeCount += buffer.Length;
}
#endif
public override void Write(byte[] buffer, int offset, int count)
{
_stream.Write(buffer, offset, count);
throw new NotSupportedException();
}
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = new CancellationToken())
{
await _stream.WriteAsync(buffer, cancellationToken);
_writeCount += buffer.Length;
}
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
await _stream.WriteAsync(buffer, offset, count, cancellationToken);
_writeCount += count;
}
public override void WriteByte(byte value)
{
_stream.WriteByte(value);
++_writeCount;
throw new NotSupportedException();
}
#endregion

View File

@@ -224,7 +224,7 @@ namespace SharpCompress.Compressors.LZMA
_highCoder.Init();
}
public virtual async ValueTask EncodeAsync(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
public async ValueTask EncodeAsync(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
{
if (symbol < Base.K_NUM_LOW_LEN_SYMBOLS)
{
@@ -310,7 +310,7 @@ namespace SharpCompress.Compressors.LZMA
}
}
public override async ValueTask EncodeAsync(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
public new async ValueTask EncodeAsync(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
{
await base.EncodeAsync(rangeEncoder, symbol, posState);
if (--_counters[posState] == 0)

View File

@@ -7,10 +7,11 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Compressors.LZMA.LZ;
using SharpCompress.IO;
namespace SharpCompress.Compressors.LZMA
{
public class LzmaStream : Stream
public class LzmaStream : AsyncStream
{
private Stream _inputStream;
private long _inputSize;
@@ -119,11 +120,6 @@ namespace SharpCompress.Compressors.LZMA
public override bool CanWrite => _encoder != null;
public override void Flush()
{
throw new NotSupportedException();
}
public override async ValueTask DisposeAsync()
{
if (_isDisposed)
@@ -138,20 +134,10 @@ namespace SharpCompress.Compressors.LZMA
_inputStream?.DisposeAsync();
}
protected override void Dispose(bool disposing)
{
throw new NotSupportedException();
}
public override long Length => _position + _availableBytes;
public override long Position { get => _position; set => throw new NotSupportedException(); }
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (_endReached)
@@ -307,22 +293,25 @@ namespace SharpCompress.Compressors.LZMA
throw new NotSupportedException();
}
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (_encoder != null)
{
_position = await _encoder.CodeAsync(new MemoryStream(buffer, offset, count), false);
}
}
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = new CancellationToken())
{
if (_encoder != null)
{
var m = ArrayPool<byte>.Shared.Rent(buffer.Length);
buffer.CopyTo(m.AsMemory());
_position = await _encoder.CodeAsync(new MemoryStream(m), false);
buffer.CopyTo(m.AsMemory().Slice(0, buffer.Length));
_position = await _encoder.CodeAsync(new MemoryStream(m, 0, buffer.Length), false);
ArrayPool<byte>.Shared.Return(m);
}
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public byte[] Properties { get; private set; }
}
}

View File

@@ -2,6 +2,8 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.Crypto
{
@@ -52,16 +54,20 @@ namespace SharpCompress.Crypto
}
#endif
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = new CancellationToken())
{
await stream.WriteAsync(buffer, cancellationToken);
hash = CalculateCrc(table, hash, buffer.Span);
}
public override void Write(byte[] buffer, int offset, int count)
{
stream.Write(buffer, offset, count);
hash = CalculateCrc(table, hash, buffer.AsSpan(offset, count));
throw new NotSupportedException();
}
public override void WriteByte(byte value)
{
stream.WriteByte(value);
hash = CalculateCrc(table, hash, value);
throw new NotSupportedException();
}
public override bool CanRead => stream.CanRead;

View File

@@ -0,0 +1,73 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.IO
{
public abstract class AsyncStream : Stream
{
protected sealed override void Dispose(bool disposing)
{
if (disposing)
{
throw new NotSupportedException();
}
}
public sealed override void Flush()
{
throw new NotSupportedException();
}
public abstract override ValueTask DisposeAsync();
public sealed override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public sealed override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public sealed override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
{
throw new NotSupportedException();
}
public sealed override int EndRead(IAsyncResult asyncResult)
{
throw new NotSupportedException();
}
public sealed override int ReadByte()
{
throw new NotSupportedException();
}
public sealed override void WriteByte(byte b)
{
throw new NotSupportedException();
}
public abstract override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);
public abstract override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default);
#if !NET461 && !NETSTANDARD2_0
public sealed override int Read(Span<byte> buffer)
{
throw new NotSupportedException();
}
public sealed override void Write(ReadOnlySpan<byte> buffer)
{
throw new NotSupportedException();
}
#endif
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.IO
{
@@ -25,16 +27,11 @@ namespace SharpCompress.IO
public override bool CanWrite => false;
public override void Flush()
{
throw new NotSupportedException();
}
public override long Length => BytesLeftToRead;
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override int Read(byte[] buffer, int offset, int count)
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (count > BytesLeftToRead)
{
@@ -47,7 +44,7 @@ namespace SharpCompress.IO
{
cacheOffset = 0;
Stream.Position = position;
cacheLength = Stream.Read(cache, 0, cache.Length);
cacheLength = await Stream.ReadAsync(cache, 0, cache.Length, cancellationToken);
position += cacheLength;
}
@@ -74,10 +71,5 @@ namespace SharpCompress.IO
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
}
}

View File

@@ -19,20 +19,15 @@ namespace SharpCompress.IO
public override bool CanWrite => true;
public override void Flush()
public override Task FlushAsync(CancellationToken cancellationToken)
{
Stream.Flush();
return Stream.FlushAsync(cancellationToken);
}
public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
@@ -54,17 +49,5 @@ namespace SharpCompress.IO
await Stream.WriteAsync(buffer, cancellationToken);
Count += (uint)buffer.Length;
}
public override void Write(byte[] buffer, int offset, int count)
{
Stream.Write(buffer, offset, count);
Count += (uint)count;
}
public override void WriteByte(byte value)
{
Stream.WriteByte(value);
++Count;
}
}
}

View File

@@ -5,7 +5,7 @@ using System.Threading.Tasks;
namespace SharpCompress.IO
{
public class NonDisposingStream : Stream
public class NonDisposingStream : AsyncStream
{
public NonDisposingStream(Stream stream, bool throwOnDispose = false)
{
@@ -22,15 +22,7 @@ namespace SharpCompress.IO
throw new InvalidOperationException($"Attempt to dispose of a {nameof(NonDisposingStream)} when {nameof(ThrowOnDispose)} is {ThrowOnDispose}");
}
return base.DisposeAsync();
}
protected override void Dispose(bool disposing)
{
if (ThrowOnDispose)
{
throw new InvalidOperationException($"Attempt to dispose of a {nameof(NonDisposingStream)} when {nameof(ThrowOnDispose)} is {ThrowOnDispose}");
}
return new ValueTask();
}
protected Stream Stream { get; }
@@ -41,35 +33,20 @@ namespace SharpCompress.IO
public override bool CanWrite => Stream.CanWrite;
public override void Flush()
public override Task FlushAsync(CancellationToken cancellationToken)
{
Stream.Flush();
return Stream.FlushAsync(cancellationToken);
}
public override long Length => Stream.Length;
public override long Position { get => Stream.Position; set => Stream.Position = value; }
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken)
{
return Stream.ReadAsync(buffer, cancellationToken);
}
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
{
throw new NotImplementedException();
}
public override int EndRead(IAsyncResult asyncResult)
{
throw new NotImplementedException();
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return Stream.ReadAsync(buffer, offset, count, cancellationToken);
@@ -85,11 +62,6 @@ namespace SharpCompress.IO
Stream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
Stream.Write(buffer, offset, count);
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return Stream.WriteAsync(buffer, offset, count, cancellationToken);
@@ -99,19 +71,5 @@ namespace SharpCompress.IO
{
return Stream.WriteAsync(buffer, cancellationToken);
}
#if !NET461 && !NETSTANDARD2_0
public override int Read(Span<byte> buffer)
{
return Stream.Read(buffer);
}
public override void Write(ReadOnlySpan<byte> buffer)
{
Stream.Write(buffer);
}
#endif
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.IO
{
@@ -28,22 +30,17 @@ namespace SharpCompress.IO
public override bool CanWrite => false;
public override void Flush()
{
throw new NotSupportedException();
}
public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override int Read(byte[] buffer, int offset, int count)
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (BytesLeftToRead < count)
{
count = (int)BytesLeftToRead;
}
int read = Stream.Read(buffer, offset, count);
int read = await Stream.ReadAsync(buffer, offset, count, cancellationToken);
if (read > 0)
{
BytesLeftToRead -= read;
@@ -51,20 +48,6 @@ namespace SharpCompress.IO
return read;
}
public override int ReadByte()
{
if (BytesLeftToRead <= 0)
{
return -1;
}
int value = Stream.ReadByte();
if (value != -1)
{
--BytesLeftToRead;
}
return value;
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
@@ -74,10 +57,5 @@ namespace SharpCompress.IO
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
}
}

View File

@@ -48,8 +48,8 @@ namespace SharpCompress.Readers
public async ValueTask DisposeAsync()
{
await (entriesForCurrentReadStream?.DisposeAsync() ?? new ValueTask(Task.CompletedTask));
Volume?.Dispose();
await (entriesForCurrentReadStream?.DisposeAsync() ?? new ValueTask());
await Volume.DisposeAsync();
}
#endregion

View File

@@ -11,6 +11,13 @@ namespace SharpCompress
{
internal static class Utility
{
public static async ValueTask ForEachAsync<T>(this IEnumerable<T> collection, Func<T, Task> action)
{
foreach (T item in collection)
{
await action(item);
}
}
public static async ValueTask<T> ReadPrimitive<T>(this Stream stream, int bytes, Func<ReadOnlyMemory<byte>, T> func, CancellationToken cancellationToken)
{
using var buffer = MemoryPool<byte>.Shared.Rent(bytes);

View File

@@ -130,7 +130,7 @@ namespace SharpCompress.Writers.Tar
} */
case LZipStream l:
{
l.Finish();
await l.FinishAsync();
break;
}
}

View File

@@ -1,4 +1,7 @@
using System.IO;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.Test.Mocks
{
@@ -22,8 +25,12 @@ namespace SharpCompress.Test.Mocks
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
stream.Dispose();
throw new NotSupportedException();
}
public override async ValueTask DisposeAsync()
{
await stream.DisposeAsync();
IsDisposed = true;
}
@@ -46,10 +53,17 @@ namespace SharpCompress.Test.Mocks
set => stream.Position = value;
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return stream.ReadAsync(buffer, offset, count, cancellationToken);
}
public override int Read(byte[] buffer, int offset, int count)
{
return stream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
@@ -65,5 +79,10 @@ namespace SharpCompress.Test.Mocks
{
stream.Write(buffer, offset, count);
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return stream.WriteAsync(buffer, offset, count, cancellationToken);
}
}
}

View File

@@ -26,11 +26,11 @@ namespace SharpCompress.Test
private async ValueTask ReadImplAsync(string testArchive, CompressionType expectedCompression, ReaderOptions options)
{
using (var file = File.OpenRead(testArchive))
await using (var file = File.OpenRead(testArchive))
{
using (var protectedStream = new NonDisposingStream(new ForwardOnlyStream(file), throwOnDispose: true))
await using (var protectedStream = new NonDisposingStream(new ForwardOnlyStream(file), throwOnDispose: true))
{
using (var testStream = new TestStream(protectedStream))
await using (var testStream = new TestStream(protectedStream))
{
await using (var reader = await ReaderFactory.OpenAsync(testStream, options))
{