chore(repo): prune dead code and duplicate abstractions (#3413)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-12 13:09:42 +02:00
1 parent c17091768c
commit c9fdf8fead
2937 files changed
+42233 -176793

No files matched your search

+3 -278
View File
@@ -2,33 +2,6 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "autocfg"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "bit-set"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
[[package]]
name = "bitflags"
version = "2.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
[[package]]
name = "bumpalo"
version = "3.20.3"
@@ -53,46 +26,12 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
[[package]]
name = "find-msvc-tools"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "getrandom"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"libc",
"r-efi 5.3.0",
"wasip2",
]
[[package]]
name = "getrandom"
version = "0.4.3"
@@ -101,7 +40,7 @@ checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
dependencies = [
"cfg-if",
"libc",
"r-efi 6.0.0",
"r-efi",
]
[[package]]
@@ -110,7 +49,7 @@ version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3"
dependencies = [
"getrandom 0.4.3",
"getrandom",
"libc",
]
@@ -124,26 +63,10 @@ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
name = "libfluxcore"
version = "0.1.0"
dependencies = [
"proptest",
"wasm-bindgen",
"zstd",
]
[[package]]
name = "linux-raw-sys"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.4"
@@ -156,15 +79,6 @@ version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.107"
@@ -174,31 +88,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "proptest"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"
dependencies = [
"bit-set",
"bit-vec",
"bitflags",
"num-traits",
"rand",
"rand_chacha",
"rand_xorshift",
"regex-syntax",
"rusty-fork",
"tempfile",
"unarray",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.47"
@@ -208,110 +97,24 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "r-efi"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "rand"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41"
dependencies = [
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
dependencies = [
"getrandom 0.3.4",
]
[[package]]
name = "rand_xorshift"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
dependencies = [
"rand_core",
]
[[package]]
name = "regex-syntax"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "rustix"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "rustversion"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
[[package]]
name = "rusty-fork"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2"
dependencies = [
"fnv",
"quick-error",
"tempfile",
"wait-timeout",
]
[[package]]
name = "shlex"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
name = "syn"
version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "3.0.6"
@@ -323,49 +126,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
"getrandom 0.4.3",
"once_cell",
"rustix",
"windows-sys",
]
[[package]]
name = "unarray"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
[[package]]
name = "unicode-ident"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
[[package]]
name = "wait-timeout"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11"
dependencies = [
"libc",
]
[[package]]
name = "wasip2"
version = "1.0.4+wasi-0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.128"
@@ -398,7 +164,7 @@ dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn 3.0.6",
"syn",
"wasm-bindgen-shared",
]
@@ -411,47 +177,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "wit-bindgen"
version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "zerocopy"
version = "0.8.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "zstd"
version = "0.14.0"
-3
View File
@@ -12,9 +12,6 @@ crate-type = ["cdylib", "rlib"]
wasm-bindgen = "=0.2.128"
zstd = {version = "0.14.0", default-features = false, features = ["no_asm", "thin", "wasm"]}
[dev-dependencies]
proptest = "1.11.0"
[profile.release]
codegen-units = 1
lto = true
+3 -80
View File
@@ -235,91 +235,14 @@ mod tests {
out
}
#[test]
fn detects_apng_animation_chunk() {
let png = png_with_chunks(&[(b"acTL", &[0; 8])]);
assert!(is_animated_image_bytes(&png));
}
#[test]
fn detects_webp_animation_chunk() {
let mut webp = b"RIFF\x12\x00\x00\x00WEBPVP8X\x00\x00\x00\x00ANIM\x00\x00\x00\x00".to_vec();
webp[4..8].copy_from_slice(&18u32.to_le_bytes());
assert!(is_animated_image_bytes(&webp));
}
#[test]
fn detects_two_frame_gif() {
let gif = [
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 1, 0, 1, 0, 0, 0, 0, 0x2c, 0, 0, 0, 0, 1, 0, 1, 0,
0, 2, 0, 0x2c, 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 0, 0x3b,
];
assert!(is_animated_image_bytes(&gif));
}
#[test]
fn treats_single_frame_gif_as_static() {
let gif = [
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 1, 0, 1, 0, 0, 0, 0, 0x2c, 0, 0, 0, 0, 1, 0, 1, 0,
0, 2, 0, 0x3b,
];
assert!(!is_animated_image_bytes(&gif));
}
#[test]
fn detects_avif_sequence_brand() {
let still = b"\x00\x00\x00\x18ftypavif\x00\x00\x00\x00mif1miaf";
assert!(!is_animated_image_bytes(still));
let avis = b"\x00\x00\x00\x18ftypavis\x00\x00\x00\x00avif";
assert!(is_animated_image_bytes(avis));
}
#[test]
fn detects_avis_among_compatible_brands() {
let compat = b"\x00\x00\x00\x1cftypavif\x00\x00\x00\x00mif1avismsf1";
assert!(is_animated_image_bytes(compat));
let outside_ftyp = b"\x00\x00\x00\x14ftypavif\x00\x00\x00\x00mif1avis";
assert!(!is_animated_image_bytes(outside_ftyp));
let truncated = b"\x00\x00\x00\x40ftypavif\x00\x00\x00\x00mif1av";
assert!(!is_animated_image_bytes(truncated));
}
#[test]
fn sniffs_image_formats_from_magic_bytes() {
assert_eq!(sniff_image_format_bytes(b""), 0);
assert_eq!(sniff_image_format_bytes(b"<svg xmlns"), 0);
assert_eq!(
sniff_image_format_bytes(b"\x89PNG\r\n\x1a\n\0\0\0\rIHDR"),
1
);
assert_eq!(sniff_image_format_bytes(b"GIF89a\x01\x00"), 2);
assert_eq!(sniff_image_format_bytes(b"GIF87a\x01\x00"), 2);
assert_eq!(sniff_image_format_bytes(b"RIFF\x04\0\0\0WEBPVP8 "), 3);
assert_eq!(sniff_image_format_bytes(b"RIFF\x04\0\0\0WAVEfmt "), 0);
assert_eq!(
sniff_image_format_bytes(b"\x00\x00\x00\x18ftypavif\x00\x00\x00\x00"),
4
);
assert_eq!(
sniff_image_format_bytes(b"\x00\x00\x00\x18ftypavis\x00\x00\x00\x00"),
4
);
assert_eq!(
sniff_image_format_bytes(b"\x00\x00\x00\x18ftypheic\x00\x00\x00\x00"),
0
);
assert_eq!(sniff_image_format_bytes(b"\xff\xd8\xff\xe0\x00\x10JFIF"), 5);
assert_eq!(sniff_image_format_bytes(b"\xff\xd8"), 0);
}
#[test]
fn rejects_truncated_chunks_without_panicking() {
assert!(!is_animated_image_bytes(
b"\x89PNG\r\n\x1a\n\xff\xff\xff\xffbad!"
));
let mut png = png_with_chunks(&[(b"bad!", &[0; 8])]);
png[8..12].copy_from_slice(&u32::MAX.to_be_bytes());
assert!(!is_animated_image_bytes(&png));
assert!(!is_animated_image_bytes(b"RIFF\xff\xff\xff\xffWEBPbad!"));
}
}
+1 -7
View File
@@ -2,7 +2,6 @@
mod formats;
mod rgba;
mod zstd_frame;
mod zstd_stream;
use formats::{is_animated_image_bytes, sniff_image_format_bytes};
@@ -42,11 +41,6 @@ pub fn crop_rotate_rgba_into_buffer(
.map_err(|error| JsValue::from_str(error.message()))
}
#[wasm_bindgen]
pub fn decompress_zstd_frame(input: &[u8]) -> Result<Vec<u8>, JsValue> {
zstd_frame::decompress(input).map_err(zstd_error_to_js)
}
#[wasm_bindgen]
pub fn create_zstd_stream_decoder() -> Result<u32, JsValue> {
let decoder = zstd_stream::ZstdStreamDecoder::new().map_err(zstd_error_to_js)?;
@@ -113,7 +107,7 @@ pub fn sniff_image_format(input: &[u8]) -> u8 {
sniff_image_format_bytes(input)
}
fn zstd_error_to_js(error: zstd_frame::ZstdError) -> JsValue {
fn zstd_error_to_js(error: zstd_stream::ZstdError) -> JsValue {
JsValue::from_str(error.message())
}
-50
View File
@@ -345,7 +345,6 @@ fn copy_pixel(input: &[u8], dst: &mut [u8], layout: PixelLayout, src: Point, tar
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
fn request(src_width: u32, src_height: u32) -> TransformRequest {
TransformRequest {
@@ -378,44 +377,6 @@ mod tests {
Ok(((geometry.target_width, geometry.target_height), output))
}
#[test]
fn rotate_90_uses_clockwise_quarter_turns() {
let mut transform = request(2, 3);
transform.rotation_deg = 90;
let (size, pixels) = transformed(&rgba(&[1, 2, 3, 4, 5, 6]), transform).unwrap();
assert_eq!(size, (3, 2));
assert_eq!(pixels, rgba(&[5, 3, 1, 6, 4, 2]));
}
#[test]
fn rotate_180_reverses_rows_and_columns() {
let mut transform = request(2, 2);
transform.rotation_deg = 180;
let (size, pixels) = transformed(&rgba(&[1, 2, 3, 4]), transform).unwrap();
assert_eq!(size, (2, 2));
assert_eq!(pixels, rgba(&[4, 3, 2, 1]));
}
#[test]
fn rotate_270_uses_clockwise_quarter_turns() {
let mut transform = request(2, 3);
transform.rotation_deg = 270;
let (size, pixels) = transformed(&rgba(&[1, 2, 3, 4, 5, 6]), transform).unwrap();
assert_eq!(size, (3, 2));
assert_eq!(pixels, rgba(&[2, 4, 6, 1, 3, 5]));
}
#[test]
fn applies_nearest_resize_after_rotation() {
let mut transform = request(4, 1);
transform.x = 1;
transform.width = 2;
transform.resize_width = 4;
let (size, pixels) = transformed(&rgba(&[1, 2, 3, 4]), transform).unwrap();
assert_eq!(size, (4, 1));
assert_eq!(pixels, rgba(&[2, 2, 3, 3]));
}
#[test]
fn clamps_crop_to_source_bounds() {
let mut transform = request(3, 2);
@@ -463,15 +424,4 @@ mod tests {
TransformError::InvalidOutputLength
);
}
proptest! {
#[test]
fn identity_transform_preserves_pixels(width in 1u32..16, height in 1u32..16) {
let pixel_count = (width * height) as usize;
let input = rgba(&(0..pixel_count).map(|index| index as u8).collect::<Vec<_>>());
let (size, pixels) = transformed(&input, request(width, height)).unwrap();
prop_assert_eq!(size, (width, height));
prop_assert_eq!(pixels, input);
}
}
}
@@ -1,89 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::io::Read;
pub(crate) const READ_BUFFER_BYTES: usize = 16 * 1024;
pub(crate) const MAX_DECOMPRESSED_BYTES: usize = 64 * 1024 * 1024;
#[derive(Debug)]
pub enum ZstdError {
DecompressedSizeTooLarge,
Decode,
Encode,
OutOfMemory,
}
impl ZstdError {
pub fn message(&self) -> &'static str {
match self {
Self::DecompressedSizeTooLarge => "zstd decompressed payload is too large",
Self::Decode => "zstd decompression failed",
Self::Encode => "zstd compression failed",
Self::OutOfMemory => "out of memory",
}
}
}
pub fn decompress(input: &[u8]) -> Result<Vec<u8>, ZstdError> {
if let Some(content_size) =
zstd::zstd_safe::get_frame_content_size(input).map_err(|_| ZstdError::Decode)?
{
let content_size =
usize::try_from(content_size).map_err(|_| ZstdError::DecompressedSizeTooLarge)?;
if content_size > MAX_DECOMPRESSED_BYTES {
return Err(ZstdError::DecompressedSizeTooLarge);
}
}
let mut decoder = zstd::stream::read::Decoder::new(input)
.map_err(|_| ZstdError::Decode)?
.single_frame();
let mut output = Vec::new();
let mut buffer = [0u8; READ_BUFFER_BYTES];
loop {
let read = decoder.read(&mut buffer).map_err(|_| ZstdError::Decode)?;
if read == 0 {
return Ok(output);
}
let next_len = output
.len()
.checked_add(read)
.ok_or(ZstdError::DecompressedSizeTooLarge)?;
if next_len > MAX_DECOMPRESSED_BYTES {
return Err(ZstdError::DecompressedSizeTooLarge);
}
output
.try_reserve(read)
.map_err(|_| ZstdError::OutOfMemory)?;
output.extend_from_slice(&buffer[..read]);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decompresses_a_zstd_frame() {
let input = b"hello from fluxcore";
let compressed = zstd::stream::encode_all(input.as_slice(), 1).unwrap();
assert_eq!(decompress(&compressed).unwrap(), input);
}
#[test]
fn rejects_invalid_zstd() {
assert!(matches!(decompress(b"not zstd"), Err(ZstdError::Decode)));
}
#[test]
fn rejects_frames_over_the_decompressed_limit() {
let input = vec![b'x'; MAX_DECOMPRESSED_BYTES + 1];
let compressed = zstd::stream::encode_all(input.as_slice(), 1).unwrap();
assert!(matches!(
decompress(&compressed),
Err(ZstdError::DecompressedSizeTooLarge)
));
}
}
+43 -71
View File
@@ -3,7 +3,27 @@
use zstd::zstd_safe::zstd_sys::ZSTD_EndDirective;
use zstd::zstd_safe::{CCtx, CParameter, DCtx, InBuffer, OutBuffer};
use crate::zstd_frame::{MAX_DECOMPRESSED_BYTES, READ_BUFFER_BYTES, ZstdError};
const READ_BUFFER_BYTES: usize = 16 * 1024;
const MAX_DECOMPRESSED_BYTES: usize = 64 * 1024 * 1024;
#[derive(Debug)]
pub enum ZstdError {
DecompressedSizeTooLarge,
Decode,
Encode,
OutOfMemory,
}
impl ZstdError {
pub fn message(&self) -> &'static str {
match self {
Self::DecompressedSizeTooLarge => "zstd decompressed payload is too large",
Self::Decode => "zstd decompression failed",
Self::Encode => "zstd compression failed",
Self::OutOfMemory => "out of memory",
}
}
}
pub struct ZstdStreamEncoder {
context: CCtx<'static>,
@@ -114,48 +134,6 @@ fn append_output(output: &mut Vec<u8>, bytes: &[u8]) -> Result<(), ZstdError> {
#[cfg(test)]
mod tests {
use super::*;
use zstd::stream::raw::{Encoder, InBuffer, Operation, OutBuffer};
fn compress_stream_chunk(encoder: &mut Encoder<'_>, input: &[u8]) -> Vec<u8> {
let mut compressed = Vec::new();
let mut input = InBuffer::around(input);
let mut buffer = [0u8; READ_BUFFER_BYTES];
while input.pos() < input.src.len() {
let written = {
let mut output = OutBuffer::around(&mut buffer[..]);
encoder.run(&mut input, &mut output).unwrap();
output.pos()
};
compressed.extend_from_slice(&buffer[..written]);
}
loop {
let (remaining, written) = {
let mut output = OutBuffer::around(&mut buffer[..]);
let remaining = encoder.flush(&mut output).unwrap();
(remaining, output.pos())
};
compressed.extend_from_slice(&buffer[..written]);
if remaining == 0 {
break;
}
}
compressed
}
#[test]
fn decodes_multiple_flushed_chunks_from_one_zstd_stream() {
let mut encoder = Encoder::new(1).unwrap();
let mut decoder = ZstdStreamDecoder::new().unwrap();
let first = compress_stream_chunk(&mut encoder, br#"{"op":10}"#);
let second = compress_stream_chunk(&mut encoder, br#"{"op":11}"#);
assert_eq!(decoder.decompress_chunk(&first).unwrap(), br#"{"op":10}"#);
assert_eq!(decoder.decompress_chunk(&second).unwrap(), br#"{"op":11}"#);
}
#[test]
fn keeps_partial_frame_state_between_chunks() {
@@ -169,23 +147,6 @@ mod tests {
assert_eq!([first, second].concat(), b"hello stream");
}
#[test]
fn encoder_and_decoder_roundtrip_ten_thousand_messages_bidirectionally() {
let mut encoder = ZstdStreamEncoder::new(3).unwrap();
let mut decoder = ZstdStreamDecoder::new().unwrap();
for seq in 1..=10_000 {
let payload = format!(
r#"{{"op":1,"d":{},"meta":"bidirectional zstd stream message {}"}}"#,
seq, seq
);
let compressed = encoder.compress_chunk(payload.as_bytes()).unwrap();
assert!(!compressed.is_empty());
let decoded = decoder.decompress_chunk(&compressed).unwrap();
assert_eq!(decoded, payload.as_bytes());
}
}
#[test]
fn encoder_handles_a_payload_larger_than_the_buffer() {
let mut encoder = ZstdStreamEncoder::new(3).unwrap();
@@ -197,19 +158,30 @@ mod tests {
}
#[test]
fn decodes_ten_thousand_flushed_gateway_json_chunks() {
let mut encoder = Encoder::new(3).unwrap();
fn rejects_invalid_zstd() {
let mut decoder = ZstdStreamDecoder::new().unwrap();
assert!(matches!(
decoder.decompress_chunk(b"not zstd"),
Err(ZstdError::Decode)
));
}
for seq in 1..=10_000 {
let payload = format!(
r#"{{"op":0,"t":"MESSAGE_CREATE","s":{},"d":{{"id":"{}","channel_id":"1497639278555484216","guild_id":"1427764661718740994","content":"gateway zstd stream stress payload {}"}}}}"#,
seq, seq, seq
);
let compressed = compress_stream_chunk(&mut encoder, payload.as_bytes());
let decoded = decoder.decompress_chunk(&compressed).unwrap();
#[test]
fn accepts_the_decompressed_limit() {
let input = vec![b'x'; MAX_DECOMPRESSED_BYTES];
let compressed = zstd::stream::encode_all(input.as_slice(), 1).unwrap();
let mut decoder = ZstdStreamDecoder::new().unwrap();
assert_eq!(decoder.decompress_chunk(&compressed).unwrap(), input);
}
assert_eq!(decoded, payload.as_bytes());
}
#[test]
fn rejects_frames_over_the_decompressed_limit() {
let input = vec![b'x'; MAX_DECOMPRESSED_BYTES + 1];
let compressed = zstd::stream::encode_all(input.as_slice(), 1).unwrap();
let mut decoder = ZstdStreamDecoder::new().unwrap();
assert!(matches!(
decoder.decompress_chunk(&compressed),
Err(ZstdError::DecompressedSizeTooLarge)
));
}
}