#nullable disable using System; using System.Collections; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace SharpCompress; internal sealed class LazyAsyncReadOnlyCollection(IAsyncEnumerable source) : IAsyncEnumerable { private readonly List _backing = new(); private readonly IAsyncEnumerator _source = source.GetAsyncEnumerator(); private bool _fullyLoaded; private class LazyLoader( LazyAsyncReadOnlyCollection lazyReadOnlyCollection, CancellationToken cancellationToken ) : IAsyncEnumerator { private bool _disposed; private int _index = -1; public ValueTask DisposeAsync() { if (!_disposed) { _disposed = true; } return default; } public async ValueTask MoveNextAsync() { cancellationToken.ThrowIfCancellationRequested(); if (_index + 1 < lazyReadOnlyCollection._backing.Count) { _index++; return true; } if ( !lazyReadOnlyCollection._fullyLoaded && await lazyReadOnlyCollection._source.MoveNextAsync() ) { lazyReadOnlyCollection._backing.Add(lazyReadOnlyCollection._source.Current); _index++; return true; } lazyReadOnlyCollection._fullyLoaded = true; return false; } #region IEnumerator Members public T Current => lazyReadOnlyCollection._backing[_index]; #endregion #region IDisposable Members public void Dispose() { if (!_disposed) { _disposed = true; } } #endregion } internal async ValueTask EnsureFullyLoaded() { if (!_fullyLoaded) { var loader = new LazyLoader(this, CancellationToken.None); while (await loader.MoveNextAsync()) { // Intentionally empty } _fullyLoaded = true; } } internal IEnumerable GetLoaded() => _backing; #region ICollection Members public void Add(T item) => throw new NotSupportedException(); public void Clear() => throw new NotSupportedException(); public bool IsReadOnly => true; public bool Remove(T item) => throw new NotSupportedException(); #endregion public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) => new LazyLoader(this, cancellationToken); }