summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Turner <jturner.usa@gmail.com>2025-11-13 18:03:34 +0000
committerJohn Turner <jturner.usa@gmail.com>2025-11-13 18:03:34 +0000
commit1882ce3137e246aaa145568c6ba405f1be3f3a53 (patch)
tree04693f304160a720fa57b2d869a78b75e9e767ba
parentf4a45717d2bc952a545f7cee28e941a65744604b (diff)
downloadgentoo-utils-1882ce3137e246aaa145568c6ba405f1be3f3a53.tar.gz
impl Cpv type
-rw-r--r--src/atom/mod.rs49
-rw-r--r--src/atom/parsers.rs17
2 files changed, 65 insertions, 1 deletions
diff --git a/src/atom/mod.rs b/src/atom/mod.rs
index 0dea415..0d1d3a9 100644
--- a/src/atom/mod.rs
+++ b/src/atom/mod.rs
@@ -108,6 +108,13 @@ pub struct UseDep {
condition: Option<UseDepCondition>,
}
+#[derive(Clone, Debug, PartialEq, Eq, Get)]
+pub struct Cpv {
+ category: Category,
+ name: Name,
+ version: Version,
+}
+
#[derive(Clone, Debug, Get, PartialEq, Eq)]
pub struct Atom {
blocker: Option<Blocker>,
@@ -361,6 +368,16 @@ impl Ord for Version {
}
}
+impl PartialOrd for Cpv {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ if self.category == other.category && self.name == other.name {
+ Some(self.version.cmp(&other.version))
+ } else {
+ None
+ }
+ }
+}
+
impl fmt::Display for Blocker {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
@@ -541,6 +558,12 @@ impl fmt::Display for UseDep {
}
}
+impl fmt::Display for Cpv {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}/{}-{}", &self.category, &self.name, &self.version)
+ }
+}
+
impl fmt::Display for Atom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(blocker) = self.blocker.as_ref() {
@@ -602,6 +625,14 @@ mod test {
};
}
+ macro_rules! assert_partial_cmp_display {
+ ($a:expr, $b:expr, $ordering:expr) => {
+ if $a.partial_cmp(&$b) != $ordering {
+ panic!("{} ~ {} != {:?}", $a, $b, $ordering)
+ }
+ };
+ }
+
#[test]
fn test_version_display() {
let s = "1.0.0_alpha1_beta1-r1";
@@ -670,4 +701,22 @@ mod test {
assert_cmp_display!(a, b, *ordering);
}
}
+
+ #[test]
+ fn test_cpv_eq() {
+ let cpvs = [
+ ("foo/bar-1", "foo/bar-1", Some(Ordering::Equal)),
+ ("foo/baz-1", "foo/bar-1", None),
+ ];
+
+ for (a, b, ordering) in cpvs.iter().copied().map(|(a, b, ordering)| {
+ (
+ Cpv::parser().parse_finished(InputIter::new(a)).unwrap(),
+ Cpv::parser().parse_finished(InputIter::new(b)).unwrap(),
+ ordering,
+ )
+ }) {
+ assert_partial_cmp_display!(a, b, ordering);
+ }
+ }
}
diff --git a/src/atom/parsers.rs b/src/atom/parsers.rs
index 0f95d16..9d3cb15 100644
--- a/src/atom/parsers.rs
+++ b/src/atom/parsers.rs
@@ -5,7 +5,7 @@ use mon::{Parser, ParserIter, r#if, numeric1, one_of, tag};
use crate::{
Parseable,
atom::{
- Atom, Blocker, Category, Name, Slot, SlotName, SlotOperator, UseDep, UseDepCondition,
+ Atom, Blocker, Category, Cpv, Name, Slot, SlotName, SlotOperator, UseDep, UseDepCondition,
UseDepNegate, UseDepSign, Version, VersionNumber, VersionNumbers, VersionOperator,
VersionSuffix, VersionSuffixKind, VersionSuffixes,
},
@@ -334,6 +334,21 @@ impl<'a> Parseable<'a, &'a str> for Atom {
}
}
+impl<'a> Parseable<'a, &'a str> for Cpv {
+ type Parser = impl Parser<&'a str, Output = Self>;
+
+ fn parser() -> Self::Parser {
+ Category::parser()
+ .and(Name::parser().preceded_by(tag("/")))
+ .and(Version::parser().preceded_by(tag("-")))
+ .map(|((category, name), version)| Cpv {
+ category,
+ name,
+ version,
+ })
+ }
+}
+
#[cfg(test)]
mod test {