diff options
Diffstat (limited to 'src/atom/mod.rs')
| -rw-r--r-- | src/atom/mod.rs | 772 |
1 files changed, 0 insertions, 772 deletions
diff --git a/src/atom/mod.rs b/src/atom/mod.rs deleted file mode 100644 index 24cb555..0000000 --- a/src/atom/mod.rs +++ /dev/null @@ -1,772 +0,0 @@ -use core::{ - fmt::{self}, - option::Option, -}; -use std::cmp::Ordering; - -use crate::useflag::UseFlag; - -use get::Get; - -use itertools::Itertools; - -mod parsers; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Blocker { - Weak, - Strong, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum VersionOperator { - Lt, - Gt, - Eq, - LtEq, - GtEq, - Roughly, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)] -pub struct Category(#[get(method = "get", kind = "deref")] String); - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)] -pub struct Name(#[get(method = "get", kind = "deref")] String); - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)] -pub struct VersionNumber(#[get(method = "get", kind = "deref")] String); - -#[derive(Debug, Clone, PartialEq, Eq, Hash, Get)] -struct VersionNumbers(#[get(method = "get", kind = "deref")] Vec<VersionNumber>); - -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum VersionSuffixKind { - Alpha, - Beta, - Pre, - Rc, - P, -} - -#[derive(Clone, Debug, Hash, PartialEq, Eq, Get)] -pub struct VersionSuffix { - kind: VersionSuffixKind, - number: Option<VersionNumber>, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash, Get)] -pub struct VersionSuffixes(#[get(method = "get", kind = "deref")] Vec<VersionSuffix>); - -#[derive(Debug, Clone, Get, PartialEq, Eq, Hash)] -pub struct BuildId(#[get(method = "get", kind = "deref")] String); - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)] -pub struct Version { - numbers: VersionNumbers, - letter: Option<char>, - suffixes: VersionSuffixes, - rev: Option<VersionNumber>, - build_id: Option<BuildId>, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Wildcard; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum SlotOperator { - Eq, - Star, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)] -pub struct SlotName(#[get(method = "name", kind = "deref")] String); - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum Slot { - Wildcard, - Equal, - NameEqual { - primary: SlotName, - sub: Option<SlotName>, - }, - Name { - primary: SlotName, - sub: Option<SlotName>, - }, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum UseDepNegate { - Minus, - Exclamation, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum UseDepSign { - Enabled, - Disabled, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum UseDepCondition { - Eq, - Question, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Repo(String); - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)] -pub struct UseDep { - negate: Option<UseDepNegate>, - flag: UseFlag, - sign: Option<UseDepSign>, - condition: Option<UseDepCondition>, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)] -pub struct Cp { - category: Category, - name: Name, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)] -pub struct Cpv { - category: Category, - name: Name, - version: Version, - slot: Option<Slot>, -} - -#[derive(Clone, Debug, Get, PartialEq, Eq, Hash)] -pub struct Atom { - blocker: Option<Blocker>, - category: Category, - name: Name, - version: Option<(VersionOperator, Version, Option<Wildcard>)>, - slot: Option<Slot>, - repo: Option<Repo>, - #[get(kind = "deref")] - usedeps: Vec<UseDep>, -} - -impl Cpv { - #[must_use] - pub fn into_cp(self) -> Cp { - Cp { - name: self.name, - category: self.category, - } - } -} - -impl Atom { - #[must_use] - pub fn version_operator(&self) -> Option<VersionOperator> { - self.version.clone().map(|(oper, _, _)| oper) - } - - #[must_use] - pub fn into_cp(self) -> Cp { - Cp { - category: self.category, - name: self.name, - } - } - - #[must_use] - pub fn into_cpv(self) -> Option<Cpv> { - match self.version { - Some((_, version, _)) => Some(Cpv { - category: self.category, - name: self.name, - version, - slot: self.slot, - }), - None => None, - } - } -} - -impl VersionNumber { - #[must_use] - pub fn cmp_as_ints(&self, other: &Self) -> Ordering { - let a = self.get().trim_start_matches('0'); - let b = other.get().trim_start_matches('0'); - - a.len().cmp(&b.len()).then_with(|| a.cmp(b)) - } - - #[must_use] - pub fn cmp_as_str(&self, other: &Self) -> Ordering { - if self.get().starts_with('0') || other.get().starts_with('0') { - let a = self.get().trim_end_matches('0'); - let b = other.get().trim_end_matches('0'); - - a.cmp(b) - } else { - self.cmp_as_ints(other) - } - } -} - -impl PartialOrd for BuildId { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for BuildId { - fn cmp(&self, other: &Self) -> Ordering { - // build-id may not start with a zero so we dont need to strip them - self.get() - .len() - .cmp(&other.get().len()) - .then_with(|| self.get().cmp(other.get())) - } -} - -impl PartialOrd for VersionSuffix { - fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for VersionSuffix { - fn cmp(&self, other: &Self) -> Ordering { - match &self.kind.cmp(&other.kind) { - Ordering::Less => Ordering::Less, - Ordering::Greater => Ordering::Greater, - Ordering::Equal => match (&self.number, &other.number) { - (Some(a), Some(b)) => a.cmp_as_ints(b), - (Some(a), None) if a.get().chars().all(|c| c == '0') => Ordering::Equal, - (None, Some(b)) if b.get().chars().all(|c| c == '0') => Ordering::Equal, - (Some(_), None) => Ordering::Greater, - (None, Some(_)) => Ordering::Less, - (None, None) => Ordering::Equal, - }, - } - } -} - -impl PartialOrd for VersionSuffixes { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for VersionSuffixes { - fn cmp(&self, other: &Self) -> Ordering { - let mut a = self.get().iter(); - let mut b = other.get().iter(); - - loop { - match (a.next(), b.next()) { - (Some(a), Some(b)) => match a.cmp(b) { - Ordering::Less => break Ordering::Less, - Ordering::Greater => break Ordering::Greater, - Ordering::Equal => (), - }, - (Some(a), None) if matches!(a.kind, VersionSuffixKind::P) => { - break Ordering::Greater; - } - (Some(_), None) => break Ordering::Less, - (None, Some(b)) if matches!(b.kind, VersionSuffixKind::P) => break Ordering::Less, - (None, Some(_)) => break Ordering::Greater, - (None, None) => break Ordering::Equal, - } - } - } -} - -impl PartialOrd for VersionNumbers { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for VersionNumbers { - fn cmp(&self, other: &Self) -> Ordering { - match self - .get() - .first() - .unwrap() - .cmp_as_ints(other.get().first().unwrap()) - { - Ordering::Less => Ordering::Less, - Ordering::Greater => Ordering::Greater, - Ordering::Equal => { - let mut a = self.get().iter().skip(1); - let mut b = other.get().iter().skip(1); - - loop { - match (a.next(), b.next()) { - (Some(a), Some(b)) => match a.cmp_as_str(b) { - Ordering::Less => break Ordering::Less, - Ordering::Greater => break Ordering::Greater, - Ordering::Equal => (), - }, - - (Some(_), None) => break Ordering::Greater, - (None, Some(_)) => break Ordering::Less, - (None, None) => break Ordering::Equal, - } - } - } - } - } -} - -impl PartialOrd for Version { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for Version { - fn cmp(&self, other: &Self) -> Ordering { - match self.numbers.cmp(&other.numbers) { - Ordering::Less => return Ordering::Less, - Ordering::Greater => return Ordering::Greater, - Ordering::Equal => (), - } - - match (self.letter, other.letter) { - (Some(a), Some(b)) if a < b => return Ordering::Less, - (Some(a), Some(b)) if a > b => return Ordering::Greater, - (Some(a), Some(b)) if a == b => (), - (Some(_), None) => return Ordering::Greater, - (None, Some(_)) => return Ordering::Less, - (None, None) => (), - _ => unreachable!(), - } - - match self.suffixes.cmp(&other.suffixes) { - Ordering::Less => return Ordering::Less, - Ordering::Greater => return Ordering::Greater, - Ordering::Equal => (), - } - - match (&self.rev, &other.rev) { - (Some(a), Some(b)) => match a.cmp_as_ints(b) { - Ordering::Less => return Ordering::Less, - Ordering::Greater => return Ordering::Greater, - Ordering::Equal => (), - }, - (Some(a), None) if a.get().chars().all(|c| c == '0') => (), - (Some(_), None) => return Ordering::Greater, - (None, Some(b)) if b.get().chars().all(|c| c == '0') => (), - (None, Some(_)) => return Ordering::Less, - (None, None) => (), - } - - match (&self.build_id, &other.build_id) { - (Some(a), Some(b)) => a.cmp(b), - (Some(_), None) => Ordering::Greater, - (None, Some(_)) => Ordering::Less, - (None, None) => Ordering::Equal, - } - } -} - -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 { - Self::Weak => write!(f, "!"), - Self::Strong => write!(f, "!!"), - } - } -} - -impl fmt::Display for VersionOperator { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Lt => write!(f, "<"), - Self::Gt => write!(f, ">"), - Self::Eq => write!(f, "="), - Self::LtEq => write!(f, "<="), - Self::GtEq => write!(f, ">="), - Self::Roughly => write!(f, "~"), - } - } -} - -impl fmt::Display for Category { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl fmt::Display for Name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl fmt::Display for VersionNumber { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl fmt::Display for BuildId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.get()) - } -} - -impl fmt::Display for VersionSuffixKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Alpha => write!(f, "alpha"), - Self::Beta => write!(f, "beta"), - Self::Pre => write!(f, "pre"), - Self::Rc => write!(f, "rc"), - Self::P => write!(f, "p"), - } - } -} - -impl fmt::Display for VersionSuffix { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.kind)?; - - if let Some(number) = self.number.as_ref() { - write!(f, "{number}")?; - } - - Ok(()) - } -} - -impl fmt::Display for Version { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let numbers = self - .numbers - .get() - .iter() - .map(VersionNumber::get) - .intersperse(".") - .collect::<String>(); - - let suffixes = self - .suffixes - .get() - .iter() - .map(VersionSuffix::to_string) - .intersperse("_".to_string()) - .collect::<String>(); - - write!(f, "{numbers}")?; - - if let Some(letter) = self.letter { - write!(f, "{letter}")?; - } - - if !suffixes.is_empty() { - write!(f, "_{suffixes}")?; - } - - if let Some(rev) = self.rev.as_ref() { - write!(f, "-r{rev}")?; - } - - if let Some(build_id) = self.build_id.as_ref() { - write!(f, "-{build_id}")?; - } - - Ok(()) - } -} - -impl fmt::Display for SlotOperator { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Eq => write!(f, "="), - Self::Star => write!(f, "*"), - } - } -} - -impl fmt::Display for SlotName { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl fmt::Display for Slot { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Wildcard => write!(f, "*"), - Self::Equal => { - write!(f, "=") - } - Self::NameEqual { primary, sub } => { - write!(f, "{primary}")?; - - if let Some(sub) = sub { - write!(f, "/{sub}")?; - } - - write!(f, "=") - } - Self::Name { primary, sub } => { - write!(f, "{primary}")?; - - if let Some(sub) = sub { - write!(f, "/{sub}")?; - } - - Ok(()) - } - } - } -} - -impl fmt::Display for UseDepNegate { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Minus => write!(f, "-"), - Self::Exclamation => write!(f, "!"), - } - } -} - -impl fmt::Display for UseDepSign { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Enabled => write!(f, "(+)"), - Self::Disabled => write!(f, "(-)"), - } - } -} - -impl fmt::Display for UseDepCondition { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Eq => write!(f, "="), - Self::Question => write!(f, "?"), - } - } -} - -impl fmt::Display for UseDep { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(negate) = self.negate.as_ref() { - write!(f, "{negate}")?; - } - - write!(f, "{}", self.flag)?; - - if let Some(sign) = self.sign.as_ref() { - write!(f, "{sign}")?; - } - - if let Some(condition) = self.condition.as_ref() { - write!(f, "{condition}")?; - } - - Ok(()) - } -} - -impl fmt::Display for Cp { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}/{}", &self.category, &self.name) - } -} - -impl fmt::Display for Cpv { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}/{}-{}", &self.category, &self.name, &self.version)?; - - if let Some(slot) = self.slot.as_ref() { - write!(f, ":{slot}")?; - } - - Ok(()) - } -} - -impl fmt::Display for Atom { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(blocker) = self.blocker.as_ref() { - write!(f, "{blocker}")?; - } - - if let Some(version_operator) = self.version_operator().as_ref() { - write!(f, "{version_operator}")?; - } - - write!(f, "{}", self.category)?; - write!(f, "/")?; - write!(f, "{}", self.name)?; - - if let Some((_, version, None)) = self.version() { - write!(f, "-{version}")?; - } else if let Some((_, version, Some(_))) = self.version() { - write!(f, "-{version}*")?; - } - - if let Some(slot) = self.slot.as_ref() { - write!(f, ":{slot}")?; - } - - let usedeps = self - .usedeps - .iter() - .map(UseDep::to_string) - .intersperse(",".to_string()) - .collect::<String>(); - - if !usedeps.is_empty() { - write!(f, "[{usedeps}]")?; - } - - Ok(()) - } -} - -#[cfg(test)] -mod test { - use mon::{Parser, input::InputIter}; - - use super::*; - - use crate::Parseable; - - macro_rules! assert_cmp_display { - ($a:expr, $b:expr, $ordering:expr) => { - if $a.cmp(&$b) != $ordering { - panic!("{} ~ {} != {:?}", $a, $b, $ordering) - } - }; - } - - 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"; - let version = Version::parser().parse_finished(InputIter::new(s)).unwrap(); - - assert_eq!(version.to_string().as_str(), s); - } - - #[test] - fn test_display_atom() { - let s = "!!>=foo/bar-1.0.0v_alpha1_beta1-r1:slot/sub=[a,b,c]"; - let atom = Atom::parser().parse_finished(InputIter::new(s)).unwrap(); - - assert_eq!(atom.to_string().as_str(), s); - } - - #[test] - fn test_version_cmp() { - let versions = [ - ("1.0.1", "1.0", Ordering::Greater), - ("1.0.0", "1.0.0_alpha", Ordering::Greater), - ("1.0.0_alpha", "1.0.0_alpha_p", Ordering::Less), - ("1.0.0-r0", "1.0.0", Ordering::Equal), - ("1.0.0-r0000", "1.0.0", Ordering::Equal), - ("1.0.0-r1-1", "1.0.0-r1-2", Ordering::Less), - ]; - - for (a, b, ordering) in versions.iter().map(|(a, b, ordering)| { - ( - Version::parser().parse_finished(InputIter::new(a)).unwrap(), - Version::parser().parse_finished(InputIter::new(b)).unwrap(), - ordering, - ) - }) { - 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); - } - } - - #[test] - fn test_version_cmp_letter() { - let a = Version::parser() - .parse_finished(InputIter::new("1.0.0")) - .unwrap(); - let b = Version::parser() - .parse_finished(InputIter::new("1.0.0a")) - .unwrap(); - - assert_cmp_display!(a, b, Ordering::Less); - } - - #[test] - fn test_version_cmp_where_b_has_leading_zeros() { - let a = Version::parser() - .parse_finished(InputIter::new("1.2")) - .unwrap(); - let b = Version::parser() - .parse_finished(InputIter::new("1.054")) - .unwrap(); - - assert_cmp_display!(a, b, Ordering::Greater); - } - - #[test] - fn test_version_has_more_zeros() { - let a = Version::parser() - .parse_finished(InputIter::new("1.0.0")) - .unwrap(); - let b = Version::parser() - .parse_finished(InputIter::new("1.0")) - .unwrap(); - - assert_cmp_display!(a, b, Ordering::Greater); - } - - #[test] - fn test_fuzzer_cases() { - let control = Version::parser() - .parse_finished(InputIter::new("1.2.0a_alpha1_beta2-r1-8")) - .unwrap(); - - #[allow(clippy::single_element_loop)] - for (version_str, expected) in [("1.2.0", Ordering::Greater)] { - let version = Version::parser() - .parse_finished(InputIter::new(version_str)) - .unwrap(); - - assert_cmp_display!(control, version, expected); - } - } -} |
