simple_semver/
semver.rs

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}