From 1882ce3137e246aaa145568c6ba405f1be3f3a53 Mon Sep 17 00:00:00 2001 From: John Turner Date: Thu, 13 Nov 2025 18:03:34 +0000 Subject: [PATCH] impl Cpv type --- src/atom/mod.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++ src/atom/parsers.rs | 17 +++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) 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, } +#[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, @@ -361,6 +368,16 @@ impl Ord for Version { } } +impl PartialOrd for Cpv { + fn partial_cmp(&self, other: &Self) -> Option { + 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 {