mirror of
https://github.com/RGBCube/dix
synced 2025-07-28 12:17:45 +00:00
util: Replace regex with custom iterator
This commit is contained in:
parent
006a9b3a60
commit
da723c704f
1 changed files with 80 additions and 19 deletions
99
src/util.rs
99
src/util.rs
|
@ -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())
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue