pub struct ZstdDictCompressor;Expand description
Stateless driver for zstd dictionary operations.
All methods take the dictionary by reference. No internal state is retained between calls; callers supply both the data and the dictionary each time.
The trained dictionary should be stored in
crate::infrastructure::repositories::InMemoryDictionaryStore (or a
custom crate::domain::ports::dictionary_store::DictionaryStore impl)
and shared via Arc<ZstdDictionary>.
§Examples
use pjson_rs::compression::zstd::{ZstdDictCompressor, N_TRAIN, MAX_DICT_SIZE};
let samples: Vec<Vec<u8>> = (0..N_TRAIN).map(|i| {
format!("{{\"id\":{i},\"key\":\"value\",\"score\":{}}}", i * 3).into_bytes()
}).collect();
let dict = ZstdDictCompressor::train(&samples, MAX_DICT_SIZE).unwrap();
let data = b"{\"id\":99,\"key\":\"value\",\"score\":297}";
let compressed = ZstdDictCompressor::compress(data, &dict).unwrap();
let decompressed = ZstdDictCompressor::decompress(&compressed, &dict, data.len() * 2).unwrap();
assert_eq!(decompressed, data);Implementations§
Source§impl ZstdDictCompressor
impl ZstdDictCompressor
Sourcepub fn train(
samples: &[Vec<u8>],
max_dict_size: usize,
) -> Result<ZstdDictionary>
pub fn train( samples: &[Vec<u8>], max_dict_size: usize, ) -> Result<ZstdDictionary>
Train a zstd dictionary from a corpus of sample byte strings.
max_dict_size is clamped to MAX_DICT_SIZE before being passed to
libzstd — even if the caller requests a larger dict, the type invariant of
ZstdDictionary is always satisfied.
Libzstd requires at least 8 samples; the PJS convention is to call this
after accumulating N_TRAIN (32) samples for better dictionary quality.
§Errors
Returns Error::CompressionError if:
samples.len() < 8(libzstd hard minimum)- libzstd training itself fails (e.g., samples too small or too uniform)
§Examples
use pjson_rs::compression::zstd::{ZstdDictCompressor, N_TRAIN, MAX_DICT_SIZE};
let samples: Vec<Vec<u8>> = (0..N_TRAIN).map(|i| {
format!("{{\"seq\":{i},\"payload\":\"aaabbbccc{i}\"}}").into_bytes()
}).collect();
let dict = ZstdDictCompressor::train(&samples, MAX_DICT_SIZE).unwrap();
assert!(dict.len() <= MAX_DICT_SIZE);
// Requesting a larger size is silently clamped.
let dict2 = ZstdDictCompressor::train(&samples, usize::MAX).unwrap();
assert!(dict2.len() <= MAX_DICT_SIZE);
// Insufficient samples are rejected before calling libzstd.
let few: Vec<Vec<u8>> = vec![b"data".to_vec(); 3];
assert!(ZstdDictCompressor::train(&few, MAX_DICT_SIZE).is_err());Sourcepub fn compress(data: &[u8], dict: &ZstdDictionary) -> Result<Vec<u8>>
pub fn compress(data: &[u8], dict: &ZstdDictionary) -> Result<Vec<u8>>
Compress data using the dictionary at the default level (DEFAULT_LEVEL).
§Errors
Returns Error::CompressionError on libzstd failure.
§Examples
use pjson_rs::compression::zstd::{ZstdDictCompressor, N_TRAIN, MAX_DICT_SIZE};
let samples: Vec<Vec<u8>> = (0..N_TRAIN)
.map(|i| format!("{{\"n\":{i}}}").into_bytes())
.collect();
let dict = ZstdDictCompressor::train(&samples, MAX_DICT_SIZE).unwrap();
let compressed = ZstdDictCompressor::compress(b"{\"n\":99}", &dict).unwrap();
assert!(!compressed.is_empty());Sourcepub fn compress_with_level(
data: &[u8],
dict: &ZstdDictionary,
level: i32,
) -> Result<Vec<u8>>
pub fn compress_with_level( data: &[u8], dict: &ZstdDictionary, level: i32, ) -> Result<Vec<u8>>
Compress data using the dictionary at an explicit compression level.
Level must be in [1, 22]; libzstd clamps out-of-range values silently.
§Errors
Returns Error::CompressionError on libzstd failure.
§Examples
use pjson_rs::compression::zstd::{ZstdDictCompressor, N_TRAIN, MAX_DICT_SIZE};
let samples: Vec<Vec<u8>> = (0..N_TRAIN)
.map(|i| format!("{{\"n\":{i}}}").into_bytes())
.collect();
let dict = ZstdDictCompressor::train(&samples, MAX_DICT_SIZE).unwrap();
let compressed = ZstdDictCompressor::compress_with_level(b"{\"n\":99}", &dict, 1).unwrap();
assert!(!compressed.is_empty());Sourcepub fn decompress(
data: &[u8],
dict: &ZstdDictionary,
max_output: usize,
) -> Result<Vec<u8>>
pub fn decompress( data: &[u8], dict: &ZstdDictionary, max_output: usize, ) -> Result<Vec<u8>>
Decompress data using the dictionary, capping output at max_output bytes.
This is the standalone decompression path — for untrusted input routed
through crate::compression::secure::SecureCompressor, use
crate::compression::secure::ByteCodec::ZstdDict instead, which passes the
output through crate::security::CompressionBombDetector.
§Errors
Returns Error::CompressionError on libzstd failure.
§Examples
use pjson_rs::compression::zstd::{ZstdDictCompressor, N_TRAIN, MAX_DICT_SIZE};
let samples: Vec<Vec<u8>> = (0..N_TRAIN)
.map(|i| format!("{{\"n\":{i}}}").into_bytes())
.collect();
let dict = ZstdDictCompressor::train(&samples, MAX_DICT_SIZE).unwrap();
let data = b"{\"n\":99}";
let compressed = ZstdDictCompressor::compress(data, &dict).unwrap();
let decompressed = ZstdDictCompressor::decompress(&compressed, &dict, 1024).unwrap();
assert_eq!(decompressed.as_slice(), data.as_slice());Auto Trait Implementations§
impl Freeze for ZstdDictCompressor
impl RefUnwindSafe for ZstdDictCompressor
impl Send for ZstdDictCompressor
impl Sync for ZstdDictCompressor
impl Unpin for ZstdDictCompressor
impl UnsafeUnpin for ZstdDictCompressor
impl UnwindSafe for ZstdDictCompressor
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more