Skip to content

Commit 78c4172

Browse files
authored
Implement rudimentary compression support (#65)
Adds support for a basic encoder that just packs the input into raw blocks
1 parent 453fd65 commit 78c4172

File tree

20 files changed

+1050
-10
lines changed

20 files changed

+1050
-10
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-all
2424
[dev-dependencies]
2525
criterion = "0.5"
2626
rand = { version = "0.8.5", features = ["small_rng"] }
27+
zstd = "0.13.2"
2728

2829
[features]
2930
default = ["hash", "std"]

Readme.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,22 @@
66

77
# What is this
88

9-
A feature-complete decoder for the zstd compression format as defined in: [This document](https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md).
9+
A pure Rust implementation of the Zstandard compression algorithm, as defined in [this document](https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md).
1010

11-
It is NOT a compressor. I don't plan on implementing that part either, at least not in the near future. (If someone is motivated enough I will of course accept a pull-request!)
11+
This crate contains a fully operational implementation of the decompression portion of the standard.
1212

13-
This crate might look like it is not active, this is because there isn't really anything to do anymore, unless a bug is found or a new API feature is requested. I will of course respond to and look into issues!
13+
*Work has started on a compressor, but it has not reached a point where the compressor provides any real function.* (CONTRIBUTORS WELCOME)
14+
15+
This crate is currently actively maintained.
1416

1517
# Current Status
1618

1719
Feature complete on the decoder side. In terms of speed it is still behind the original C implementation which has a rust binding located [here](https://github.com/gyscos/zstd-rs).
1820

19-
Actively maintained but no new features currently planned. If you have suggestions please open an issue and I'll consider it.
21+
On the compression side:
22+
- [x] Support for generating raw, uncompressed frames
23+
- [ ] Support for generating RLE compressed blocks
24+
- [ ] Support for generating compressed blocks at any compression level
2025

2126
## Speed
2227

benches/decode_all.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use ruzstd::FrameDecoder;
33

44
fn criterion_benchmark(c: &mut Criterion) {
55
let mut fr = FrameDecoder::new();
6-
let mut target_slice = &mut vec![0u8;1024 * 1024 * 200];
6+
let mut target_slice = &mut vec![0u8; 1024 * 1024 * 200];
77
let src = include_bytes!("../decodecorpus_files/z000033.zst");
88

99
c.bench_function("decode_all_slice", |b| {

fuzz/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ members = ["."]
2424
name = "decode"
2525
path = "fuzz_targets/decode.rs"
2626

27+
[[bin]]
28+
name = "encode"
29+
path = "fuzz_targets/encode.rs"
30+
2731
[[bin]]
2832
name = "interop"
2933
path = "fuzz_targets/interop.rs"

fuzz/fuzz_targets/encode.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![no_main]
2+
#[macro_use] extern crate libfuzzer_sys;
3+
extern crate ruzstd;
4+
use ruzstd::encoding::{FrameCompressor, CompressionLevel};
5+
6+
fuzz_target!(|data: &[u8]| {
7+
let mut content = data;
8+
let mut compressor = FrameCompressor::new(data, CompressionLevel::Uncompressed);
9+
let mut output = Vec::new();
10+
compressor.compress(&mut output);
11+
});

fuzz/fuzz_targets/interop.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,42 @@ fn encode_zstd(data: &[u8]) -> Result<Vec<u8>, std::io::Error> {
3131
zstd::stream::encode_all(std::io::Cursor::new(data), 3)
3232
}
3333

34+
fn encode_ruzstd_uncompressed(data: &mut dyn std::io::Read) -> Vec<u8> {
35+
let mut input = Vec::new();
36+
data.read_to_end(&mut input).unwrap();
37+
let mut compressor = ruzstd::encoding::FrameCompressor::new(&input, ruzstd::encoding::CompressionLevel::Uncompressed);
38+
let mut output = Vec::new();
39+
compressor.compress(&mut output);
40+
output
41+
}
42+
43+
fn decode_zstd(data: &[u8]) -> Result<Vec<u8>, std::io::Error> {
44+
let mut output = Vec::new();
45+
zstd::stream::copy_decode(data, &mut output)?;
46+
Ok(output)
47+
}
48+
3449
fuzz_target!(|data: &[u8]| {
50+
// Decoding
3551
let compressed = encode_zstd(data).unwrap();
3652
let decoded = decode_ruzstd(&mut compressed.as_slice());
3753
let decoded2 = decode_ruzstd_writer(&mut compressed.as_slice());
3854
assert!(
3955
decoded == data,
40-
"Decoded data did not match the original input"
56+
"Decoded data did not match the original input during decompression"
4157
);
4258
assert_eq!(
4359
decoded2, data,
44-
"Decoded data did not match the original input"
60+
"Decoded data did not match the original input during decompression"
61+
);
62+
63+
// Encoding
64+
// Uncompressed encoding
65+
let mut input = data;
66+
let compressed = encode_ruzstd_uncompressed(&mut input);
67+
let decoded = decode_zstd(&compressed).unwrap();
68+
assert_eq!(
69+
decoded, data,
70+
"Decoded data did not match the original input during compression"
4571
);
4672
});

src/decoding/block_decoder.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,8 @@ impl BlockDecoder {
454454
Ok(())
455455
}
456456

457+
/// Reads 3 bytes from the provided reader and returns
458+
/// the deserialized header and the number of bytes read.
457459
pub fn read_block_header(
458460
&mut self,
459461
mut r: impl Read,

0 commit comments

Comments
 (0)