Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API Proposal]: ZLibPipeReader #61502

Closed
wegylexy opened this issue Nov 12, 2021 · 3 comments
Closed

[API Proposal]: ZLibPipeReader #61502

wegylexy opened this issue Nov 12, 2021 · 3 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.IO.Pipelines untriaged New issue has not been triaged by the area owner

Comments

@wegylexy
Copy link
Contributor

Background and motivation

Existing ZLibStream often consumes more bytes than it needs and discards the residue. A hack into its private fields is required to scavenge the unprocessed bytes.

See #61405

Proposed ZLibPipeReader only advances the underlying pipe reader to the end of the zlib stream.

API Proposal

namespace System.IO.Compression
{
    public class ZLibPipeReader : System.IO.Pipelines.PipeReader
    {
        public static ZLibPipeReader Create(System.IO.Pipelines.PipeReader basePipeReader);

        private ZLibPipeReader(System.IO.Pipelines.PipeReader basePipeReader);
    }
}

API Usage

var baseReader = PipeReader.Create(myGitPackStream, new(bufferSize: 16384));
var entries = await MyGitPackGetEntryCount(baseReader);
while (entries-- > 0)
{
    var (type, uncompressedSize) = await MyGitPackGetHeaderAsync(baseReader, cancellationToken);
    ZLibPipeReader inflateReader = new(baseReader);
    var result = inflateReader.ReadAtLeastAsync(uncompressedSize, cancellationToken);
}

Alternative Designs

namespace System.IO.Compression
{
    public class ZLibStream : Stream
    {
+        public ReadOnlyMemory<byte> Residue { get; }
    }
}

namespace System.IO
{
+    public class StackStream : Stream
+    {
+        public StackStream(Stream baseStream, bool leaveOpen = false);
+        public void Push(ReadOnlyMemory<byte> prolog);
+    }
}
MyStackStream stackStream = new(myGitPackStream);
var entries = await MyGitPackGetEntryCount(stackStream);
while (entries-- > 0)
{
    var (type, uncompressedSize) = await MyGitPackGetHeaderAsync(stackStream, cancellationToken);
    var buffer = GC.AllocateUninitializedArray<byte>((int)uncompressedSize).AsMemory();
    using ZLibStream inflateStream = new(stackStream, CompressionMode.Decompress, true);
    for (var read = 0; read < uncompressedSize; read += await inflateStream.ReadAsync(buffer[read..], cancellationToken) { }
    stackStream.Push(inflateStream.Residue);
}

Risks

No response

@wegylexy wegylexy added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Nov 12, 2021
@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.IO.Pipelines untriaged New issue has not been triaged by the area owner labels Nov 12, 2021
@stephentoub
Copy link
Member

We don't have any plans to duplicate this functionality as pipereaders/writers.

We are open to the idea of creating lower-level encoder/decoder APIs, as was done with BrotliEncoder/Decoder, which can then be used by a reader/writer on top, just as BrotliStream is just a thin wrapper around those.
e.g. #39327

@wegylexy
Copy link
Contributor Author

Ya, ZLipEncoder/Decoder will do.

@adityamandaleeka
Copy link
Member

Looks like this has been answered. Please reopen if needed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.IO.Pipelines untriaged New issue has not been triaged by the area owner
Projects
None yet
Development

No branches or pull requests

3 participants