pub mod deflate;
pub mod fletcher32;
#[cfg(feature = "lz4")]
pub mod lz4;
pub mod nbit;
pub mod scaleoffset;
pub mod shuffle;
use std::collections::HashMap;
use crate::error::{Error, Result};
use crate::messages::filter_pipeline::FilterDescription;
pub const FILTER_DEFLATE: u16 = 1;
pub const FILTER_SHUFFLE: u16 = 2;
pub const FILTER_FLETCHER32: u16 = 3;
pub const FILTER_SZIP: u16 = 4;
pub const FILTER_NBIT: u16 = 5;
pub const FILTER_SCALEOFFSET: u16 = 6;
pub const FILTER_LZ4: u16 = 32004;
pub type FilterFn = Box<dyn Fn(&FilterDescription, &[u8], usize) -> Result<Vec<u8>> + Send + Sync>;
pub struct FilterRegistry {
filters: HashMap<u16, FilterFn>,
}
impl FilterRegistry {
pub fn new() -> Self {
let mut registry = FilterRegistry {
filters: HashMap::new(),
};
registry.register(
FILTER_DEFLATE,
Box::new(|_, data, _| deflate::decompress(data)),
);
registry.register(
FILTER_SHUFFLE,
Box::new(|_, data, elem_size| Ok(shuffle::unshuffle(data, elem_size))),
);
registry.register(
FILTER_FLETCHER32,
Box::new(|_, data, _| fletcher32::verify_and_strip(data)),
);
registry.register(
FILTER_NBIT,
Box::new(|filter, data, _| nbit::decompress(data, &filter.client_data)),
);
registry.register(
FILTER_SCALEOFFSET,
Box::new(|filter, data, _| scaleoffset::decompress(data, &filter.client_data)),
);
#[cfg(feature = "lz4")]
registry.register(FILTER_LZ4, Box::new(|_, data, _| lz4::decompress(data)));
registry
}
pub fn register(&mut self, id: u16, f: FilterFn) {
self.filters.insert(id, f);
}
pub fn apply(
&self,
filter: &FilterDescription,
data: &[u8],
element_size: usize,
) -> Result<Vec<u8>> {
match self.filters.get(&filter.id) {
Some(f) => f(filter, data, element_size),
None => Err(Error::UnsupportedFilter(format!("filter id {}", filter.id))),
}
}
}
impl Default for FilterRegistry {
fn default() -> Self {
Self::new()
}
}
pub fn apply_pipeline(
data: &[u8],
filters: &[FilterDescription],
filter_mask: u32,
element_size: usize,
registry: Option<&FilterRegistry>,
) -> Result<Vec<u8>> {
let active_count = filters
.iter()
.enumerate()
.rev()
.filter(|(i, _)| filter_mask & (1 << i) == 0)
.count();
if active_count == 0 {
return Ok(data.to_vec());
}
if active_count == 1 {
for (i, filter) in filters.iter().enumerate().rev() {
if filter_mask & (1 << i) != 0 {
continue;
}
return if let Some(reg) = registry {
reg.apply(filter, data, element_size)
} else {
apply_builtin_filter(filter, data, element_size)
};
}
}
let mut owned: Option<Vec<u8>> = None;
for (i, filter) in filters.iter().enumerate().rev() {
if filter_mask & (1 << i) != 0 {
continue;
}
let input: &[u8] = match &owned {
Some(buf) => buf,
None => data,
};
owned = Some(if let Some(reg) = registry {
reg.apply(filter, input, element_size)?
} else {
apply_builtin_filter(filter, input, element_size)?
});
}
Ok(owned.unwrap_or_else(|| data.to_vec()))
}
fn apply_builtin_filter(
filter: &FilterDescription,
data: &[u8],
element_size: usize,
) -> Result<Vec<u8>> {
match filter.id {
FILTER_DEFLATE => deflate::decompress(data),
FILTER_SHUFFLE => Ok(shuffle::unshuffle(data, element_size)),
FILTER_FLETCHER32 => fletcher32::verify_and_strip(data),
FILTER_SZIP => Err(Error::UnsupportedFilter("szip".into())),
FILTER_NBIT => nbit::decompress(data, &filter.client_data),
FILTER_SCALEOFFSET => scaleoffset::decompress(data, &filter.client_data),
#[cfg(feature = "lz4")]
FILTER_LZ4 => lz4::decompress(data),
id => Err(Error::UnsupportedFilter(format!("filter id {}", id))),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_filter_registry_default() {
let registry = FilterRegistry::new();
assert!(registry.filters.contains_key(&FILTER_DEFLATE));
assert!(registry.filters.contains_key(&FILTER_SHUFFLE));
assert!(registry.filters.contains_key(&FILTER_FLETCHER32));
assert!(registry.filters.contains_key(&FILTER_NBIT));
assert!(registry.filters.contains_key(&FILTER_SCALEOFFSET));
}
#[test]
fn test_filter_registry_custom() {
let mut registry = FilterRegistry::new();
registry.register(32000, Box::new(|_, data, _| Ok(data.to_vec())));
let filter = FilterDescription {
id: 32000,
name: None,
client_data: Vec::new(),
};
let result = registry.apply(&filter, &[1, 2, 3], 1).unwrap();
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_filter_registry_unknown() {
let registry = FilterRegistry::new();
let filter = FilterDescription {
id: 9999,
name: None,
client_data: Vec::new(),
};
let err = registry.apply(&filter, &[1, 2, 3], 1).unwrap_err();
assert!(matches!(err, Error::UnsupportedFilter(_)));
}
}