use serde::Serialize;
use std::str::FromStr;
use crate::error::{Error, ErrorKind, Result};
#[derive(Clone, Debug, PartialEq, Serialize)]
#[non_exhaustive]
pub enum Compressor {
#[cfg(feature = "zstd-compression")]
Zstd {
level: Option<i32>,
},
#[cfg(feature = "zlib-compression")]
Zlib {
level: Option<u32>,
},
#[cfg(feature = "snappy-compression")]
Snappy,
}
impl Compressor {
pub(crate) fn name(&self) -> &'static str {
match *self {
#[cfg(feature = "zstd-compression")]
Compressor::Zstd { .. } => "zstd",
#[cfg(feature = "zlib-compression")]
Compressor::Zlib { .. } => "zlib",
#[cfg(feature = "snappy-compression")]
Compressor::Snappy => "snappy",
}
}
pub(crate) fn id(&self) -> u8 {
match self {
#[cfg(feature = "zstd-compression")]
Self::Zstd { .. } => super::ZSTD_COMPRESSOR_ID,
#[cfg(feature = "zlib-compression")]
Self::Zlib { .. } => super::ZLIB_COMPRESSOR_ID,
#[cfg(feature = "snappy-compression")]
Self::Snappy => super::SNAPPY_COMPRESSOR_ID,
}
}
pub(crate) fn validate(&self) -> Result<()> {
#[cfg(feature = "zstd-compression")]
if let Self::Zstd { level: Some(level) } = self {
let valid_levels = zstd::compression_level_range();
if !valid_levels.contains(level) {
return Err(ErrorKind::InvalidArgument {
message: format!(
"Invalid zstd compression level {level}: compression level must be within \
the range {valid_levels:?}"
),
}
.into());
}
}
#[cfg(feature = "zlib-compression")]
if let Self::Zlib { level: Some(level) } = self {
if *level > 9 {
return Err(ErrorKind::InvalidArgument {
message: format!(
"Invalid zlib compression level {level}: compression level must be \
between 0 and 9 (inclusive)"
),
}
.into());
}
}
Ok(())
}
#[cfg(feature = "zlib-compression")]
pub(crate) fn write_zlib_level(&mut self, uri_level: i32) -> Result<()> {
#[allow(irrefutable_let_patterns)]
if let Compressor::Zlib { ref mut level } = *self {
if uri_level == -1 {
*level = None;
} else {
let zlib_compression_level =
u32::try_from(uri_level).map_err(|_| ErrorKind::InvalidArgument {
message: format!(
"Invalid zlib compression level specified: {uri_level}\nzlib \
compression level must be a nonnegative integer or -1 to use the \
default compression level"
),
})?;
*level = Some(zlib_compression_level);
}
}
Ok(())
}
}
impl FromStr for Compressor {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
match s.to_lowercase().as_str() {
#[cfg(feature = "zstd-compression")]
"zstd" => Ok(Self::Zstd { level: None }),
#[cfg(feature = "zlib-compression")]
"zlib" => Ok(Self::Zlib { level: None }),
#[cfg(feature = "snappy-compression")]
"snappy" => Ok(Self::Snappy),
other if other == "zstd" || other == "zlib" || other == "snappy" => {
Err(ErrorKind::InvalidArgument {
message: format!(
"Enable the {other}-compression feature flag to use {other} compression"
),
}
.into())
}
other => Err(ErrorKind::InvalidArgument {
message: format!("Unsupported compressor: {other}"),
}
.into()),
}
}
}