Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
f61d816
feat(compressors): add streaming compression crate
martintmk Sep 1, 2026
7f14112
fix(compressors): preserve binary gzip fixtures
martintmk Sep 1, 2026
a9fd437
docs(compressors): align imported documentation
martintmk Sep 1, 2026
eb8c99e
test(compressors): reach 100% coverage and fix all surviving mutants
martintmk Sep 2, 2026
f3b97c2
refactor(compressors): share builders, traits and resources across fo…
martintmk Sep 2, 2026
5b47776
refactor(compressors): fold flush into Compression and drop the split…
martintmk Sep 2, 2026
8bc7326
refactor(compressors): make compress and decompress crate-level funct…
martintmk Sep 2, 2026
9fdd4c6
refactor(compressors): lift Format to the crate root
martintmk Sep 2, 2026
d06079a
refactor(compressors): drop the per-format builder aliases
martintmk Sep 2, 2026
ec3e895
refactor(compressors): rename DecompressionLimits to DecompressorLimits
martintmk Sep 2, 2026
007dcc1
refactor(compressors): move Output into core
martintmk Sep 2, 2026
db3e585
docs(compressors): hide the Compression methods as an internal detail
martintmk Sep 2, 2026
b5742b3
feat(compressors)!: enable no format by default
martintmk Sep 2, 2026
747792f
docs(compressors): lead with the high-level API and trim Security
martintmk Sep 2, 2026
04a90de
fix(compressors): satisfy the nightly formatter and close the coverag…
martintmk Sep 2, 2026
17f82b1
review(compressors): use the tick crate for the example's timer
martintmk Sep 2, 2026
3162647
docs(compressors): regenerate the README after the doc-comment reformat
martintmk Sep 2, 2026
821ad48
fix(compressors): stop dropping pooled engines inside Drop
martintmk Sep 2, 2026
b1a8dc1
ci(compressors): exclude the crate from the Miri check
martintmk Sep 2, 2026
05ec5ee
fix(compressors)!: bound the buffering conveniences and tighten codec…
martintmk Sep 2, 2026
82ec1fd
ci: exclude compressors from the extended-analysis Miri step
martintmk Sep 2, 2026
f20f008
review(compressors): drop the unused CompressionStream::into_parts API
martintmk Sep 3, 2026
ee50634
review(compressors): lead the crate docs with bytesbuf, pooling and t…
martintmk Sep 3, 2026
d549ff3
review(compressors): move the driving methods to a sealed Compression…
martintmk Sep 3, 2026
1ea798e
review(compressors): hide CompressionInternal behind a pub(crate) module
martintmk Sep 3, 2026
0cd5109
review(compressors): implement recoverable::Recovery on Error
martintmk Sep 3, 2026
e807273
review(compressors): keep Output out of the public API
martintmk Sep 3, 2026
d6432c7
test(compressors): assert the wrapped cause renders, restoring 100% c…
martintmk Sep 3, 2026
15a94b7
style(compressors): apply nightly rustfmt to the reviewed changes
martintmk Sep 3, 2026
a3bb149
test(compressors): tighten the drain-loop step cap so spinning mutant…
martintmk Sep 3, 2026
000a210
review(compressors): fix duplicated cfg gates and misleading builder …
martintmk Sep 3, 2026
69a6eb3
fix(compressors): clamp the zstd output fill mark and exclude test mo…
martintmk Sep 3, 2026
4a9f6fa
Merge branch 'main' into user/martintomka/20260901-add-compressors-crate
martintmk Sep 3, 2026
608a135
fix(compressors): end the stream when a codec asks for input after en…
martintmk Sep 3, 2026
67be047
merge: integrate the updated PR branch head
martintmk Sep 3, 2026
e9a9763
fix(compressors): gate gzip doctests, correct recovery and brotli qua…
martintmk Sep 3, 2026
9c68a71
feat(compressors)!: give the format module the shape every other form…
martintmk Sep 3, 2026
a81a13a
fix(compressors): unbreak the docs job and address the review's high-…
martintmk Sep 3, 2026
52eb54f
fix(compressors)!: reject trailing data after a single stream by default
martintmk Sep 3, 2026
7666761
chore(compressors): address the review's manifest, workflow and index…
martintmk Sep 3, 2026
fd3dc6a
perf(compressors): pool zstd contexts by nothing and reserve output l…
martintmk Sep 3, 2026
35df0d1
docs(compressors): tighten the benchmark documentation and methodology
martintmk Sep 3, 2026
1a62813
docs(compressors): enable docs.rs feature badges and correct several …
martintmk Sep 3, 2026
4ce506d
fix(compressors): decode brotli in strict RFC 7932 mode
martintmk Sep 3, 2026
59af4e2
review: tighten format test step cap to 10,000
martintmk Sep 3, 2026
befe349
perf: inline non-generic exported constructors and conversions
martintmk Sep 3, 2026
5547bbd
perf: inline the remaining non-generic forwarding wrappers
martintmk Sep 3, 2026
22fb419
docs: settle on "engine" as the single term and simplify pool docs
martintmk Sep 3, 2026
c358339
docs(compressors): thread one Resources through the round-trip example
martintmk Sep 3, 2026
5a10200
test(compressors): correct the false SAFETY note on the Overreports f…
martintmk Sep 3, 2026
0683502
docs(compressors): frame cold error paths as external-contract defence
martintmk Sep 3, 2026
ffaee88
docs(compressors): tie the decompression output cap to retained output
martintmk Sep 3, 2026
136a6ed
docs(compressors): keep zstd guidance to what the crate can support
martintmk Sep 3, 2026
e764d8a
refactor(compressors): gate optional code on test-or-feature, add tes…
martintmk Sep 3, 2026
e58d58c
feat(compressors)!: seal Compression against trait objects
martintmk Sep 3, 2026
404fa63
refactor(compressors)!: drop the with_ prefix from DecompressorLimits…
martintmk Sep 3, 2026
e773c26
refactor(compressors)!: rename enable_pooling to with_pool_capacity
martintmk Sep 3, 2026
448e68a
refactor(compressors)!: make brotli compressor construction infallible
martintmk Sep 3, 2026
83d4a96
docs(compressors): add design and implementation guides
martintmk Sep 3, 2026
b874272
test(compressors): catch the surviving runtime-format mutants
martintmk Sep 3, 2026
b8a1199
docs(compressors): describe what each backend adapter owns
martintmk Sep 3, 2026
6b3cf88
docs(compressors)!: remove the crate-wide broken-link suppression
martintmk Sep 3, 2026
a3f1881
perf(compressors): drive the tokio example's clock in simulated time
martintmk Sep 3, 2026
3eb7395
test(compressors): bound the stream test drivers
martintmk Sep 4, 2026
88eac68
merge: integrate origin/main into PR branch
martintmk Sep 4, 2026
d1f53d7
docs(compressors): upper-case the guide filenames
martintmk Sep 4, 2026
6eec2f4
feat(compressors)!: implement ThreadAware for Resources
martintmk Sep 4, 2026
5e07a3a
test(compressors): mutation-test the stream polling state machine
martintmk Sep 4, 2026
2dc3e32
fix(compressors): restore the unconditional Level export
martintmk Sep 4, 2026
7272c33
fix(compressors): stop the whole-buffer compress from panicking
martintmk Sep 4, 2026
7f82364
docs(compressors): correct claims the recent API changes invalidated
martintmk Sep 4, 2026
bfb37bf
test(compressors): actually exercise the caller's memory provider
martintmk Sep 4, 2026
0939fdf
docs(compressors): stop presenting sealed mechanics as a consumption …
martintmk Sep 4, 2026
1902f63
docs(compressors): record the reasoning behind the zstd policy numbers
martintmk Sep 4, 2026
bcfb1e3
test(compressors): say what the cross-format suite actually checks
martintmk Sep 4, 2026
a9c07e9
docs(compressors): describe the test modules as the white-box tests t…
martintmk Sep 4, 2026
4cc3980
docs(compressors): limit the error predicates to what they establish
martintmk Sep 4, 2026
fcf4f3d
test(compressors): make the fixtures and the zstd window limit carry …
martintmk Sep 4, 2026
2c620be
docs(compressors): keep benchmark observations out of the public cont…
martintmk Sep 4, 2026
68f7818
docs(compressors): record how the tuning defaults were chosen
martintmk Sep 4, 2026
0e8683f
style(compressors): use unwrap in test code per AGENTS.md
martintmk Sep 4, 2026
0bd63d2
Merge branch 'main' into user/martintomka/20260901-add-compressors-crate
martintmk Sep 4, 2026
e698431
fix(compressors): hard-fail an out-of-range zstd fill count
martintmk Sep 4, 2026
5e15c7c
merge: integrate the branch's remote main merge
martintmk Sep 4, 2026
605bc2a
feat(compressors)!: default the crate-level decompress to a 64 MiB ce…
martintmk Sep 4, 2026
0128081
refactor(compressors): move the buffering output ceiling into the engine
martintmk Sep 4, 2026
0da1dcb
fix(compressors): repair the no-format build and cut test allocations
martintmk Sep 4, 2026
8089cfc
merge: integrate origin/main into PR branch (auto-resolved .spelling …
martintmk Sep 4, 2026
92d2aa5
test(compressors): exclude the Codec::remaining_output default from m…
martintmk Sep 4, 2026
4dfc067
fix(compressors): restore the buffered stream cap alongside the outpu…
martintmk Sep 7, 2026
396b486
docs(compressors): add a security model guide and a documentation module
martintmk Sep 7, 2026
c08c954
test(compressors): add a bounded Bolero campaign over the decompressi…
martintmk Sep 7, 2026
d14a50b
test(compressors): make pooling tests control the exact engine they v…
martintmk Sep 7, 2026
b2cafe1
test(compressors): name the reuse tests for the property they assert
martintmk Sep 7, 2026
f86242b
Merge branch 'main' into user/martintomka/20260901-add-compressors-crate
martintmk Sep 7, 2026
f2034b2
test(compressors): cover no-feature encoding rejection
martintmk Sep 7, 2026
276fee0
Merge branch 'main' into user/martintomka/20260901-add-compressors-crate
martintmk Sep 7, 2026
81b8fa9
merge: integrate origin/main into compressors PR
martintmk Sep 10, 2026
b57627c
fix: sort merged workspace dependencies
martintmk Sep 10, 2026
3371aed
refactor(compressors): adopt metabench and simplify limit setters
martintmk Sep 10, 2026
1c56ee2
merge: integrate latest origin/main into compressors PR
martintmk Sep 10, 2026
fa5ef10
test(compressors): skip timeout-only zstd mutants
martintmk Sep 10, 2026
c158624
fix(compressors): make limit setters value-only
martintmk Sep 10, 2026
4601eae
test(compressors): cover exact ratio boundary
martintmk Sep 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,10 @@ jobs:
run: cargo +${{ env.RUST_NIGHTLY }} careful nextest run --all-features --workspace ${{ needs.delta.outputs.exclude_not_affected }} --color always --target ${{ matrix.target }} --no-tests=pass
- name: Miri (stacked borrows)
if: success() || failure()
# Most excluded crates generate code rather than run it, so Miri has no
# aliasing or provenance violations to find in them:
# Excluded crates fall into two groups.
#
# Crates in the first group generate code rather than run it, so Miri has
# no aliasing or provenance violations to find in them:
#
# * the `*_macros_impl` crates are proc-macro implementations whose
# tests are snapshot comparisons of generated token streams;
Expand All @@ -408,11 +410,24 @@ jobs:
# Interpreting them anyway cost ~75 min of the ~3h16m step
# (`multitude_macros_impl` alone ran 30 tests in 45 min).
#
# The second group is `compressors`, whose backends Miri cannot all run:
# `zstd-safe` binds the native zstd library and Miri cannot call foreign
# functions, while `flate2`'s `zlib-rs` backend trips Stacked Borrows
# whenever a deflate or inflate stream is dropped
# (https://github.com/trifectatechfoundation/zlib-rs/issues/491). Brotli
# is pure Rust and would run; excluding the whole crate rather than
# maintaining a brotli-only Miri configuration is a separate decision,
# taken because gating every other format's tests on `cfg(miri)` costs
# more than the remaining coverage is worth. The crate also carries
# `package.metadata.anvil.miri.exclude`, which is what the `anvil-miri`
# recipe honours; this job builds its own command line, so it needs the
# exclusion spelled out here too.
#
# Note `rest_over_grpc` is deliberately NOT excluded: its build half is
# already `#[cfg_attr(miri, ignore)]`, and the tests that do run cover the
# runtime transcoding path over `bytes`/`hyper`, which is exactly the kind
# of buffer handling Miri needs to check.
run: cargo +${{ env.RUST_NIGHTLY }} miri test --all-features --workspace ${{ needs.delta.outputs.exclude_not_affected }} --exclude data_privacy_macros_impl --exclude fundle_macros_impl --exclude internity_macros_impl --exclude metabench --exclude metabench_macros_impl --exclude multitude_macros_impl --exclude observed_macros_impl --exclude ohno_macros_impl --exclude routerama_build --exclude templated_uri_macros_impl --exclude thread_aware_macros_impl --lib --tests
run: cargo +${{ env.RUST_NIGHTLY }} miri test --all-features --workspace ${{ needs.delta.outputs.exclude_not_affected }} --exclude compressors --exclude data_privacy_macros_impl --exclude fundle_macros_impl --exclude internity_macros_impl --exclude metabench --exclude metabench_macros_impl --exclude multitude_macros_impl --exclude observed_macros_impl --exclude ohno_macros_impl --exclude routerama_build --exclude templated_uri_macros_impl --exclude thread_aware_macros_impl --lib --tests

model-checking:
if: (github.event_name == 'pull_request' || github.event_name == 'merge_group') && needs.delta.outputs.skip != 'true'
Expand Down
21 changes: 21 additions & 0 deletions .spelling
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,21 @@ userland
WebIO
WebSocket
wiremock
Zlib
Zstandard
Zstd's
brotli
brotli's
checksum
codec's
decompressor
decompressors
flate2
PNG
resumable
selectable
semver
WOFF
reentrantly
rebalancing
unsizing
Expand Down Expand Up @@ -867,7 +882,13 @@ hardcoding
Idempotence
symlinks
junctions
zlib
zstd's
unkeyed
incompressible
decompressor's
recurse
flate's
Cancelling
TUI
mutex's
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Please see each crate's change log below:
- [`cachet_memory`](./crates/cachet_memory/CHANGELOG.md)
- [`cachet_service`](./crates/cachet_service/CHANGELOG.md)
- [`cachet_tier`](./crates/cachet_tier/CHANGELOG.md)
- [`compressors`](./crates/compressors/CHANGELOG.md)
- [`data_privacy`](./crates/data_privacy/CHANGELOG.md)
- [`data_privacy_macros`](./crates/data_privacy_macros/CHANGELOG.md)
- [`data_privacy_macros_impl`](./crates/data_privacy_macros_impl/CHANGELOG.md)
Expand Down
93 changes: 93 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ azure_storage_blob = { version = "1.0.0", default-features = false }
backtrace = { version = "0.3.76", default-features = false }
base64 = { version = "0.23.0", default-features = false, features = ["alloc"] }
bolero = { version = "0.13.4", default-features = false }
brotli = { version = "8.0.4", default-features = false }
bumpalo = { version = "3.20.2", default-features = false }
bytemuck = { version = "1.25.0", default-features = false }
bytes = { version = "1.11.1", default-features = false }
Expand All @@ -89,12 +90,14 @@ cachet_memory = { path = "crates/cachet_memory", default-features = false, versi
cachet_service = { path = "crates/cachet_service", default-features = false, version = "0.5.0" }
cachet_tier = { path = "crates/cachet_tier", default-features = false, version = "0.5.0" }
cc = { version = "1.2", default-features = false }
cfg_aliases = { version = "0.2.2", default-features = false }
chrono = { version = "0.4.40", default-features = false }
chrono-tz = { version = "0.10.4", default-features = false }
chumsky = { version = "0.13.0", default-features = false }
clap = { version = "4.6.4", default-features = false }
# The latest command-group release still uses nix 0.27 on Unix; accept the duplicate until upstream updates.
command-group = { version = "5.0.1", default-features = false }
compressors = { path = "crates/compressors", default-features = false, version = "0.1.0" }
const-hex = { version = "1.15.0", default-features = false }
criterion = { version = "0.8.2", default-features = false }
crossterm = { version = "0.29.0", default-features = false }
Expand All @@ -118,6 +121,7 @@ fetch_options = { path = "crates/fetch_options", default-features = false, versi
fetch_tls = { path = "crates/fetch_tls", default-features = false, version = "0.4.0" }
fetch_winhttp = { path = "crates/fetch_winhttp", default-features = false, version = "0.1.1" }
fetch_winhttp_impl = { path = "crates/fetch_winhttp_impl", default-features = false, version = "0.1.1" }
flate2 = { version = "1.1.10", default-features = false }
foldhash = { version = "0.2.0", default-features = false }
fundle = { path = "crates/fundle", default-features = false, version = "0.3.5" }
fundle_macros = { path = "crates/fundle_macros", default-features = false, version = "0.3.5" }
Expand Down Expand Up @@ -268,6 +272,7 @@ time = { version = "0.3.47", default-features = false }
tokio = { version = "1.48.0", default-features = false }
tokio-native-tls = { version = "0.3.1", default-features = false }
tokio-rustls = { version = "0.26.4", default-features = false }
tokio-stream = { version = "0.1.19", default-features = false }
tonic = { version = "0.14.2", default-features = false }
tonic-prost = { version = "0.14.2", default-features = false }
tonic-prost-build = { version = "0.14.2", default-features = false }
Expand All @@ -291,6 +296,7 @@ windows-sys = { version = "0.61.2", default-features = false }
wiremock = { version = "0.6.5", default-features = false }
xxhash-rust = { version = "0.8.15", default-features = false }
zerocopy = { version = "0.8.26", default-features = false }
zstd-safe = { version = "7.2.4", default-features = false }

# >>> anvil-managed: anvil-workspace-lints
[workspace.lints]
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ These are the primary crates built out of this repo:
- [`cachet_memory`](./crates/cachet_memory/README.md) - In-memory cache tier backed by Moka for the cachet caching library.
- [`cachet_service`](./crates/cachet_service/README.md) - Layered service integration for the cachet caching library.
- [`cachet_tier`](./crates/cachet_tier/README.md) - Core cache tier trait and abstractions for building cache backends.
- [`compressors`](./crates/compressors/README.md) - Streaming compression and decompression over bytesbuf byte sequences.
- [`data_privacy`](./crates/data_privacy/README.md) - Mechanisms to classify, manipulate, and redact sensitive data.
- [`fetch`](./crates/fetch/README.md) - "Universal, composable and resilient HTTP client."
- [`fetch_azure`](./crates/fetch_azure/README.md) - Azure SDK HTTP transport backed by the fetch HTTP client.
Expand Down
1 change: 1 addition & 0 deletions crates/compressors/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Changelog
104 changes: 104 additions & 0 deletions crates/compressors/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Copyright (c) Microsoft Corporation.
Comment thread
martintmk marked this conversation as resolved.
Comment thread
martintmk marked this conversation as resolved.
# Licensed under the MIT License.

[package]
name = "compressors"
Comment thread
martintmk marked this conversation as resolved.
version = "0.1.0"
description = "Streaming compression and decompression over bytesbuf byte sequences"
readme = "README.md"
Comment thread
martintmk marked this conversation as resolved.
keywords = ["compression", "gzip", "streaming", "zero-copy"]
categories = ["compression", "network-programming"]
edition = { workspace = true }
rust-version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
homepage = { workspace = true }
include = { workspace = true }
repository = "https://github.com/microsoft/oxidizer/tree/main/crates/compressors"

# Miri cannot run all of this crate's backends. `zstd-safe` binds the native zstd library, and Miri
# cannot call foreign functions; `flate2`'s `zlib-rs` backend has an open soundness bug that trips
# Stacked Borrows whenever a Deflate or Inflate is dropped
# (https://github.com/trifectatechfoundation/zlib-rs/issues/491). Brotli is pure Rust and would run;
# excluding the whole crate rather than maintaining a brotli-only Miri configuration is a separate
# decision, taken because the per-format `cfg(miri)` scaffolding the rest would need costs more than
# the remaining coverage is worth.
[package.metadata.anvil.miri]
exclude = true

[package.metadata.docs.rs]
all-features = true

# `cfg_aliases` is used only by `build.rs`. cargo-machete does not scan build
# scripts, so it reports a false positive; ignore it here.
[package.metadata.cargo-machete]
ignored = ["cfg_aliases"]

[package.metadata.cargo_check_external_types]
allowed_external_types = [
"bytesbuf::*",
"futures_core::stream::Stream",
"recoverable::*",
"thread_aware_core::thread_aware::ThreadAware",
]

[features]
brotli = ["dep:brotli"]
# No format is enabled by default: a dependent names the ones it actually speaks, so a build that
# only needs brotli never compiles flate2, and vice versa. A build with no format at all still gets
# the shared contract and builders, which is what a crate that only re-exports them needs.
default = []
deflate = ["dep:flate2"]
futures-stream = ["dep:futures-core", "dep:pin-project-lite"]
gzip = ["dep:flate2"]
zlib = ["dep:flate2"]
zstd = ["dep:zstd-safe"]

[dependencies]
brotli = { workspace = true, features = ["std"], optional = true }
bytesbuf = { workspace = true, features = ["std"] }
# `zlib-rs` rather than flate2's default `miniz_oxide`: it is the fastest of flate2's backends and,
# unlike the `zlib`/`zlib-ng` bindings, is pure Rust, so the deflate family stays free of C on a path
# that parses untrusted input. The cost is recorded above -- it is what keeps this crate out of Miri.
flate2 = { workspace = true, features = ["zlib-rs"], optional = true }
Comment thread
martintmk marked this conversation as resolved.
Comment thread
martintmk marked this conversation as resolved.
futures-core = { workspace = true, optional = true }
pin-project-lite = { workspace = true, optional = true }
recoverable = { workspace = true }
thread_aware = { workspace = true, features = ["std"] }
zstd-safe = { workspace = true, features = ["std"], optional = true }

[build-dependencies]
cfg_aliases = { workspace = true }

[dev-dependencies]
bolero = { workspace = true, features = ["std"] }
brotli = { workspace = true, features = ["std"] }
bytesbuf = { workspace = true, features = ["std", "test-util"] }
criterion = { workspace = true }
flate2 = { workspace = true, features = ["zlib-rs"] }
futures = { workspace = true, features = ["executor"] }
futures-core = { workspace = true }
metabench = { workspace = true }
mutants = { workspace = true }
pin-project-lite = { workspace = true }
thread_aware = { path = "../thread_aware", default-features = false, features = ["std", "test-utils"] }
tick = { path = "../tick", features = ["tokio", "test-util"] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "time", "sync"] }
tokio-stream = { workspace = true }
zstd-safe = { workspace = true, features = ["std"] }

[[example]]
name = "round_trip"
required-features = ["brotli", "deflate", "gzip", "zlib", "zstd"]

[[example]]
name = "tokio_stream"
required-features = ["futures-stream", "gzip"]

[[bench]]
harness = false
name = "compressors_codec"
required-features = ["brotli", "deflate", "futures-stream", "gzip", "zlib", "zstd"]

[lints]
workspace = true
Loading
Loading