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:
parent
574142c4a0
commit
af7f63d3f6
1 changed files with 35 additions and 57 deletions
92
src/util.rs
92
src/util.rs
|
@ -18,6 +18,7 @@ type Result<T> = std::result::Result<T, AppError>;
|
|||
use std::string::ToString;
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
enum VersionComponent {
|
||||
Number(u64),
|
||||
Text(String),
|
||||
|
@ -29,72 +30,53 @@ impl std::cmp::Ord for VersionComponent {
|
|||
Number,
|
||||
Text,
|
||||
};
|
||||
|
||||
match (self, other) {
|
||||
(Number(x), Number(y)) => x.cmp(y),
|
||||
(Text(x), Text(y)) => {
|
||||
match (x.as_str(), y.as_str()) {
|
||||
("pre", _) => Ordering::Less,
|
||||
(_, "pre") => Ordering::Greater,
|
||||
("pre", _) => cmp::Ordering::Less,
|
||||
(_, "pre") => cmp::Ordering::Greater,
|
||||
_ => x.cmp(y),
|
||||
}
|
||||
},
|
||||
(Text(_), Number(_)) => Ordering::Less,
|
||||
(Number(_), Text(_)) => Ordering::Greater,
|
||||
(Text(_), Number(_)) => cmp::Ordering::Less,
|
||||
(Number(_), Text(_)) => cmp::Ordering::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for VersionComponent {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
/// Yields [`VertionComponent`] from a version string.
|
||||
#[derive(Deref, DerefMut, From)]
|
||||
struct VersionComponentIter<'a>(&'a str);
|
||||
|
||||
// takes a version string and outputs the different components
|
||||
//
|
||||
// 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<'_> {
|
||||
impl Iterator for VersionComponentIter<'_> {
|
||||
type Item = VersionComponent;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// skip all '-' and '.' in the beginning
|
||||
while let Some(b'.' | b'-') = self.v.get(self.pos) {
|
||||
self.pos += 1;
|
||||
// Skip all '-' and '.'.
|
||||
while self.starts_with(['.', '-']) {
|
||||
**self = &self[1..];
|
||||
}
|
||||
|
||||
// get the next character and decide if it is a digit or char
|
||||
let c = self.v.get(self.pos)?;
|
||||
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();
|
||||
// Get the next character and decide if it is a digit.
|
||||
let is_digit = self.chars().next()?.is_ascii_digit();
|
||||
|
||||
// remember what chars we used
|
||||
self.pos += component_len;
|
||||
// Based on this collect characters after this into the component.
|
||||
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() {
|
||||
None
|
||||
} else if is_digit {
|
||||
let component = self[..component_len].to_owned();
|
||||
**self = &self[component_len..];
|
||||
|
||||
assert!(!component.is_empty());
|
||||
|
||||
if is_digit {
|
||||
component.parse::<u64>().ok().map(VersionComponent::Number)
|
||||
} else {
|
||||
Some(VersionComponent::Text(component))
|
||||
|
@ -103,15 +85,11 @@ impl Iterator for VersionComponentIterator<'_> {
|
|||
}
|
||||
|
||||
/// Compares two strings of package versions, and figures out the greater one.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * Ordering
|
||||
pub fn compare_versions(a: &str, b: &str) -> Ordering {
|
||||
let iter_a = VersionComponentIterator::new(a);
|
||||
let iter_b = VersionComponentIterator::new(b);
|
||||
pub fn compare_versions(this: &str, that: &str) -> cmp::Ordering {
|
||||
let this = VersionComponentIter::from(this);
|
||||
let that = VersionComponentIter::from(that);
|
||||
|
||||
iter_a.cmp(iter_b)
|
||||
this.cmp(that)
|
||||
}
|
||||
|
||||
/// Parses a nix store path to extract the packages name and version
|
||||
|
@ -244,10 +222,10 @@ mod test {
|
|||
Number,
|
||||
Text,
|
||||
};
|
||||
use crate::util::VersionComponentIterator;
|
||||
use crate::util::VersionComponentIter;
|
||||
let v = "132.1.2test234-1-man----.--.......---------..---";
|
||||
|
||||
let comp: Vec<_> = VersionComponentIterator::new(v).collect();
|
||||
let comp: Vec<_> = VersionComponentIter::new(v).collect();
|
||||
assert_eq!(comp, [
|
||||
Number(132),
|
||||
Number(1),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue