pub mod codecs;
pub mod packing;
pub mod rle;
pub mod roaring;
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum MaskMethod {
Rle,
#[default]
Roaring,
#[cfg(feature = "blosc2")]
Blosc2 {
codec: crate::pipeline::Blosc2Codec,
level: i32,
},
Zstd {
level: Option<i32>,
},
Lz4,
None,
}
impl MaskMethod {
pub fn name(&self) -> &'static str {
match self {
Self::Rle => "rle",
Self::Roaring => "roaring",
#[cfg(feature = "blosc2")]
Self::Blosc2 { .. } => "blosc2",
Self::Zstd { .. } => "zstd",
Self::Lz4 => "lz4",
Self::None => "none",
}
}
pub fn from_name(name: &str) -> Result<Self, MaskError> {
match name {
"rle" => Ok(Self::Rle),
"roaring" => Ok(Self::Roaring),
"blosc2" => {
#[cfg(feature = "blosc2")]
{
Ok(Self::Blosc2 {
codec: crate::pipeline::Blosc2Codec::Lz4,
level: 5,
})
}
#[cfg(not(feature = "blosc2"))]
{
Err(MaskError::FeatureDisabled { method: "blosc2" })
}
}
"zstd" => Ok(Self::Zstd { level: None }),
"lz4" => Ok(Self::Lz4),
"none" => Ok(Self::None),
other => Err(MaskError::UnknownMethod(other.to_string())),
}
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum MaskError {
#[error(
"unknown mask method {0:?} (expected \"none\" | \"rle\" | \"roaring\" | \"lz4\" | \"zstd\" | \"blosc2\")"
)]
UnknownMethod(String),
#[error("mask method {method:?} requires feature {method:?} which is not compiled in")]
FeatureDisabled { method: &'static str },
#[error("bitmask length mismatch: expected {expected} elements, got {actual}")]
LengthMismatch { expected: usize, actual: usize },
#[error("malformed mask payload: {0}")]
Malformed(String),
#[error("RLE decode error: {0}")]
Rle(String),
#[error("Roaring decode error: {0}")]
Roaring(String),
#[error("underlying codec error: {0}")]
Codec(String),
#[error("failed to reserve {bytes} bytes for bitmask buffer: {reason}")]
AllocationFailed { bytes: usize, reason: String },
}
pub(crate) fn try_reserve_mask(v: &mut Vec<bool>, n: usize) -> Result<(), MaskError> {
v.try_reserve_exact(n)
.map_err(|e| MaskError::AllocationFailed {
bytes: n,
reason: e.to_string(),
})
}
pub type Bitmask = Vec<bool>;
#[cfg(test)]
mod allocation_tests {
use super::*;
#[test]
fn try_reserve_mask_rejects_pathological_capacity() {
let mut v: Vec<bool> = Vec::new();
let err = try_reserve_mask(&mut v, isize::MAX as usize + 1)
.expect_err("reservation beyond isize::MAX must fail capacity check");
match err {
MaskError::AllocationFailed { .. } => {}
other => panic!("expected AllocationFailed, got {other:?}"),
}
}
#[test]
fn roaring_decode_rejects_addressable_limit() {
let err = roaring::decode(&[], u32::MAX as usize + 1)
.expect_err("roaring must reject n_elements > u32::MAX");
match err {
MaskError::Malformed(_) => {}
other => panic!("expected Malformed, got {other:?}"),
}
}
}