use serde::{Deserialize, Serialize};
use ts_rs::TS;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, TS)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub enum SchemaVersion {
V1,
}
impl<'de> Deserialize<'de> for SchemaVersion {
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if de.is_human_readable() {
#[derive(Deserialize)]
#[serde(untagged)]
enum Repr {
Num(u64),
Name(String),
}
match Repr::deserialize(de)? {
Repr::Num(1) => Ok(SchemaVersion::V1),
Repr::Num(n) => Err(serde::de::Error::custom(format!(
"unknown schema_version {n} (known versions: 1)"
))),
Repr::Name(s) if s.eq_ignore_ascii_case("v1") => Ok(SchemaVersion::V1),
Repr::Name(s) => Err(serde::de::Error::custom(format!(
"unknown schema_version {s:?} (known versions: \"V1\")"
))),
}
} else {
#[derive(Deserialize)]
enum Wire {
V1,
}
match Wire::deserialize(de)? {
Wire::V1 => Ok(SchemaVersion::V1),
}
}
}
}
impl Default for SchemaVersion {
fn default() -> Self {
Self::V1
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn accepts_integer_and_string_forms_and_writes_the_name() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Doc {
schema_version: SchemaVersion,
}
for src in [
"schema_version = 1",
r#"schema_version = "V1""#,
r#"schema_version = "v1""#,
] {
let doc: Doc = toml::from_str(src).unwrap_or_else(|e| panic!("{src}: {e}"));
assert_eq!(doc.schema_version, SchemaVersion::V1);
}
let out = toml::to_string(&Doc {
schema_version: SchemaVersion::V1,
})
.expect("serialize");
assert!(out.contains("\"V1\""), "canonical output, got {out}");
}
#[test]
fn rejects_unknown_versions() {
#[derive(Deserialize, Debug)]
struct Doc {
#[allow(dead_code)]
schema_version: SchemaVersion,
}
assert!(toml::from_str::<Doc>("schema_version = 2").is_err());
assert!(toml::from_str::<Doc>(r#"schema_version = "V2""#).is_err());
}
#[test]
fn round_trips_through_postcard() {
let bytes = postcard::to_allocvec(&SchemaVersion::V1).expect("encode");
assert_eq!(
postcard::from_bytes::<SchemaVersion>(&bytes).expect("decode"),
SchemaVersion::V1
);
}
}