This commit is contained in:
Adam Hathcock
2026-01-08 09:41:48 +00:00
parent 0f37cbfd0b
commit 60e5220bd0
5 changed files with 55 additions and 27 deletions

View File

@@ -25,8 +25,12 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
_sourceStream = sourceStream;
_lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(_sourceStream));
_lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
_lazyVolumesAsync = new LazyAsyncReadOnlyCollection<TVolume>(LoadVolumesAsync(_sourceStream));
_lazyEntriesAsync = new LazyAsyncReadOnlyCollection<TEntry>(LoadEntriesAsync(_lazyVolumesAsync));
_lazyVolumesAsync = new LazyAsyncReadOnlyCollection<TVolume>(
LoadVolumesAsync(_sourceStream)
);
_lazyEntriesAsync = new LazyAsyncReadOnlyCollection<TEntry>(
LoadEntriesAsync(_lazyVolumesAsync)
);
}
internal AbstractArchive(ArchiveType type)
@@ -35,8 +39,12 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
ReaderOptions = new();
_lazyVolumes = new LazyReadOnlyCollection<TVolume>(Enumerable.Empty<TVolume>());
_lazyEntries = new LazyReadOnlyCollection<TEntry>(Enumerable.Empty<TEntry>());
_lazyVolumesAsync = new LazyAsyncReadOnlyCollection<TVolume>(AsyncEnumerableEx.Empty<TVolume>());
_lazyEntriesAsync = new LazyAsyncReadOnlyCollection<TEntry>(AsyncEnumerableEx.Empty<TEntry>());
_lazyVolumesAsync = new LazyAsyncReadOnlyCollection<TVolume>(
AsyncEnumerableEx.Empty<TVolume>()
);
_lazyEntriesAsync = new LazyAsyncReadOnlyCollection<TEntry>(
AsyncEnumerableEx.Empty<TEntry>()
);
}
public ArchiveType Type { get; }
@@ -45,6 +53,7 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
/// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive.
/// </summary>
public virtual ICollection<TEntry> Entries => _lazyEntries;
/// <summary>
/// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive.
/// </summary>
@@ -65,16 +74,19 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
protected abstract IEnumerable<TVolume> LoadVolumes(SourceStream sourceStream);
protected abstract IEnumerable<TEntry> LoadEntries(IEnumerable<TVolume> volumes);
protected virtual IAsyncEnumerable<TVolume> LoadVolumesAsync(SourceStream sourceStream) =>
LoadVolumes(sourceStream).ToAsyncEnumerable();
protected virtual IAsyncEnumerable<TVolume> LoadVolumesAsync(SourceStream sourceStream) => LoadVolumes(sourceStream).ToAsyncEnumerable();
protected virtual async IAsyncEnumerable<TEntry> LoadEntriesAsync(IAsyncEnumerable<TVolume> volumes)
protected virtual async IAsyncEnumerable<TEntry> LoadEntriesAsync(
IAsyncEnumerable<TVolume> volumes
)
{
foreach (var item in LoadEntries(await volumes.ToListAsync()) )
foreach (var item in LoadEntries(await volumes.ToListAsync()))
{
yield return item;
}
}
IEnumerable<IArchiveEntry> IArchive.Entries => Entries.Cast<IArchiveEntry>();
IEnumerable<IVolume> IArchive.Volumes => _lazyVolumes.Cast<IVolume>();
@@ -149,14 +161,13 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
private readonly LazyAsyncReadOnlyCollection<TVolume> _lazyVolumesAsync;
private readonly LazyAsyncReadOnlyCollection<TEntry> _lazyEntriesAsync;
public virtual async ValueTask DisposeAsync()
{
if (!_disposed)
{
await foreach (var v in _lazyVolumesAsync)
{
v.Dispose();
v.Dispose();
}
foreach (var v in _lazyEntriesAsync.GetLoaded().Cast<Entry>())
{
@@ -175,9 +186,11 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
}
public virtual IAsyncEnumerable<TEntry> EntriesAsync => _lazyEntriesAsync;
IAsyncEnumerable<IArchiveEntry> IArchiveAsync.EntriesAsync => EntriesAsync.Cast<TEntry, IArchiveEntry>();
IAsyncEnumerable<IArchiveEntry> IArchiveAsync.EntriesAsync =>
EntriesAsync.Cast<TEntry, IArchiveEntry>();
public IAsyncEnumerable<IVolume> VolumesAsync => _lazyVolumesAsync.Cast<TVolume, IVolume>();
public async ValueTask<IReader> ExtractAllEntriesAsync()
{
if (!IsSolid && Type != ArchiveType.SevenZip)
@@ -190,11 +203,10 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
return await CreateReaderForSolidExtractionAsync();
}
protected virtual ValueTask<IReader> CreateReaderForSolidExtractionAsync() =>
new (CreateReaderForSolidExtraction());
new(CreateReaderForSolidExtraction());
public virtual ValueTask<bool> IsSolidAsync() => new (false);
public virtual ValueTask<bool> IsSolidAsync() => new(false);
public async ValueTask<bool> IsCompleteAsync()
{
@@ -202,9 +214,11 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
return await EntriesAsync.All(x => x.IsComplete);
}
public async ValueTask<long> TotalSizeAsync() => await EntriesAsync.Aggregate(0L, (total, cf) => total + cf.CompressedSize);
public async ValueTask<long> TotalSizeAsync() =>
await EntriesAsync.Aggregate(0L, (total, cf) => total + cf.CompressedSize);
public async ValueTask<long> TotalUncompressSizeAsync() => await EntriesAsync.Aggregate(0L, (total, cf) => total + cf.Size);
public async ValueTask<long> TotalUncompressSizeAsync() =>
await EntriesAsync.Aggregate(0L, (total, cf) => total + cf.Size);
#endregion
}

View File

@@ -42,7 +42,6 @@ public interface IArchiveAsync : IAsyncDisposable
ValueTask<long> TotalUncompressSizeAsync();
}
public interface IArchive : IDisposable
{
IEnumerable<IArchiveEntry> Entries { get; }

View File

@@ -7,13 +7,17 @@ using System.Threading.Tasks;
namespace SharpCompress;
internal sealed class LazyAsyncReadOnlyCollection<T>(IAsyncEnumerable<T> source) : IAsyncEnumerable<T>
internal sealed class LazyAsyncReadOnlyCollection<T>(IAsyncEnumerable<T> source)
: IAsyncEnumerable<T>
{
private readonly List<T> backing = new();
private readonly IAsyncEnumerator<T> source = source.GetAsyncEnumerator();
private bool fullyLoaded;
private class LazyLoader(LazyAsyncReadOnlyCollection<T> lazyReadOnlyCollection, CancellationToken cancellationToken) : IAsyncEnumerator<T>
private class LazyLoader(
LazyAsyncReadOnlyCollection<T> lazyReadOnlyCollection,
CancellationToken cancellationToken
) : IAsyncEnumerator<T>
{
private bool disposed;
private int index = -1;
@@ -35,7 +39,10 @@ internal sealed class LazyAsyncReadOnlyCollection<T>(IAsyncEnumerable<T> source)
index++;
return true;
}
if (!lazyReadOnlyCollection.fullyLoaded && await lazyReadOnlyCollection.source.MoveNextAsync())
if (
!lazyReadOnlyCollection.fullyLoaded
&& await lazyReadOnlyCollection.source.MoveNextAsync()
)
{
lazyReadOnlyCollection.backing.Add(lazyReadOnlyCollection.source.Current);
index++;
@@ -62,7 +69,6 @@ internal sealed class LazyAsyncReadOnlyCollection<T>(IAsyncEnumerable<T> source)
}
#endregion
}
internal async ValueTask EnsureFullyLoaded()
@@ -92,5 +98,6 @@ internal sealed class LazyAsyncReadOnlyCollection<T>(IAsyncEnumerable<T> source)
#endregion
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) => new LazyLoader(this, cancellationToken);
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) =>
new LazyLoader(this, cancellationToken);
}

