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::cmp::Ordering;
|
||||||
use std::sync::OnceLock;
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
enum VersionComponent {
|
enum VersionComponent {
|
||||||
Number(u64),
|
Number(u64),
|
||||||
Text(String),
|
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.
|
/// Compares two strings of package versions, and figures out the greater one.
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// * Ordering
|
/// * Ordering
|
||||||
pub fn compare_versions(a: &str, b: &str) -> Ordering {
|
pub fn compare_versions(a: &str, b: &str) -> Ordering {
|
||||||
let iter_a = version_split_regex().find_iter(a).map(|m| {
|
let iter_a = VersionComponentIterator::new(a);
|
||||||
use VersionComponent::{Number, Text};
|
let iter_b = VersionComponentIterator::new(b);
|
||||||
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)
|
|
||||||
});
|
|
||||||
|
|
||||||
iter_a.cmp(iter_b)
|
iter_a.cmp(iter_b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version_split_regex() -> &'static Regex {
|
mod test {
|
||||||
static REGEX: OnceLock<Regex> = OnceLock::new();
|
|
||||||
REGEX.get_or_init(|| {
|
#[test]
|
||||||
Regex::new(r"(\d+|[a-zA-Z]+)").expect("Failed to compile regex pattern for nix store paths")
|
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