1use std::num::ParseIntError;
2
3use regex::Regex;
4
5use crate::{
6 change::ChangeType,
7 errors::{CheckError, ParseError},
8 SemVerChangeID,
9};
10
11#[derive(Debug, Clone, Copy, Eq, PartialEq)]
12pub struct SemVer {
13 pub major: i32,
14 pub minor: i32,
15 pub patch: Option<i32>,
16 pub change: Option<SemVerChangeID>,
17}
18
19unsafe impl Send for SemVer {}
20unsafe impl Sync for SemVer {}
21
22impl SemVer {
23 pub fn from_many(versions: Vec<&str>) -> Result<Vec<SemVer>, ParseError> {
24 let mut semvers: Vec<SemVer> = Vec::new();
25
26 for version in versions {
27 let semver = SemVer::from(version);
28
29 if semver.is_err() {
30 return Err(semver.unwrap_err());
31 }
32
33 semvers.push(semver.unwrap());
34 }
35
36 return Ok(semvers);
37 }
38
39 pub fn from(version: &str) -> Result<SemVer, ParseError> {
40 let rx = Regex::new(r#"(?i)([0-9]+)\.([0-9]+)\.?([0-9]+)?-?((?:alpha|beta)?\.?[0-9]+)?"#)
41 .unwrap();
42
43 let matches = rx.captures(version);
44
45 match matches {
46 Some(result) => {
47 let major_res = result.get(1);
48 let minor_res = result.get(2);
49 let patch_res = result.get(3);
50 let change_res = result.get(4);
51
52 if major_res.is_none() || minor_res.is_none() {
53 return Err(ParseError::InvalidSemver);
54 }
55
56 let major_str = major_res.unwrap();
57 let minor_str = minor_res.unwrap();
58
59 let major_parse: Result<i32, ParseIntError> = major_str.as_str().parse::<i32>();
60 let minor_parse: Result<i32, ParseIntError> = minor_str.as_str().parse::<i32>();
61
62 if major_parse.is_err() || minor_parse.is_err() {
63 return Err(ParseError::InvalidNumber);
64 }
65
66 let major = major_parse.unwrap();
67 let minor = minor_parse.unwrap();
68 let mut patch: Option<i32> = None;
69 let mut change: Option<SemVerChangeID> = None;
70
71 if patch_res.is_some() {
72 let patch_str = patch_res.unwrap();
73 let patch_parse: Result<i32, ParseIntError> = patch_str.as_str().parse::<i32>();
74
75 if patch_parse.is_err() {
76 return Err(ParseError::InvalidNumber);
77 }
78
79 patch = Some(patch_parse.unwrap());
80 }
81
82 if change_res.is_some() {
83 let change_str = change_res.unwrap().as_str().to_lowercase();
84 let change_str_id = change_str
85 .replace("alpha", "")
86 .replace("beta", "")
87 .replace(".", "");
88 let change_parse: Result<i32, ParseIntError> = change_str_id.parse::<i32>();
89
90 if change_parse.is_err() {
91 return Err(ParseError::InvalidNumber);
92 }
93
94 let change_type: ChangeType;
95
96 match change_str.replace(change_str_id.as_str(), "").as_str() {
97 "alpha" | "alpha." => change_type = ChangeType::Alpha,
98 "beta" | "beta." => change_type = ChangeType::Beta,
99 _ => change_type = ChangeType::None,
100 };
101
102 let change_struct = SemVerChangeID {
103 r#type: change_type,
104 id: change_parse.unwrap(),
105 };
106
107 change = Some(change_struct);
108 }
109
110 return Ok(SemVer {
111 major,
112 minor,
113 patch,
114 change,
115 });
116 }
117
118 None => return Err(ParseError::InvalidSemver),
119 };
120 }
121
122 pub fn gt(&self, other: &SemVer) -> Result<bool, CheckError> {
123 if other.major == self.major {
124 if other.minor == self.minor {
125 if other.patch == self.patch {
126 if other.change.is_none() || self.change.is_none() {
127 return Err(CheckError::SameValue);
128 }
129
130 let other_change = other.change.unwrap();
131 let my_change = self.change.unwrap();
132
133 if other_change.eq(my_change) {
134 return Err(CheckError::SameValue);
135 } else if other_change.gt(my_change) {
136 return Ok(false);
137 } else if other_change.lt(my_change) {
138 return Ok(true);
139 }
140 } else if other.patch > self.patch {
141 return Ok(false);
142 } else if other.patch < self.patch {
143 return Ok(true);
144 }
145 } else if other.minor > self.minor {
146 return Ok(false);
147 } else if other.minor < self.minor {
148 return Ok(true);
149 }
150 } else if other.major > self.major {
151 return Ok(false);
152 } else if other.major < self.major {
153 return Ok(true);
154 }
155
156 return Err(CheckError::UnknownValues);
157 }
158
159 pub fn lt(&self, other: &SemVer) -> Result<bool, CheckError> {
160 if other.major == self.major {
161 if other.minor == self.minor {
162 if other.patch == self.patch {
163 if other.change.is_none() || self.change.is_none() {
164 return Err(CheckError::SameValue);
165 }
166
167 let other_change = other.change.unwrap();
168 let my_change = self.change.unwrap();
169
170 if other_change.eq(my_change) {
171 return Err(CheckError::SameValue);
172 } else if other_change.gt(my_change) {
173 return Ok(true);
174 } else if other_change.lt(my_change) {
175 return Ok(false);
176 }
177 } else if other.patch > self.patch {
178 return Ok(true);
179 } else if other.patch < self.patch {
180 return Ok(false);
181 }
182 } else if other.minor > self.minor {
183 return Ok(true);
184 } else if other.minor < self.minor {
185 return Ok(false);
186 }
187 } else if other.major > self.major {
188 return Ok(true);
189 } else if other.major < self.major {
190 return Ok(false);
191 }
192
193 return Err(CheckError::UnknownValues);
194 }
195
196 pub fn eq(&self, other: SemVer) -> bool {
197 let mut same_change = false;
198
199 if other.change.is_none() && self.change.is_none() {
200 same_change = true;
201 } else {
202 if other.change.is_some() && self.change.is_some() {
203 if other.change.unwrap().eq(self.change.unwrap()) {
204 same_change = true;
205 }
206 }
207 }
208
209 return other.major == self.major
210 && other.minor == self.minor
211 && other.patch == self.patch
212 && same_change;
213 }
214
215 pub fn to_string(&self) -> String {
216 let major = self.major.to_string();
217 let minor = self.minor.to_string();
218
219 if self.patch.is_some() {
220 let patch = self.patch.unwrap().to_string();
221
222 if self.change.is_some() {
223 let change = self.change.unwrap().to_string();
224
225 return format!("{}.{}.{}-{}", major, minor, patch, change);
226 }
227
228 return format!("{}.{}.{}", major, minor, patch);
229 } else if self.change.is_some() {
230 let change = self.change.unwrap().to_string();
231
232 return format!("{}.{}-{}", major, minor, change);
233 }
234
235 return format!("{}.{}", major, minor);
236 }
237}