use core::fmt;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct FormatVersion(u8);
impl FormatVersion {
pub const MIN: Self = Self(21);
pub const MAX: Self = Self(27);
pub(crate) const fn get(self) -> u32 {
self.0 as u32
}
pub(crate) const fn new(version: u32) -> Option<Self> {
if version < Self::MIN.0 as u32 || version > Self::MAX.0 as u32 {
return None;
}
Some(Self(version as u8))
}
}
impl Default for FormatVersion {
fn default() -> Self {
Self::MAX
}
}
impl From<FormatVersion> for u32 {
fn from(version: FormatVersion) -> Self {
version.get()
}
}
impl TryFrom<u32> for FormatVersion {
type Error = UnsupportedFormatVersion;
fn try_from(version: u32) -> Result<Self, Self::Error> {
Self::new(version).ok_or(UnsupportedFormatVersion { version })
}
}
impl fmt::Display for FormatVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, thiserror::Error)]
#[error("OpenZL format version {version} is not supported (supported: 21..=27)")]
pub struct UnsupportedFormatVersion {
pub version: u32,
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::ToString;
#[test]
fn supported_range_is_inclusive() {
for version in 21..=27 {
assert_eq!(
u32::from(FormatVersion::try_from(version).unwrap()),
version
);
}
for version in [0, 8, 20, 28, u32::MAX] {
assert_eq!(
FormatVersion::try_from(version),
Err(UnsupportedFormatVersion { version })
);
}
}
#[test]
fn default_is_the_newest_and_displays_as_a_number() {
assert_eq!(FormatVersion::default(), FormatVersion::MAX);
assert_eq!(FormatVersion::MAX.to_string(), "27");
}
#[test]
fn error_names_the_version_and_range() {
let message = UnsupportedFormatVersion { version: 9 }.to_string();
assert!(message.contains('9') && message.contains("21..=27"));
}
}