Skip to content

Commit

Permalink
Merge pull request #242 from Nullus157/brotli-params
Browse files Browse the repository at this point in the history
Brotli encoder params
  • Loading branch information
robjtede authored Aug 29, 2023
2 parents 8af8b96 + b698b1a commit 29a411b
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 122 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0),

## Unreleased

- Add top-level `brotli` module containing stable `brotli` crate wrapper types.
- Add `BrotliEncoder::with_quality_and_params()` constructors.
- Add `Deflate64Decoder` behind new crate feature `deflate64`.

## 0.4.1 - 2023-07-10
Expand All @@ -16,7 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0),
## 0.4.0 - 2023-05-10

- `Level::Precise` variant now takes a `i32` instead of `u32`.
- Add top level `zstd` module containing stable `zstd` crate wrapper types.
- Add top-level `zstd` module containing stable `zstd` crate wrapper types.
- Add `ZstdEncoder::with_quality_and_params()` constructors.
- Update `zstd` dependency to `0.12`.
- Remove deprecated `stream`, `futures-bufread` and `futures-write` crate features.
Expand Down
66 changes: 66 additions & 0 deletions src/brotli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//! This module contains Brotli-specific types for async-compression.

use brotli::enc::backward_references::{BrotliEncoderMode, BrotliEncoderParams};

/// A compression parameter for Brotli. This is a stable wrapper around Brotli's own encoder params
/// type, to abstract over different versions of the Brotli library.
///
/// See the [Brotli documentation](https://www.brotli.org/encode.html#a9a8) for more information on
/// these parameters.

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EncoderParams {
window_size: i32,
block_size: i32,
size_hint: usize,
mode: BrotliEncoderMode,
}

impl EncoderParams {
/// Sets window size in bytes (as a power of two).
///
/// Used as Brotli's `lgwin` parameter.
///
/// `window_size` is clamped to `0 <= window_size <= 24`.
pub fn window_size(mut self, window_size: i32) -> Self {
self.window_size = window_size.clamp(0, 24);
self
}

/// Sets input block size in bytes (as a power of two).
///
/// Used as Brotli's `lgblock` parameter.
///
/// `block_size` is clamped to `16 <= block_size <= 24`.
pub fn block_size(mut self, block_size: i32) -> Self {
self.block_size = block_size.clamp(16, 24);
self
}

/// Sets hint for size of data to be compressed.
pub fn size_hint(mut self, size_hint: usize) -> Self {
self.size_hint = size_hint;
self
}

/// Sets encoder to text mode.
///
/// If input data is known to be UTF-8 text, this allows the compressor to make assumptions and
/// optimizations.
///
/// Used as Brotli's `mode` parameter.
pub fn text_mode(mut self) -> Self {
self.mode = BrotliEncoderMode::BROTLI_MODE_TEXT;
self
}

pub(crate) fn as_brotli(&self) -> BrotliEncoderParams {
BrotliEncoderParams {
lgwin: self.window_size,
lgblock: self.block_size,
size_hint: self.size_hint,
mode: self.mode,
..Default::default()
}
}
}
134 changes: 13 additions & 121 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,28 +154,35 @@ mod unshared;
mod util;

#[cfg(feature = "brotli")]
use brotli::enc::backward_references::BrotliEncoderParams;
pub mod brotli;
#[cfg(feature = "zstd")]
pub mod zstd;

/// Level of compression data should be compressed with.
#[non_exhaustive]
#[derive(Clone, Copy, Debug)]
pub enum Level {
/// Fastest quality of compression, usually produces bigger size.
Fastest,

/// Best quality of compression, usually produces the smallest size.
Best,

/// Default quality of compression defined by the selected compression algorithm.
Default,
/// Precise quality based on the underlying compression algorithms'
/// qualities. The interpretation of this depends on the algorithm chosen
/// and the specific implementation backing it.
/// Qualities are implicitly clamped to the algorithm's maximum.

/// Precise quality based on the underlying compression algorithms' qualities. The
/// interpretation of this depends on the algorithm chosen and the specific implementation
/// backing it. Qualities are implicitly clamped to the algorithm's maximum.
Precise(i32),
}

