1
Fork 0
mirror of https://github.com/RGBCube/dix synced 2025-09-13 03:07:59 +00:00

feat: refactor version comparisions

This commit is contained in:
RGBCube 2025-05-08 22:40:25 +03:00 committed by bloxx12
parent 574142c4a0
commit af7f63d3f6

View file

@ -18,6 +18,7 @@ type Result<T> = std::result::Result<T, AppError>;
use std::string::ToString; use std::string::ToString;
#[derive(Eq, PartialEq, Debug)] #[derive(Eq, PartialEq, Debug)]
#[derive(Debug, Clone, Eq, PartialEq)]
enum VersionComponent { enum VersionComponent {
Number(u64), Number(u64),
Text(String), Text(String),
@ -29,72 +30,53 @@ impl std::cmp::Ord for VersionComponent {
Number, Number,
Text, Text,
}; };
match (self, other) { match (self, other) {
(Number(x), Number(y)) => x.cmp(y), (Number(x), Number(y)) => x.cmp(y),
(Text(x), Text(y)) => { (Text(x), Text(y)) => {
match (x.as_str(), y.as_str()) { match (x.as_str(), y.as_str()) {
("pre", _) => Ordering::Less, ("pre", _) => cmp::Ordering::Less,
(_, "pre") => Ordering::Greater, (_, "pre") => cmp::Ordering::Greater,
_ => x.cmp(y), _ => x.cmp(y),
} }
}, },
(Text(_), Number(_)) => Ordering::Less, (Text(_), Number(_)) => cmp::Ordering::Less,
(Number(_), Text(_)) => Ordering::Greater, (Number(_), Text(_)) => cmp::Ordering::Greater,
} }
} }
} }
impl PartialOrd for VersionComponent { /// Yields [`VertionComponent`] from a version string.
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { #[derive(Deref, DerefMut, From)]
Some(self.cmp(other)) struct VersionComponentIter<'a>(&'a str);
}
}
// takes a version string and outputs the different components impl Iterator for VersionComponentIter<'_> {
//
// a component is delimited by '-' or '.' and consists of just digits or letters
struct VersionComponentIterator<'a> {
v: &'a [u8],
pos: usize,
}
impl<'a> VersionComponentIterator<'a> {
pub fn new<I: Into<&'a str>>(v: I) -> Self {
Self {
v: v.into().as_bytes(),
pos: 0,
}
}
}
impl Iterator for VersionComponentIterator<'_> {
type Item = VersionComponent; type Item = VersionComponent;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
// skip all '-' and '.' in the beginning // Skip all '-' and '.'.
while let Some(b'.' | b'-') = self.v.get(self.pos) { while self.starts_with(['.', '-']) {
self.pos += 1; **self = &self[1..];
} }
// get the next character and decide if it is a digit or char // Get the next character and decide if it is a digit.
let c = self.v.get(self.pos)?; let is_digit = self.chars().next()?.is_ascii_digit();
let is_digit = c.is_ascii_digit();
// based on this collect characters after this into the component
let component_len = self.v[self.pos..]
.iter()
.copied()
.take_while(|&c| c.is_ascii_digit() == is_digit && c != b'.' && c != b'-')
.count();
let component =
String::from_utf8_lossy(&self.v[self.pos..(self.pos + component_len)])
.into_owned();
// remember what chars we used // Based on this collect characters after this into the component.
self.pos += component_len; let component_len = self
.chars()
.take_while(|&c| {
c.is_ascii_digit() == is_digit && !matches!(c, '.' | '-')
})
.map(char::len_utf8)
.sum();
if component.is_empty() { let component = self[..component_len].to_owned();
None **self = &self[component_len..];
} else if is_digit {
assert!(!component.is_empty());
if is_digit {
component.parse::<u64>().ok().map(VersionComponent::Number) component.parse::<u64>().ok().map(VersionComponent::Number)
} else { } else {
Some(VersionComponent::Text(component)) Some(VersionComponent::Text(component))
@ -103,15 +85,11 @@ impl Iterator for VersionComponentIterator<'_> {
} }
/// Compares two strings of package versions, and figures out the greater one. /// Compares two strings of package versions, and figures out the greater one.
/// pub fn compare_versions(this: &str, that: &str) -> cmp::Ordering {
/// # Returns let this = VersionComponentIter::from(this);
/// let that = VersionComponentIter::from(that);
/// * Ordering
pub fn compare_versions(a: &str, b: &str) -> Ordering {
let iter_a = VersionComponentIterator::new(a);
let iter_b = VersionComponentIterator::new(b);
iter_a.cmp(iter_b) this.cmp(that)
} }
/// Parses a nix store path to extract the packages name and version /// Parses a nix store path to extract the packages name and version
@ -244,10 +222,10 @@ mod test {
Number, Number,
Text, Text,
}; };
use crate::util::VersionComponentIterator; use crate::util::VersionComponentIter;
let v = "132.1.2test234-1-man----.--.......---------..---"; let v = "132.1.2test234-1-man----.--.......---------..---";
let comp: Vec<_> = VersionComponentIterator::new(v).collect(); let comp: Vec<_> = VersionComponentIter::new(v).collect();
assert_eq!(comp, [ assert_eq!(comp, [
Number(132), Number(132),
Number(1), Number(1),