Skip to content

[API Proposal]: ZstandardDecompressionOptions #128456

@rzikm

Description

@rzikm

Background and motivation

The new Zstandard APIs provide a way to configure the ZstandardEncoder with ZstandardCompressionOptions, but there is no symmetric options for ZstandardDecoder. This is problematic in case user wants to configure maxWindowLog on a decompressing ZstandardStream. Currently, it is possible by passing ZstandardStream a pre-configured ZstandardDecoder:

var decoder = new ZstandardDecoder(dictionary, maxWindowLog);
var stream = new ZstandardStream(decoder);

However, in this case, ZstandardStream does not own the ZstandardDecoder instance, and caller is responsible for disposing it (or reusing it in the future). But this may be difficult for some scenarios, consider e.g. ASP.NET Core decompression middleware:

 internal sealed class ZstandardDecompressionProvider : IDecompressionProvider
{
    /// <inheritdoc />
    public Stream GetDecompressionStream(Stream stream)
    {
        var decoder = new ZstandardDecoder(dictionary, maxWindowLog);
        return new ZstandardStream(stream, decoder, leaveOpen: true);
    }
}

There is no good way to tie the decoder's lifetime to the stream, except creating another wrapper stream, or leaving it to be GC'd.

API Proposal

namespace System.IO.Compression;

public class ZstandardDecompressionOptions
{
    public ZstandardDictionary? Dictionary { get; set; }

    // Value 0 indicates the implementation-defined default window size.
    // range from ZstandardCompressionOptions.MinWindowLog - MaxWindowLog
    public int MaxWindowLog { get; set; } 
}

public partial class ZstandardDecoder
{
    // not strictly necessary, other ctors can be used
    public ZstandardDecoder(ZstandardDecompressionOptions decompressionOptions);
}

public partial class ZstandardStream
{
    // symmetric to ZstandardStream(Stream! stream, ZstandardCompressionOptions! compressionOptions, bool leaveOpen = false);
    public ZstandardStream(Stream stream, ZstandardDecompressionOptions decompressionOptions, bool leaveOpen = false);
}

API Usage

ASP.NET Core can benefit from this and allow configuring maxWindowLog in incoming request decompression:

internal sealed class ZstandardDecompressionProvider : IDecompressionProvider
{
    // configured by the app code
    public ZstandardDecompressionOptions Options { get; set; }

    /// <inheritdoc />
    public Stream GetDecompressionStream(Stream stream)
    {
        return new ZstandardStream(stream, Options, leaveOpen: true);
    }
}

This would otherwise be difficult, because ZstandardDecompressionProvider would need to pass in a configured ZstandardDecoder, and then there is question of disposing the decoder.

Alternative Designs

Allow specifying whether ZstandardStream takes over the ownership of passed in ZstandardEncoder/Decoder:

public partial class ZstandardStream
{
    public ZstandardStream(Stream stream, ZstandardEncoder encoder, bool leaveOpen = false, bool shouldDisposeEncoder);
    public ZstandardStream(Stream stream, ZstandardDecoder decoder, bool leaveOpen = false, bool shouldDisposeDecoder);
}

Risks

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-System.IO.CompressionuntriagedNew issue has not been triaged by the area owner

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions