version_spec/
version_types.rs1use crate::get_calver_regex;
2use crate::spec_error::SpecError;
3use semver::Version;
4use serde::{Deserialize, Serialize};
5use std::fmt;
6use std::ops::Deref;
7
8#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
10pub struct SemVer(pub Version);
11
12impl SemVer {
13 pub fn parse(value: &str) -> Result<Self, SpecError> {
15 Ok(Self(Version::parse(value)?))
16 }
17}
18
19impl Deref for SemVer {
20 type Target = Version;
21
22 fn deref(&self) -> &Self::Target {
23 &self.0
24 }
25}
26
27impl fmt::Display for SemVer {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 write!(f, "{}", self.0)
30 }
31}
32
33#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
35pub struct CalVer(pub Version);
36
37impl CalVer {
38 pub fn parse(value: &str) -> Result<Self, SpecError> {
42 let Some(caps) = get_calver_regex().captures(value) else {
43 return Err(SpecError::InvalidCalverFormat);
44 };
45
46 let year = caps
50 .name("year")
51 .map(|cap| cap.as_str().trim_start_matches('0'))
52 .unwrap_or("0");
53 let mut year_no: usize = year.parse().unwrap();
54
55 if year.len() < 4 {
56 year_no += 2000;
57 }
58
59 let month = caps
63 .name("month")
64 .map(|cap| cap.as_str().trim_start_matches('0'))
65 .unwrap_or("0");
66
67 let day = caps
68 .name("day")
69 .map(|cap| cap.as_str().trim_start_matches('0'))
70 .unwrap_or("0");
71
72 let mut version = format!("{year_no}.{month}.{day}");
73
74 if let Some(pre) = caps.name("pre") {
75 version.push_str(pre.as_str());
76 }
77
78 if let Some(micro) = caps.name("micro") {
79 version.push('+');
80 version.push_str(micro.as_str());
81 }
82
83 Ok(Self(Version::parse(&version)?))
84 }
85}
86
87impl Deref for CalVer {
88 type Target = Version;
89
90 fn deref(&self) -> &Self::Target {
91 &self.0
92 }
93}
94
95impl fmt::Display for CalVer {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 let version = &self.0;
98
99 write!(f, "{:0>4}-{:0>2}", version.major, version.minor)?;
100
101 if version.patch > 0 {
102 write!(f, "-{:0>2}", version.patch)?;
103 }
104
105 if !version.build.is_empty() {
107 write!(f, ".{}", version.build)?;
108 }
109
110 if !version.pre.is_empty() {
111 write!(f, "-{}", version.pre)?;
112 }
113
114 Ok(())
115 }
116}