1
Fork 0
mirror of https://github.com/RGBCube/dix synced 2025-07-28 04:07:46 +00:00

util: Replace regex with custom iterator

This commit is contained in:
Dragyx 2025-05-07 12:49:22 +02:00 committed by Bloxx12
parent 006a9b3a60
commit da723c704f

View file

@ -1,8 +1,6 @@
use regex::Regex;
use std::cmp::Ordering;
use std::sync::OnceLock;
#[derive(Eq, PartialEq)]
#[derive(Eq, PartialEq, Debug)]
enum VersionComponent {
Number(u64),
Text(String),
@ -30,30 +28,93 @@ impl PartialOrd for VersionComponent {
}
}
// 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 str,
pos: usize,
}
impl<'a> VersionComponentIterator<'a> {
pub fn new<I: Into<&'a str>>(v: I) -> Self {
Self {
v: v.into(),
pos: 0,
}
}
}
impl Iterator for VersionComponentIterator<'_> {
type Item = VersionComponent;
fn next(&mut self) -> Option<Self::Item> {
// check if there is something left
if self.pos >= self.v.len() {
return None;
}
// skip all '-' and '.' in the beginning
let mut skipped_chars = 0;
let mut chars = self.v[self.pos..].chars().peekable();
while let Some('.' | '-') = chars.peek() {
skipped_chars += 1;
chars.next();
}
// get the next character and decide if it is a digit or char
let c = chars.peek()?;
let is_digit = c.is_ascii_digit();
// based on this collect characters after this into the component
let component: String = chars
.take_while(|&c| c.is_ascii_digit() == is_digit && c != '.' && c != '-')
.collect();
// remember what chars we used
self.pos += component.len() + skipped_chars;
if component.is_empty() {
None
} else if is_digit {
component.parse::<u64>().ok().map(VersionComponent::Number)
} else {
Some(VersionComponent::Text(component))
}
}
}
/// 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 = version_split_regex().find_iter(a).map(|m| {
use VersionComponent::{Number, Text};
let bla = m.as_str();
bla.parse().map_or_else(|_| Text(bla.to_string()), Number)
});
let iter_b = version_split_regex().find_iter(b).map(|m| {
use VersionComponent::{Number, Text};
let bla = m.as_str();
bla.parse().map_or_else(|_| Text(bla.to_string()), Number)
});
let iter_a = VersionComponentIterator::new(a);
let iter_b = VersionComponentIterator::new(b);
iter_a.cmp(iter_b)
}
fn version_split_regex() -> &'static Regex {
static REGEX: OnceLock<Regex> = OnceLock::new();
REGEX.get_or_init(|| {
Regex::new(r"(\d+|[a-zA-Z]+)").expect("Failed to compile regex pattern for nix store paths")
})
mod test {
#[test]
fn test_version_component_iter() {
use super::VersionComponent::{Number, Text};
use crate::util::VersionComponentIterator;
let v = "132.1.2test234-1-man----.--.......---------..---";
let comp: Vec<_> = VersionComponentIterator::new(v).collect();
assert_eq!(
comp,
[
Number(132),
Number(1),
Number(2),
Text("test".into()),
Number(234),
Number(1),
Text("man".into())
]
);
}
}