impl Level {
#[cfg(feature = "brotli")]
fn into_brotli(self, mut params: BrotliEncoderParams) -> BrotliEncoderParams {
fn into_brotli(
self,
mut params: ::brotli::enc::backward_references::BrotliEncoderParams,
) -> ::brotli::enc::backward_references::BrotliEncoderParams {
match self {
Self::Fastest => params.quality = 0,
Self::Best => params.quality = 11,
Expand Down Expand Up @@ -243,118 +250,3 @@ impl Level {
}
}
}

#[cfg(feature = "zstd")]
/// This module contains zstd-specific types for async-compression.
pub mod zstd {
use libzstd::stream::raw::CParameter::*;

/// A compression parameter for zstd. This is a stable wrapper around zstd's own `CParameter`
/// type, to abstract over different versions of the zstd library.
///
/// See the [zstd documentation](https://facebook.github.io/zstd/zstd_manual.html) for more
/// information on these parameters.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CParameter(libzstd::stream::raw::CParameter);

impl CParameter {
/// Window size in bytes (as a power of two)
pub fn window_log(value: u32) -> Self {
Self(WindowLog(value))
}

/// Size of the initial probe table in 4-byte entries (as a power of two)
pub fn hash_log(value: u32) -> Self {
Self(HashLog(value))
}

/// Size of the multi-probe table in 4-byte entries (as a power of two)
pub fn chain_log(value: u32) -> Self {
Self(ChainLog(value))
}

/// Number of search attempts (as a power of two)
pub fn search_log(value: u32) -> Self {
Self(SearchLog(value))
}

/// Minimum size of matches searched for
pub fn min_match(value: u32) -> Self {
Self(MinMatch(value))
}

/// Strategy-dependent length modifier
pub fn target_length(value: u32) -> Self {
Self(TargetLength(value))
}

/// Enable long-distance matching mode to look for and emit long-distance references.
///
/// This increases the default window size.
pub fn enable_long_distance_matching(value: bool) -> Self {
Self(EnableLongDistanceMatching(value))
}

/// Size of the long-distance matching table (as a power of two)
pub fn ldm_hash_log(value: u32) -> Self {
Self(LdmHashLog(value))
}

/// Minimum size of long-distance matches searched for
pub fn ldm_min_match(value: u32) -> Self {
Self(LdmMinMatch(value))
}

/// Size of each bucket in the LDM hash table for collision resolution (as a power of two)
pub fn ldm_bucket_size_log(value: u32) -> Self {
Self(LdmBucketSizeLog(value))
}

/// Frequency of using the LDM hash table (as a power of two)
pub fn ldm_hash_rate_log(value: u32) -> Self {
Self(LdmHashRateLog(value))
}

/// Emit the size of the content (default: true).
pub fn content_size_flag(value: bool) -> Self {
Self(ContentSizeFlag(value))
}

/// Emit a checksum (default: false).
pub fn checksum_flag(value: bool) -> Self {
Self(ChecksumFlag(value))
}

/// Emit a dictionary ID when using a custom dictionary (default: true).
pub fn dict_id_flag(value: bool) -> Self {
Self(DictIdFlag(value))
}

/// Number of threads to spawn.
///
/// If set to 0, compression functions will block; if set to 1 or more, compression will
/// run in background threads and `flush` pushes bytes through the compressor.
///
/// # Panics
///
/// This parameter requires feature `zstdmt` to be enabled, otherwise it will cause a panic
/// when used in `ZstdEncoder::with_quality_and_params()` calls.
//
// TODO: make this a normal feature guarded fn on next breaking release
#[cfg_attr(docsrs, doc(cfg(feature = "zstdmt")))]
pub fn nb_workers(value: u32) -> Self {
Self(NbWorkers(value))
}

/// Number of bytes given to each worker.
///
/// If set to 0, zstd selects a job size based on compression parameters.
pub fn job_size(value: u32) -> Self {
Self(JobSize(value))
}

pub(crate) fn as_zstd(&self) -> libzstd::stream::raw::CParameter {
self.0
}
}
}
18 changes: 18 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,31 @@ macro_rules! algos {
{ @enc
pub fn with_quality(inner: $inner, level: crate::Level) -> Self {
let params = brotli::enc::backward_references::BrotliEncoderParams::default();

Self {
inner: crate::$($mod::)+generic::Encoder::new(
inner,
crate::codec::BrotliEncoder::new(level.into_brotli(params)),
),
}
}

/// Creates a new encoder, using the specified compression level and parameters, which
/// will read uncompressed data from the given stream and emit a compressed stream.
pub fn with_quality_and_params(
inner: $inner,
level: crate::Level,
params: crate::brotli::EncoderParams,
) -> Self {
let params = level.into_brotli(params.as_brotli());

Self {
inner: crate::$($mod::)+generic::Encoder::new(
inner,
crate::codec::BrotliEncoder::new(params),
),
}
}
}
{ @dec }
);
Expand Down
112 changes: 112 additions & 0 deletions src/zstd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//! This module contains zstd-specific types for async-compression.

use libzstd::stream::raw::CParameter::*;

/// A compression parameter for zstd. This is a stable wrapper around zstd's own `CParameter`
/// type, to abstract over different versions of the zstd library.
///
/// See the [zstd documentation](https://facebook.github.io/zstd/zstd_manual.html) for more
/// information on these parameters.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CParameter(libzstd::stream::raw::CParameter);

impl CParameter {
/// Window size in bytes (as a power of two)
pub fn window_log(value: u32) -> Self {
Self(WindowLog(value))
}

/// Size of the initial probe table in 4-byte entries (as a power of two)
pub fn hash_log(value: u32) -> Self {
Self(HashLog(value))
}

/// Size of the multi-probe table in 4-byte entries (as a power of two)
pub fn chain_log(value: u32) -> Self {
Self(ChainLog(value))
}

/// Number of search attempts (as a power of two)
pub fn search_log(value: u32) -> Self {
Self(SearchLog(value))
}

/// Minimum size of matches searched for
pub fn min_match(value: u32) -> Self {
Self(MinMatch(value))
}

/// Strategy-dependent length modifier
pub fn target_length(value: u32) -> Self {
Self(TargetLength(value))
}

/// Enable long-distance matching mode to look for and emit long-distance references.
///
/// This increases the default window size.
pub fn enable_long_distance_matching(value: bool) -> Self {
Self(EnableLongDistanceMatching(value))
}

/// Size of the long-distance matching table (as a power of two)
pub fn ldm_hash_log(value: u32) -> Self {
Self(LdmHashLog(value))
}

/// Minimum size of long-distance matches searched for
pub fn ldm_min_match(value: u32) -> Self {
Self(LdmMinMatch(value))
}

/// Size of each bucket in the LDM hash table for collision resolution (as a power of two)
pub fn ldm_bucket_size_log(value: u32) -> Self {
Self(LdmBucketSizeLog(value))
}

/// Frequency of using the LDM hash table (as a power of two)
pub fn ldm_hash_rate_log(value: u32) -> Self {
Self(LdmHashRateLog(value))
}

/// Emit the size of the content (default: true).
pub fn content_size_flag(value: bool) -> Self {
Self(ContentSizeFlag(value))
}

/// Emit a checksum (default: false).
pub fn checksum_flag(value: bool) -> Self {
Self(ChecksumFlag(value))
}

/// Emit a dictionary ID when using a custom dictionary (default: true).
pub fn dict_id_flag(value: bool) -> Self {
Self(DictIdFlag(value))
}

/// Number of threads to spawn.
///
/// If set to 0, compression functions will block; if set to 1 or more, compression will
/// run in background threads and `flush` pushes bytes through the compressor.
///
/// # Panics
///
/// This parameter requires feature `zstdmt` to be enabled, otherwise it will cause a panic
/// when used in `ZstdEncoder::with_quality_and_params()` calls.
//
// TODO: make this a normal feature guarded fn on next breaking release
#[cfg_attr(docsrs, doc(cfg(feature = "zstdmt")))]
pub fn nb_workers(value: u32) -> Self {
Self(NbWorkers(value))
}

/// Number of bytes given to each worker.
///
/// If set to 0, zstd selects a job size based on compression parameters.
pub fn job_size(value: u32) -> Self {
Self(JobSize(value))
}

pub(crate) fn as_zstd(&self) -> libzstd::stream::raw::CParameter {
self.0
}
}

0 comments on commit 29a411b

Please sign in to comment.