Skip to main content

braid_http/types/
version.rs

1//! Version identifier for the Braid-HTTP protocol.
2
3use std::hash::Hash;
4
5/// A version identifier in the Braid protocol.
6#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Deserialize)]
7#[serde(untagged)]
8pub enum Version {
9    /// String-based version ID.
10    String(String),
11    /// Integer-based version ID.
12    Integer(i64),
13}
14
15impl serde::Serialize for Version {
16    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
17    where
18        S: serde::Serializer,
19    {
20        match self {
21            Version::String(s) => serializer.serialize_str(s),
22            Version::Integer(i) => serializer.serialize_str(&i.to_string()),
23        }
24    }
25}
26
27impl Version {
28    /// Create a new string-based version.
29    #[inline]
30    #[must_use]
31    pub fn new(s: impl Into<String>) -> Self {
32        Version::String(s.into())
33    }
34
35    /// Create a new integer-based version.
36    #[inline]
37    #[must_use]
38    pub fn integer(n: i64) -> Self {
39        Version::Integer(n)
40    }
41
42    #[inline]
43    #[must_use]
44    pub fn is_string(&self) -> bool {
45        matches!(self, Version::String(_))
46    }
47
48    #[inline]
49    #[must_use]
50    pub fn is_integer(&self) -> bool {
51        matches!(self, Version::Integer(_))
52    }
53
54    #[inline]
55    #[must_use]
56    pub fn as_str(&self) -> Option<&str> {
57        match self {
58            Version::String(s) => Some(s),
59            Version::Integer(_) => None,
60        }
61    }
62
63    #[inline]
64    #[must_use]
65    pub fn as_integer(&self) -> Option<i64> {
66        match self {
67            Version::Integer(i) => Some(*i),
68            Version::String(_) => None,
69        }
70    }
71
72    #[must_use]
73    pub fn to_json(&self) -> serde_json::Value {
74        match self {
75            Version::String(s) => serde_json::Value::String(s.clone()),
76            Version::Integer(i) => serde_json::Value::String(i.to_string()),
77        }
78    }
79
80    #[must_use]
81    pub fn from_json(value: serde_json::Value) -> Self {
82        match value {
83            serde_json::Value::String(s) => Version::String(s),
84            serde_json::Value::Number(n) => {
85                if let Some(i) = n.as_i64() {
86                    Version::Integer(i)
87                } else {
88                    Version::String(n.to_string())
89                }
90            }
91            v => Version::String(v.to_string()),
92        }
93    }
94}
95
96impl std::fmt::Display for Version {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        match self {
99            Version::String(s) => write!(f, "{}", s),
100            Version::Integer(i) => write!(f, "{}", i),
101        }
102    }
103}
104
105impl From<String> for Version {
106    #[inline]
107    fn from(s: String) -> Self {
108        Version::String(s)
109    }
110}
111
112impl From<&str> for Version {
113    #[inline]
114    fn from(s: &str) -> Self {
115        Version::String(s.to_string())
116    }
117}
118
119impl From<i64> for Version {
120    #[inline]
121    fn from(n: i64) -> Self {
122        Version::Integer(n)
123    }
124}
125
126impl From<i32> for Version {
127    #[inline]
128    fn from(n: i32) -> Self {
129        Version::Integer(n as i64)
130    }
131}
132
133impl Default for Version {
134    fn default() -> Self {
135        Version::String(String::new())
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn test_version_new() {
145        let v = Version::new("abc123");
146        assert_eq!(v, Version::String("abc123".to_string()));
147    }
148
149    #[test]
150    fn test_version_integer() {
151        let v = Version::integer(42);
152        assert_eq!(v, Version::Integer(42));
153    }
154
155    #[test]
156    fn test_version_display_string() {
157        let v = Version::String("v1".to_string());
158        assert_eq!(v.to_string(), "v1");
159    }
160
161    #[test]
162    fn test_version_display_integer() {
163        let v = Version::Integer(42);
164        assert_eq!(v.to_string(), "42");
165    }
166
167    #[test]
168    fn test_version_from_str() {
169        let v: Version = "v1".into();
170        assert_eq!(v, Version::String("v1".to_string()));
171    }
172
173    #[test]
174    fn test_version_from_string() {
175        let v: Version = String::from("v1").into();
176        assert_eq!(v, Version::String("v1".to_string()));
177    }
178
179    #[test]
180    fn test_version_from_i64() {
181        let v: Version = 42i64.into();
182        assert_eq!(v, Version::Integer(42));
183    }
184
185    #[test]
186    fn test_version_from_i32() {
187        let v: Version = 42i32.into();
188        assert_eq!(v, Version::Integer(42));
189    }
190
191    #[test]
192    fn test_is_string() {
193        assert!(Version::new("abc").is_string());
194        assert!(!Version::Integer(42).is_string());
195    }
196
197    #[test]
198    fn test_is_integer() {
199        assert!(Version::Integer(42).is_integer());
200        assert!(!Version::new("abc").is_integer());
201    }
202
203    #[test]
204    fn test_as_str() {
205        let v = Version::new("abc");
206        assert_eq!(v.as_str(), Some("abc"));
207
208        let v = Version::Integer(42);
209        assert_eq!(v.as_str(), None);
210    }
211
212    #[test]
213    fn test_as_integer() {
214        let v = Version::Integer(42);
215        assert_eq!(v.as_integer(), Some(42));
216
217        let v = Version::new("abc");
218        assert_eq!(v.as_integer(), None);
219    }
220
221    #[test]
222    fn test_to_json_string() {
223        let v = Version::new("abc");
224        assert_eq!(v.to_json(), serde_json::json!("abc"));
225    }
226
227    #[test]
228    fn test_to_json_integer() {
229        let v = Version::Integer(42);
230        assert_eq!(v.to_json(), serde_json::json!("42"));
231    }
232
233    #[test]
234    fn test_from_json_string() {
235        let v = Version::from_json(serde_json::json!("abc"));
236        assert_eq!(v, Version::String("abc".to_string()));
237    }
238
239    #[test]
240    fn test_from_json_integer() {
241        let v = Version::from_json(serde_json::json!(42));
242        assert_eq!(v, Version::Integer(42));
243    }
244
245    #[test]
246    fn test_version_hash() {
247        use std::collections::HashSet;
248        let mut set = HashSet::new();
249        set.insert(Version::new("v1"));
250        set.insert(Version::new("v2"));
251        set.insert(Version::Integer(1));
252        assert_eq!(set.len(), 3);
253    }
254
255    #[test]
256    fn test_version_default() {
257        let v = Version::default();
258        assert_eq!(v, Version::String(String::new()));
259    }
260}