1use crate::*;
2
3impl fmt::Display for VersionError {
5 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15 match self {
16 VersionError::ParseError(msg) => write!(f, "Parse error: {msg}"),
17 VersionError::InvalidRangeFormat => {
18 write!(f, "Unsupported range format, only '^' or '~' are supported")
19 }
20 VersionError::MajorVersionError => write!(f, "Major version parsing error"),
21 VersionError::MinorVersionError => write!(f, "Minor version parsing error"),
22 VersionError::PatchVersionError => write!(f, "Patch version parsing error"),
23 }
24 }
25}
26
27impl Version {
28 pub(crate) fn parse(version: &str) -> Result<Self, VersionError> {
38 let mut parts: Vec<&str> = version.split('.').collect();
39 let (patch_part, pre_release) = if let Some(patch_with_prerelease) = parts.pop() {
40 let mut patch_parts = patch_with_prerelease.splitn(2, '-');
41 (
42 patch_parts.next().unwrap_or(""),
43 patch_parts.next().map(|s| s.to_string()),
44 )
45 } else {
46 return Err(VersionError::ParseError(
47 "Version format error, should be in the form 'x.y.z'.".to_string(),
48 ));
49 };
50 let major: u32 = parts
51 .first()
52 .unwrap_or(&"0")
53 .parse::<u32>()
54 .map_err(|_| VersionError::MajorVersionError)?;
55 let minor: u32 = parts
56 .get(1)
57 .unwrap_or(&"0")
58 .parse::<u32>()
59 .map_err(|_| VersionError::MinorVersionError)?;
60 let patch: u32 = patch_part
61 .parse::<u32>()
62 .map_err(|_| VersionError::PatchVersionError)?;
63 Ok(Self {
64 major,
65 minor,
66 patch,
67 pre_release,
68 })
69 }
70}
71
72impl CompareVersion {
73 pub fn compare_version(version1: &str, version2: &str) -> Result<VersionLevel, VersionError> {
84 let v1: Version = Version::parse(version1)?;
85 let v2: Version = Version::parse(version2)?;
86 match v1.cmp(&v2) {
87 std::cmp::Ordering::Greater => Ok(VersionLevel::Greater),
88 std::cmp::Ordering::Less => Ok(VersionLevel::Less),
89 std::cmp::Ordering::Equal => Ok(VersionLevel::Equal),
90 }
91 }
92
93 pub fn matches_version_range(version: &str, range: &str) -> Result<bool, VersionError> {
104 let target_version: Version = Version::parse(version)?;
105 if let Some(stripped_range) = range.strip_prefix('^') {
106 let base_version = Version::parse(stripped_range)?;
107 Ok(target_version.major == base_version.major
109 && (target_version.minor > base_version.minor
110 || (target_version.minor == base_version.minor
111 && target_version >= base_version)))
112 } else if let Some(stripped_range) = range.strip_prefix('~') {
113 let base_version: Version = Version::parse(stripped_range)?;
114 Ok(target_version.major == base_version.major
116 && target_version.minor == base_version.minor
117 && target_version >= base_version)
118 } else {
119 Err(VersionError::InvalidRangeFormat)
120 }
121 }
122}