use derive_more::{Display, From};
use serde::{Deserialize, Deserializer, Serialize};
use zarrs_metadata::ConfigurationSerialize;
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug, Display, From)]
#[non_exhaustive]
#[serde(untagged)]
pub enum ZlibCodecConfiguration {
V1(ZlibCodecConfigurationV1),
}
impl ConfigurationSerialize for ZlibCodecConfiguration {}
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug, Display)]
#[serde(deny_unknown_fields)]
#[display("{}", serde_json::to_string(self).unwrap_or_default())]
pub struct ZlibCodecConfigurationV1 {
pub level: ZlibCompressionLevel,
}
#[derive(Serialize, Copy, Clone, Debug, Eq, PartialEq)]
pub struct ZlibCompressionLevel(u32);
macro_rules! zlib_compression_level_try_from {
( $t:ty ) => {
impl TryFrom<$t> for ZlibCompressionLevel {
type Error = $t;
fn try_from(level: $t) -> Result<Self, Self::Error> {
if level <= 9 {
Ok(Self(u32::from(level)))
} else {
Err(level)
}
}
}
};
}
zlib_compression_level_try_from!(u8);
zlib_compression_level_try_from!(u16);
zlib_compression_level_try_from!(u32);
impl<'de> Deserialize<'de> for ZlibCompressionLevel {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let level = u32::deserialize(d)?;
if level <= 9 {
Ok(Self(level))
} else {
Err(serde::de::Error::custom(
"zlib compression level must be between 0 and 9",
))
}
}
}
impl ZlibCompressionLevel {
pub fn new<N: num::Unsigned + std::cmp::PartialOrd<u32>>(
compression_level: N,
) -> Result<Self, N>
where
u32: From<N>,
{
if compression_level < 10 {
Ok(Self(u32::from(compression_level)))
} else {
Err(compression_level)
}
}
#[must_use]
pub const fn as_u32(&self) -> u32 {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn codec_zlib_valid1() {
let json = r#"
{
"level": 5
}"#;
assert!(serde_json::from_str::<ZlibCodecConfiguration>(json).is_ok());
}
#[test]
fn codec_zlib_invalid_level() {
let json = r#"
{
"level": 10
}"#;
let codec_configuration = serde_json::from_str::<ZlibCodecConfiguration>(json);
assert!(codec_configuration.is_err());
}
}