#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/remoc-rs/aggligator/master/.misc/aggligator.png",
html_favicon_url = "https://raw.githubusercontent.com/remoc-rs/aggligator/master/.misc/aggligator.png",
issue_tracker_base_url = "https://github.com/remoc-rs/aggligator/issues/"
)]
use async_compression::{
Level,
tokio::{bufread::ZstdDecoder, write::ZstdEncoder},
zstd::{CParameter, DParameter},
};
use async_trait::async_trait;
use std::io::{Error, ErrorKind, Result};
use tokio::io::BufReader;
use aggligator::{
io::{IoBox, StreamBox},
transport::{AcceptingWrapper, ConnectingWrapper},
};
static NAME: &str = "zstd";
#[derive(Debug, Clone)]
#[must_use = "you must pass this wrapper to the connector or acceptor"]
pub struct Zstd {
level: i32,
window_log: Option<u32>,
}
impl Default for Zstd {
fn default() -> Self {
Self::new()
}
}
impl Zstd {
pub const DEFAULT_LEVEL: i32 = 1;
pub fn new() -> Self {
Self::with_level(Self::DEFAULT_LEVEL)
}
pub fn with_level(level: i32) -> Self {
Self { level, window_log: None }
}
pub fn level(&self) -> i32 {
self.level
}
pub fn set_window_log(&mut self, window_log: Option<u32>) {
self.window_log = window_log;
}
fn wrap(&self, stream: StreamBox) -> Result<StreamBox> {
let StreamBox::Io(io) = stream else {
return Err(Error::new(ErrorKind::Unsupported, "zstd wrapper only supports IO-based streams"));
};
let (read, write) = io.into_split();
let cparams: Vec<_> = self.window_log.map(CParameter::window_log).into_iter().collect();
let encoder = ZstdEncoder::with_quality_and_params(write, Level::Precise(self.level), &cparams);
let dparams: Vec<_> = self.window_log.map(DParameter::window_log_max).into_iter().collect();
let mut decoder = ZstdDecoder::with_params(BufReader::new(read), &dparams);
decoder.multiple_members(true);
Ok(IoBox::new(decoder, encoder).into())
}
}
#[async_trait]
impl ConnectingWrapper for Zstd {
fn name(&self) -> &str {
NAME
}
async fn wrap(&self, stream: StreamBox) -> Result<StreamBox> {
Zstd::wrap(self, stream)
}
}
#[async_trait]
impl AcceptingWrapper for Zstd {
fn name(&self) -> &str {
NAME
}
async fn wrap(&self, stream: StreamBox) -> Result<StreamBox> {
Zstd::wrap(self, stream)
}
}
#[cfg(test)]
mod tests;