use super::error::{ArtefactError, Result};
use serde::Serialize;
use std::fmt;
const CURRENT_MAX: u32 = 1;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
#[serde(transparent)]
pub struct SchemaVersion(u32);
impl SchemaVersion {
#[must_use]
pub fn current() -> Self {
Self(CURRENT_MAX)
}
#[must_use]
pub fn as_u32(self) -> u32 {
self.0
}
}
impl<'de> serde::Deserialize<'de> for SchemaVersion {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let v = <u32 as serde::Deserialize>::deserialize(deserializer)?;
Self::try_from(v).map_err(serde::de::Error::custom)
}
}
impl TryFrom<u32> for SchemaVersion {
type Error = ArtefactError;
fn try_from(value: u32) -> Result<Self> {
if value == 0 || value > CURRENT_MAX {
return Err(ArtefactError::UnsupportedSchemaVersion {
value,
max: CURRENT_MAX,
});
}
Ok(Self(value))
}
}
impl From<SchemaVersion> for u32 {
fn from(v: SchemaVersion) -> Self {
v.0
}
}
impl fmt::Display for SchemaVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn current_returns_version_one() {
let v = SchemaVersion::current();
assert_eq!(v.as_u32(), 1);
}
#[test]
fn accepts_version_one() {
let v = SchemaVersion::try_from(1_u32);
assert!(v.is_ok());
assert_eq!(v.expect("checked above").as_u32(), 1);
}
#[test]
fn rejects_version_zero() {
let result = SchemaVersion::try_from(0_u32);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(matches!(
err,
ArtefactError::UnsupportedSchemaVersion { value: 0, max: 1 }
));
}
#[test]
fn rejects_version_above_max() {
let result = SchemaVersion::try_from(2_u32);
assert!(result.is_err());
}
#[test]
fn into_u32_round_trips() {
let v = SchemaVersion::current();
let n: u32 = v.into();
assert_eq!(n, 1);
}
#[test]
fn display_shows_number() {
let v = SchemaVersion::current();
assert_eq!(format!("{v}"), "1");
}
#[test]
fn serde_round_trip() {
let v = SchemaVersion::current();
let json = serde_json::to_string(&v).expect("serialize");
let back: SchemaVersion = serde_json::from_str(&json).expect("deserialize");
assert_eq!(v, back);
}
#[test]
fn deserialize_rejects_unsupported_version() {
let json = "99";
let result: std::result::Result<SchemaVersion, _> = serde_json::from_str(json);
assert!(result.is_err());
}
}