View File

@@ -10,8 +10,8 @@ public static class AsyncEnumerableEx
public static async IAsyncEnumerable<T> Empty<T>()
where T : notnull
{
await Task.CompletedTask;
yield break;
await Task.CompletedTask;
yield break;
}
}
@@ -41,6 +41,7 @@ public static class AsyncEnumerableExtensions
}
return list;
}
public async IAsyncEnumerable<TResult> Cast<TResult>()
where TResult : class
{
@@ -49,6 +50,7 @@ public static class AsyncEnumerableExtensions
yield return (item as TResult).NotNull();
}
}
public async ValueTask<bool> All(Func<T, bool> predicate)
{
await foreach (var item in source)
@@ -61,6 +63,7 @@ public static class AsyncEnumerableExtensions
return true;
}
public async IAsyncEnumerable<T> Where(Func<T, bool> predicate)
{
await foreach (var item in source)
@@ -82,10 +85,13 @@ public static class AsyncEnumerableExtensions
return default; // Returns null/default if the stream is empty
}
public async ValueTask<TAccumulate> Aggregate<TAccumulate>(TAccumulate seed, Func<TAccumulate, T, TAccumulate> func)
public async ValueTask<TAccumulate> Aggregate<TAccumulate>(
TAccumulate seed,
Func<TAccumulate, T, TAccumulate> func
)
{
TAccumulate result = seed;
await foreach (var element in source)
await foreach (var element in source)
{
result = func(result, element);
}

View File

@@ -609,7 +609,9 @@ public class ArchiveTests : ReaderTests
{
try
{
await foreach (var entry in archive.EntriesAsync.Where(entry => !entry.IsDirectory))
await foreach (
var entry in archive.EntriesAsync.Where(entry => !entry.IsDirectory)
)
{
await entry.WriteToDirectoryAsync(
SCRATCH_FILES_PATH,