citum_schema_style/
version.rs1#[cfg(doc)]
9use crate::Style;
10#[cfg(feature = "schema")]
11use schemars::JsonSchema;
12
13pub const STYLE_SCHEMA_VERSION: &str = "0.64.0";
15
16pub const MAX_TEMPLATE_NESTING_DEPTH: usize = 64;
18
19pub const MAX_TEMPLATE_COMPONENTS: usize = 16_384;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24#[cfg_attr(feature = "schema", derive(JsonSchema), schemars(with = "String"))]
25pub struct SchemaVersion {
26 pub major: u32,
28 pub minor: Option<u32>,
30 pub patch: Option<u32>,
32}
33
34impl SchemaVersion {
35 pub fn parse(s: &str) -> Result<Self, String> {
44 let parts: Vec<&str> = s.split('.').collect();
45 if parts.len() < 2 || parts.len() > 3 {
46 return Err(format!(
47 "invalid version format (expected X.Y or X.Y.Z): \"{}\"",
48 s
49 ));
50 }
51
52 let major_str = parts
53 .first()
54 .ok_or_else(|| "missing major version".to_string())?;
55 let major = major_str
56 .parse::<u32>()
57 .map_err(|_| format!("invalid major version: \"{}\"", major_str))?;
58
59 let minor_str = parts
60 .get(1)
61 .ok_or_else(|| "missing minor version".to_string())?;
62 let minor = Some(
63 minor_str
64 .parse::<u32>()
65 .map_err(|_| format!("invalid minor version: \"{}\"", minor_str))?,
66 );
67
68 let patch = if let Some(patch_str) = parts.get(2) {
69 Some(
70 patch_str
71 .parse::<u32>()
72 .map_err(|_| format!("invalid patch version: \"{}\"", patch_str))?,
73 )
74 } else {
75 None
76 };
77
78 Ok(SchemaVersion {
79 major,
80 minor,
81 patch,
82 })
83 }
84}
85
86impl PartialOrd for SchemaVersion {
87 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
88 Some(self.cmp(other))
89 }
90}
91
92impl Ord for SchemaVersion {
93 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
94 match self.major.cmp(&other.major) {
95 std::cmp::Ordering::Equal => {
96 let self_minor = self.minor.unwrap_or(0);
97 let other_minor = other.minor.unwrap_or(0);
98 match self_minor.cmp(&other_minor) {
99 std::cmp::Ordering::Equal => {
100 let self_patch = self.patch.unwrap_or(0);
101 let other_patch = other.patch.unwrap_or(0);
102 self_patch.cmp(&other_patch)
103 }
104 ord => ord,
105 }
106 }
107 ord => ord,
108 }
109 }
110}
111
112impl std::fmt::Display for SchemaVersion {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 write!(f, "{}", self.major)?;
115 if let Some(minor) = self.minor {
116 write!(f, ".{}", minor)?;
117 if let Some(patch) = self.patch {
118 write!(f, ".{}", patch)?;
119 }
120 }
121 Ok(())
122 }
123}
124
125impl Default for SchemaVersion {
126 #[allow(
127 clippy::expect_used,
128 reason = "STYLE_SCHEMA_VERSION is a canonical constant"
129 )]
130 fn default() -> Self {
131 SchemaVersion::parse(STYLE_SCHEMA_VERSION).expect("STYLE_SCHEMA_VERSION is valid")
132 }
133}
134
135impl<'de> serde::Deserialize<'de> for SchemaVersion {
136 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
137 where
138 D: serde::Deserializer<'de>,
139 {
140 let s = <String as serde::Deserialize>::deserialize(deserializer)?;
141 SchemaVersion::parse(&s).map_err(serde::de::Error::custom)
142 }
143}
144
145impl serde::Serialize for SchemaVersion {
146 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
147 where
148 S: serde::Serializer,
149 {
150 serializer.serialize_str(&self.to_string())
151 }
152}