holodeck_simctl_core/models/
semantic_version.rs1use std::cmp::Ordering;
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub struct SemanticVersion {
6 pub major: i64,
7 pub minor: i64,
8 pub patch: i64,
9}
10
11impl SemanticVersion {
12 pub fn new(major: i64, minor: i64, patch: i64) -> Self {
13 Self { major, minor, patch }
14 }
15
16 pub fn parse(string: &str) -> Option<Self> {
19 let parts: Vec<&str> = string.split('.').collect();
20 let major = parts.first()?.parse::<i64>().ok()?;
21 let minor = parts.get(1).and_then(|p| p.parse::<i64>().ok()).unwrap_or(0);
22 let patch = parts.get(2).and_then(|p| p.parse::<i64>().ok()).unwrap_or(0);
23 Some(Self { major, minor, patch })
24 }
25}
26
27impl PartialOrd for SemanticVersion {
28 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
29 Some(self.cmp(other))
30 }
31}
32
33impl Ord for SemanticVersion {
34 fn cmp(&self, other: &Self) -> Ordering {
35 self.major.cmp(&other.major).then(self.minor.cmp(&other.minor)).then(self.patch.cmp(&other.patch))
36 }
37}
38
39impl fmt::Display for SemanticVersion {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 if self.patch == 0 {
42 write!(f, "{}.{}", self.major, self.minor)
43 } else {
44 write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
45 }
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn parses_major_minor_patch() {
55 assert_eq!(SemanticVersion::parse("18.4.1"), Some(SemanticVersion::new(18, 4, 1)));
56 }
57
58 #[test]
59 fn defaults_missing_components_to_zero() {
60 assert_eq!(SemanticVersion::parse("18"), Some(SemanticVersion::new(18, 0, 0)));
61 }
62
63 #[test]
64 fn rejects_unparseable_major() {
65 assert_eq!(SemanticVersion::parse("x.4"), None);
66 }
67
68 #[test]
69 fn display_omits_zero_patch() {
70 assert_eq!(SemanticVersion::new(26, 4, 0).to_string(), "26.4");
71 assert_eq!(SemanticVersion::new(26, 4, 1).to_string(), "26.4.1");
72 }
73
74 #[test]
75 fn orders_by_major_then_minor_then_patch() {
76 assert!(SemanticVersion::new(18, 0, 0) < SemanticVersion::new(18, 1, 0));
77 assert!(SemanticVersion::new(17, 9, 9) < SemanticVersion::new(18, 0, 0));
78 }
79}