Skip to main content

ZstdDictCompressor

Struct ZstdDictCompressor 

Source
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

Source

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());
Source

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());
Source

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());
Source

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§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more