diff options
Diffstat (limited to 'crates/shirabe-semver/src/constraint')
| -rw-r--r-- | crates/shirabe-semver/src/constraint/any_constraint.rs | 169 | ||||
| -rw-r--r-- | crates/shirabe-semver/src/constraint/constraint_interface.rs | 43 | ||||
| -rw-r--r-- | crates/shirabe-semver/src/constraint/match_all_constraint.rs | 55 | ||||
| -rw-r--r-- | crates/shirabe-semver/src/constraint/match_none_constraint.rs | 41 | ||||
| -rw-r--r-- | crates/shirabe-semver/src/constraint/multi_constraint.rs | 196 | ||||
| -rw-r--r-- | crates/shirabe-semver/src/constraint/simple_constraint.rs (renamed from crates/shirabe-semver/src/constraint/constraint.rs) | 118 |
6 files changed, 286 insertions, 336 deletions
diff --git a/crates/shirabe-semver/src/constraint/any_constraint.rs b/crates/shirabe-semver/src/constraint/any_constraint.rs new file mode 100644 index 0000000..b61a36f --- /dev/null +++ b/crates/shirabe-semver/src/constraint/any_constraint.rs @@ -0,0 +1,169 @@ +//! ref: composer/vendor/composer/semver/src/Constraint/ConstraintInterface.php + +use crate::constraint::Bound; +use crate::constraint::MatchAllConstraint; +use crate::constraint::MatchNoneConstraint; +use crate::constraint::MultiConstraint; +use crate::constraint::SimpleConstraint; + +/// Corresponds to PHP's `ConstraintInterface`. +#[derive(Clone, Debug)] +pub enum AnyConstraint { + Simple(SimpleConstraint), + Multi(MultiConstraint), + MatchAll(MatchAllConstraint), + MatchNone(MatchNoneConstraint), +} + +impl AnyConstraint { + pub fn matches(&self, provider: &AnyConstraint) -> bool { + match self { + Self::MatchAll(_) => true, + Self::MatchNone(_) => false, + Self::Simple(c) => match provider.as_constraint() { + Some(p) => c.match_specific(p, false), + None => provider.matches(self), + }, + Self::Multi(m) => { + if !m.conjunctive { + m.constraints.iter().any(|sub| provider.matches(sub)) + } else if provider.is_disjunctive() { + provider.matches(self) + } else { + m.constraints.iter().all(|sub| provider.matches(sub)) + } + } + } + } + + pub fn compile(&self, other_operator: i64) -> String { + match self { + Self::Simple(c) => c.compile(other_operator), + Self::Multi(c) => c.compile(other_operator), + Self::MatchAll(c) => c.compile(other_operator), + Self::MatchNone(c) => c.compile(other_operator), + } + } + + pub fn get_upper_bound(&self) -> Bound { + match self { + Self::Simple(c) => c.get_upper_bound(), + Self::Multi(c) => c.get_upper_bound(), + Self::MatchAll(c) => c.get_upper_bound(), + Self::MatchNone(c) => c.get_upper_bound(), + } + } + + pub fn get_lower_bound(&self) -> Bound { + match self { + Self::Simple(c) => c.get_lower_bound(), + Self::Multi(c) => c.get_lower_bound(), + Self::MatchAll(c) => c.get_lower_bound(), + Self::MatchNone(c) => c.get_lower_bound(), + } + } + + pub fn get_pretty_string(&self) -> String { + match self { + Self::Simple(c) => c.get_pretty_string(), + Self::Multi(c) => c.get_pretty_string(), + Self::MatchAll(c) => c.get_pretty_string(), + Self::MatchNone(c) => c.get_pretty_string(), + } + } + + /// PHP `$c instanceof MultiConstraint && $c->isDisjunctive()`. + pub fn is_disjunctive(&self) -> bool { + matches!(self, Self::Multi(m) if !m.conjunctive) + } + + /// PHP `$c instanceof Constraint`. + pub fn is_constraint(&self) -> bool { + matches!(self, Self::Simple(_)) + } + + pub fn get_operator(&self) -> &'static str { + match self { + Self::Simple(c) => c.get_operator(), + _ => "", + } + } + + pub fn get_version(&self) -> &str { + match self { + Self::Simple(c) => c.get_version(), + _ => "", + } + } + + pub fn as_constraint(&self) -> Option<&SimpleConstraint> { + match self { + Self::Simple(c) => Some(c), + _ => None, + } + } + + pub fn as_multi_constraint(&self) -> Option<&MultiConstraint> { + match self { + Self::Multi(c) => Some(c), + _ => None, + } + } + + pub fn is_match_all(&self) -> bool { + matches!(self, Self::MatchAll(_)) + } + + pub fn is_match_none(&self) -> bool { + matches!(self, Self::MatchNone(_)) + } + + /// PHP exposes `ConstraintInterface::setPrettyString()` and defaults the + /// pretty string to the constraint's string form when unset. This port takes + /// the pretty string at construction instead; this setter exists only so + /// `MultiConstraint::create()` can apply the pretty string PHP sets on its + /// (possibly polymorphic) result. + pub(crate) fn set_pretty_string(&mut self, pretty_string: Option<String>) { + match self { + Self::Simple(c) => c.pretty_string = pretty_string, + Self::Multi(c) => c.pretty_string = pretty_string, + Self::MatchAll(c) => c.pretty_string = pretty_string, + Self::MatchNone(c) => c.pretty_string = pretty_string, + } + } +} + +impl From<SimpleConstraint> for AnyConstraint { + fn from(c: SimpleConstraint) -> Self { + Self::Simple(c) + } +} + +impl From<MultiConstraint> for AnyConstraint { + fn from(c: MultiConstraint) -> Self { + Self::Multi(c) + } +} + +impl From<MatchAllConstraint> for AnyConstraint { + fn from(c: MatchAllConstraint) -> Self { + Self::MatchAll(c) + } +} + +impl From<MatchNoneConstraint> for AnyConstraint { + fn from(c: MatchNoneConstraint) -> Self { + Self::MatchNone(c) + } +} + +impl std::fmt::Display for AnyConstraint { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Simple(c) => write!(f, "{}", c), + Self::Multi(c) => write!(f, "{}", c), + Self::MatchAll(c) => write!(f, "{}", c), + Self::MatchNone(c) => write!(f, "{}", c), + } + } +} diff --git a/crates/shirabe-semver/src/constraint/constraint_interface.rs b/crates/shirabe-semver/src/constraint/constraint_interface.rs deleted file mode 100644 index f04ed2a..0000000 --- a/crates/shirabe-semver/src/constraint/constraint_interface.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! ref: composer/vendor/composer/semver/src/Constraint/ConstraintInterface.php - -use crate::constraint::Bound; - -pub trait ConstraintInterface: std::fmt::Debug { - fn matches(&self, provider: &dyn ConstraintInterface) -> bool; - - fn compile(&self, other_operator: i64) -> String; - - fn get_upper_bound(&self) -> Bound; - - fn get_lower_bound(&self) -> Bound; - - fn get_pretty_string(&self) -> String; - - fn set_pretty_string(&mut self, pretty_string: Option<String>); - - fn __to_string(&self) -> String; - - // Rust-specific helpers for instanceof checks in MultiConstraint::matches and optimizeConstraints. - fn is_disjunctive(&self) -> bool { - false - } - - /// Rust-specific helper: PHP `$c instanceof Constraint` check. - fn is_constraint(&self) -> bool { - false - } - - /// Rust-specific helper: PHP `$c->getOperator()`. Only meaningful when `is_constraint()` is true. - fn get_operator(&self) -> &'static str { - "" - } - - /// Rust-specific helper: PHP `$c->getVersion()`. Only meaningful when `is_constraint()` is true. - fn get_version(&self) -> &str { - "" - } - - fn clone_box(&self) -> Box<dyn ConstraintInterface>; - - fn as_any(&self) -> &dyn std::any::Any; -} diff --git a/crates/shirabe-semver/src/constraint/match_all_constraint.rs b/crates/shirabe-semver/src/constraint/match_all_constraint.rs index b695ce2..8d4e870 100644 --- a/crates/shirabe-semver/src/constraint/match_all_constraint.rs +++ b/crates/shirabe-semver/src/constraint/match_all_constraint.rs @@ -1,68 +1,41 @@ //! ref: composer/vendor/composer/semver/src/Constraint/MatchAllConstraint.php use crate::constraint::Bound; -use crate::constraint::ConstraintInterface; -#[derive(Debug)] +#[derive(Debug, Clone, Default)] pub struct MatchAllConstraint { pub(crate) pretty_string: Option<String>, } impl MatchAllConstraint { - pub fn new() -> Self { - Self { - pretty_string: None, - } + pub fn new(pretty_string: Option<String>) -> Self { + Self { pretty_string } } -} - -impl Default for MatchAllConstraint { - fn default() -> Self { - Self::new() - } -} -impl ConstraintInterface for MatchAllConstraint { - fn matches(&self, _provider: &dyn ConstraintInterface) -> bool { - true - } - - fn compile(&self, _other_operator: i64) -> String { + pub fn compile(&self, _other_operator: i64) -> String { "true".to_string() } - fn set_pretty_string(&mut self, pretty_string: Option<String>) { - self.pretty_string = pretty_string; - } - - fn get_pretty_string(&self) -> String { + pub fn get_pretty_string(&self) -> String { if let Some(ref s) = self.pretty_string && !s.is_empty() { return s.clone(); } - self.__to_string() + self.to_string() } - fn __to_string(&self) -> String { - "*".to_string() - } - - fn clone_box(&self) -> Box<dyn ConstraintInterface> { - Box::new(MatchAllConstraint { - pretty_string: self.pretty_string.clone(), - }) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn get_upper_bound(&self) -> Bound { + pub fn get_upper_bound(&self) -> Bound { Bound::positive_infinity() } - fn get_lower_bound(&self) -> Bound { + pub fn get_lower_bound(&self) -> Bound { Bound::zero() } } + +impl std::fmt::Display for MatchAllConstraint { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "*") + } +} diff --git a/crates/shirabe-semver/src/constraint/match_none_constraint.rs b/crates/shirabe-semver/src/constraint/match_none_constraint.rs index 587058a..08cb319 100644 --- a/crates/shirabe-semver/src/constraint/match_none_constraint.rs +++ b/crates/shirabe-semver/src/constraint/match_none_constraint.rs @@ -1,54 +1,41 @@ //! ref: composer/vendor/composer/semver/src/Constraint/MatchNoneConstraint.php use crate::constraint::Bound; -use crate::constraint::ConstraintInterface; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MatchNoneConstraint { pub(crate) pretty_string: Option<String>, } -impl ConstraintInterface for MatchNoneConstraint { - fn matches(&self, _provider: &dyn ConstraintInterface) -> bool { - false +impl MatchNoneConstraint { + pub fn new(pretty_string: Option<String>) -> Self { + Self { pretty_string } } - fn compile(&self, _other_operator: i64) -> String { + pub fn compile(&self, _other_operator: i64) -> String { "false".to_string() } - fn set_pretty_string(&mut self, pretty_string: Option<String>) { - self.pretty_string = pretty_string; - } - - fn get_pretty_string(&self) -> String { + pub fn get_pretty_string(&self) -> String { if let Some(ref s) = self.pretty_string && !s.is_empty() { return s.clone(); } - self.__to_string() + self.to_string() } - fn __to_string(&self) -> String { - "[]".to_string() - } - - fn clone_box(&self) -> Box<dyn ConstraintInterface> { - Box::new(MatchNoneConstraint { - pretty_string: self.pretty_string.clone(), - }) - } - - fn as_any(&self) -> &dyn std::any::Any { - self + pub fn get_upper_bound(&self) -> Bound { + Bound::new("0.0.0.0-dev".to_string(), false) } - fn get_upper_bound(&self) -> Bound { + pub fn get_lower_bound(&self) -> Bound { Bound::new("0.0.0.0-dev".to_string(), false) } +} - fn get_lower_bound(&self) -> Bound { - Bound::new("0.0.0.0-dev".to_string(), false) +impl std::fmt::Display for MatchNoneConstraint { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "[]") } } diff --git a/crates/shirabe-semver/src/constraint/multi_constraint.rs b/crates/shirabe-semver/src/constraint/multi_constraint.rs index 4222095..05cc16e 100644 --- a/crates/shirabe-semver/src/constraint/multi_constraint.rs +++ b/crates/shirabe-semver/src/constraint/multi_constraint.rs @@ -1,30 +1,22 @@ //! ref: composer/vendor/composer/semver/src/Constraint/MultiConstraint.php -use std::cell::RefCell; - +use crate::constraint::AnyConstraint; use crate::constraint::Bound; -use crate::constraint::ConstraintInterface; use crate::constraint::MatchAllConstraint; +#[derive(Debug, Clone)] pub struct MultiConstraint { - pub(crate) constraints: Vec<Box<dyn ConstraintInterface>>, + pub(crate) constraints: Vec<AnyConstraint>, pub(crate) pretty_string: Option<String>, - string: RefCell<Option<String>>, pub(crate) conjunctive: bool, - lower_bound: RefCell<Option<Bound>>, - upper_bound: RefCell<Option<Bound>>, -} - -impl std::fmt::Debug for MultiConstraint { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("MultiConstraint") - .field("conjunctive", &self.conjunctive) - .finish() - } } impl MultiConstraint { - pub fn new(constraints: Vec<Box<dyn ConstraintInterface>>, conjunctive: bool) -> Self { + pub fn new( + constraints: Vec<AnyConstraint>, + conjunctive: bool, + pretty_string: Option<String>, + ) -> Self { assert!( constraints.len() >= 2, "Must provide at least two constraints for a MultiConstraint. Use \ @@ -34,15 +26,12 @@ impl MultiConstraint { Self { constraints, - pretty_string: None, - string: RefCell::new(None), + pretty_string, conjunctive, - lower_bound: RefCell::new(None), - upper_bound: RefCell::new(None), } } - pub fn get_constraints(&self) -> &[Box<dyn ConstraintInterface>] { + pub fn get_constraints(&self) -> &[AnyConstraint] { &self.constraints } @@ -54,11 +43,9 @@ impl MultiConstraint { !self.conjunctive } - fn extract_bounds(&self) { - if self.lower_bound.borrow().is_some() { - return; - } - + /// Composer memoizes the result; this port recomputes on every call. It is not heavy + /// calculation so caching is a premature optimization. + fn extract_bounds(&self) -> (Bound, Bound) { let mut current_lower: Option<Bound> = None; let mut current_upper: Option<Bound> = None; @@ -93,52 +80,61 @@ impl MultiConstraint { } } - *self.lower_bound.borrow_mut() = current_lower; - *self.upper_bound.borrow_mut() = current_upper; + ( + current_lower.expect("MultiConstraint always has at least two constraints"), + current_upper.expect("MultiConstraint always has at least two constraints"), + ) } pub fn create( - constraints: Vec<Box<dyn ConstraintInterface>>, + constraints: Vec<AnyConstraint>, conjunctive: bool, - ) -> anyhow::Result<Box<dyn ConstraintInterface>> { + pretty_string: Option<String>, + ) -> anyhow::Result<AnyConstraint> { if constraints.is_empty() { - return Ok(Box::new(MatchAllConstraint { - pretty_string: None, - })); + return Ok(MatchAllConstraint::new(pretty_string).into()); } if constraints.len() == 1 { - return Ok(constraints.into_iter().next().unwrap()); + let mut single = constraints.into_iter().next().unwrap(); + if pretty_string.is_some() { + single.set_pretty_string(pretty_string); + } + return Ok(single); } let (constraints, conjunctive) = Self::optimize_constraints(constraints, conjunctive); if constraints.len() == 1 { - return Ok(constraints.into_iter().next().unwrap()); + let mut single = constraints.into_iter().next().unwrap(); + if pretty_string.is_some() { + single.set_pretty_string(pretty_string); + } + return Ok(single); } - Ok(Box::new(MultiConstraint::new(constraints, conjunctive))) + Ok(MultiConstraint::new(constraints, conjunctive, pretty_string).into()) } // Returns the (possibly optimized) constraints and the effective conjunctive flag. // Always returns the constraints vector (consuming it), whether or not optimization was applied. // The PHP version returns null for no optimization; here we return the original values unchanged. fn optimize_constraints( - constraints: Vec<Box<dyn ConstraintInterface>>, + constraints: Vec<AnyConstraint>, conjunctive: bool, - ) -> (Vec<Box<dyn ConstraintInterface>>, bool) { + ) -> (Vec<AnyConstraint>, bool) { // Parse the two OR groups and if they are contiguous collapse into one constraint. // [>= 1 < 2] || [>= 2 < 3] || [>= 3 < 4] => [>= 1 < 4] if !conjunctive { let mut iter = constraints.into_iter(); - let mut left: Box<dyn ConstraintInterface> = iter.next().unwrap(); - let mut merged_constraints: Vec<Box<dyn ConstraintInterface>> = Vec::new(); + let mut left: AnyConstraint = iter.next().unwrap(); + let mut merged_constraints: Vec<AnyConstraint> = Vec::new(); let mut optimized = false; for right in iter { - let merged: Option<Box<dyn ConstraintInterface>> = { - let maybe_l_mc = left.as_any().downcast_ref::<MultiConstraint>(); - let maybe_r_mc = right.as_any().downcast_ref::<MultiConstraint>(); + let merged: Option<AnyConstraint> = { + let maybe_l_mc = left.as_multi_constraint(); + let maybe_r_mc = right.as_multi_constraint(); if let (Some(l_mc), Some(r_mc)) = (maybe_l_mc, maybe_r_mc) { if l_mc.conjunctive @@ -146,10 +142,10 @@ impl MultiConstraint { && l_mc.constraints.len() == 2 && r_mc.constraints.len() == 2 { - let left0 = l_mc.constraints[0].__to_string(); - let left1 = l_mc.constraints[1].__to_string(); - let right0 = r_mc.constraints[0].__to_string(); - let right1 = r_mc.constraints[1].__to_string(); + let left0 = l_mc.constraints[0].to_string(); + let left1 = l_mc.constraints[1].to_string(); + let right0 = r_mc.constraints[0].to_string(); + let right1 = r_mc.constraints[1].to_string(); if left0.starts_with(">=") && left1.starts_with('<') @@ -157,14 +153,17 @@ impl MultiConstraint { && right1.starts_with('<') && left1.get(2..) == right0.get(3..) { - Some(Box::new(MultiConstraint::new( - vec![ - l_mc.constraints[0].clone_box(), - r_mc.constraints[1].clone_box(), - ], - true, - )) - as Box<dyn ConstraintInterface>) + Some( + MultiConstraint::new( + vec![ + l_mc.constraints[0].clone(), + r_mc.constraints[1].clone(), + ], + true, + None, + ) + .into(), + ) } else { None } @@ -198,10 +197,8 @@ impl MultiConstraint { (constraints, conjunctive) } -} -impl ConstraintInterface for MultiConstraint { - fn compile(&self, other_operator: i64) -> String { + pub fn compile(&self, other_operator: i64) -> String { let mut parts = Vec::new(); for constraint in &self.constraints { let code = constraint.compile(other_operator); @@ -233,87 +230,28 @@ impl ConstraintInterface for MultiConstraint { } } - fn matches(&self, provider: &dyn ConstraintInterface) -> bool { - if !self.conjunctive { - for constraint in &self.constraints { - if provider.matches(constraint.as_ref()) { - return true; - } - } - return false; - } - - if provider.is_disjunctive() { - return provider.matches(self); - } - - for constraint in &self.constraints { - if !provider.matches(constraint.as_ref()) { - return false; - } - } - - true - } - - fn set_pretty_string(&mut self, pretty_string: Option<String>) { - self.pretty_string = pretty_string; - } - - fn get_pretty_string(&self) -> String { + pub fn get_pretty_string(&self) -> String { if let Some(ref s) = self.pretty_string && !s.is_empty() { return s.clone(); } - self.__to_string() - } - - fn __to_string(&self) -> String { - if let Some(ref s) = *self.string.borrow() { - return s.clone(); - } - - let parts: Vec<String> = self.constraints.iter().map(|c| c.__to_string()).collect(); - let sep = if self.conjunctive { " " } else { " || " }; - let result = format!("[{}]", parts.join(sep)); - - *self.string.borrow_mut() = Some(result.clone()); - result - } - - fn get_lower_bound(&self) -> Bound { - self.extract_bounds(); - self.lower_bound - .borrow() - .clone() - .expect("extractBounds should have populated the lowerBound property") - } - - fn get_upper_bound(&self) -> Bound { - self.extract_bounds(); - self.upper_bound - .borrow() - .clone() - .expect("extractBounds should have populated the upperBound property") + self.to_string() } - fn is_disjunctive(&self) -> bool { - !self.conjunctive + pub fn get_lower_bound(&self) -> Bound { + self.extract_bounds().0 } - fn clone_box(&self) -> Box<dyn ConstraintInterface> { - Box::new(MultiConstraint { - constraints: self.constraints.iter().map(|c| c.clone_box()).collect(), - pretty_string: self.pretty_string.clone(), - string: RefCell::new(self.string.borrow().clone()), - conjunctive: self.conjunctive, - lower_bound: RefCell::new(self.lower_bound.borrow().clone()), - upper_bound: RefCell::new(self.upper_bound.borrow().clone()), - }) + pub fn get_upper_bound(&self) -> Bound { + self.extract_bounds().1 } +} - fn as_any(&self) -> &dyn std::any::Any { - self +impl std::fmt::Display for MultiConstraint { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let parts: Vec<String> = self.constraints.iter().map(|c| c.to_string()).collect(); + let sep = if self.conjunctive { " " } else { " || " }; + write!(f, "[{}]", parts.join(sep)) } } diff --git a/crates/shirabe-semver/src/constraint/constraint.rs b/crates/shirabe-semver/src/constraint/simple_constraint.rs index 3ac633d..161425a 100644 --- a/crates/shirabe-semver/src/constraint/constraint.rs +++ b/crates/shirabe-semver/src/constraint/simple_constraint.rs @@ -1,23 +1,19 @@ //! ref: composer/vendor/composer/semver/src/Constraint/Constraint.php -use std::sync::Mutex; - use anyhow::bail; use shirabe_php_shim as php; use crate::constraint::Bound; -use crate::constraint::ConstraintInterface; -#[derive(Debug)] -pub struct Constraint { +/// Corresponds to PHP's `Constraint`. +#[derive(Debug, Clone)] +pub struct SimpleConstraint { pub(crate) operator: i64, pub(crate) version: String, pub(crate) pretty_string: Option<String>, - pub(crate) lower_bound: Mutex<Option<Bound>>, - pub(crate) upper_bound: Mutex<Option<Bound>>, } -impl Constraint { +impl SimpleConstraint { pub const OP_EQ: i64 = 0; pub const OP_LT: i64 = 1; pub const OP_LE: i64 = 2; @@ -60,8 +56,7 @@ impl Constraint { } } - pub fn new(operator: impl Into<String>, version: impl Into<String>) -> Self { - let operator: String = operator.into(); + pub fn new(operator: String, version: String, pretty_string: Option<String>) -> Self { let op_int = Self::trans_op_str(&operator).unwrap_or_else(|| { // PHP raises InvalidArgumentException; in the Rust port keep that as a panic // because invalid operators are programmer errors caught during porting. @@ -74,10 +69,8 @@ impl Constraint { Self { operator: op_int, - version: version.into(), - pretty_string: None, - lower_bound: Mutex::new(None), - upper_bound: Mutex::new(None), + version, + pretty_string, } } @@ -225,7 +218,7 @@ impl Constraint { format!("!$b && {}", code_comparison) } - pub fn match_specific(&self, provider: &Constraint, compare_branches: bool) -> bool { + pub fn match_specific(&self, provider: &SimpleConstraint, compare_branches: bool) -> bool { let no_equal_op = Self::trans_op_int(self.operator).replace('=', ""); let provider_no_equal_op = Self::trans_op_int(provider.operator).replace('=', ""); @@ -286,18 +279,14 @@ impl Constraint { false } - fn extract_bounds(&self) { - if self.lower_bound.lock().unwrap().is_some() { - return; - } - + /// Composer memoizes the result; this port recomputes on every call. It is not heavy + /// calculation so caching is a premature optimization. + fn extract_bounds(&self) -> (Bound, Bound) { if self.version.starts_with("dev-") { - *self.lower_bound.lock().unwrap() = Some(Bound::zero()); - *self.upper_bound.lock().unwrap() = Some(Bound::positive_infinity()); - return; + return (Bound::zero(), Bound::positive_infinity()); } - let (lower, upper) = match self.operator { + match self.operator { Self::OP_EQ => ( Bound::new(self.version.clone(), true), Bound::new(self.version.clone(), true), @@ -314,96 +303,33 @@ impl Constraint { ), Self::OP_NE => (Bound::zero(), Bound::positive_infinity()), _ => panic!("unknown operator: {}", self.operator), - }; - - *self.lower_bound.lock().unwrap() = Some(lower); - *self.upper_bound.lock().unwrap() = Some(upper); - } -} - -impl Clone for Constraint { - fn clone(&self) -> Self { - Self { - operator: self.operator, - version: self.version.clone(), - pretty_string: self.pretty_string.clone(), - lower_bound: Mutex::new(self.lower_bound.lock().unwrap().clone()), - upper_bound: Mutex::new(self.upper_bound.lock().unwrap().clone()), } } -} -impl ConstraintInterface for Constraint { - fn matches(&self, provider: &dyn ConstraintInterface) -> bool { - if let Some(p) = provider.as_any().downcast_ref::<Constraint>() { - return self.match_specific(p, false); - } - provider.matches(self) - } - - fn compile(&self, other_operator: i64) -> String { + pub fn compile(&self, other_operator: i64) -> String { self.compile_constraint(other_operator) } - fn set_pretty_string(&mut self, pretty_string: Option<String>) { - self.pretty_string = pretty_string; - } - - fn get_pretty_string(&self) -> String { + pub fn get_pretty_string(&self) -> String { if let Some(ref s) = self.pretty_string && !s.is_empty() { return s.clone(); } - self.__to_string() + self.to_string() } - fn __to_string(&self) -> String { - format!("{} {}", Self::trans_op_int(self.operator), self.version) + pub fn get_lower_bound(&self) -> Bound { + self.extract_bounds().0 } - fn get_lower_bound(&self) -> Bound { - self.extract_bounds(); - self.lower_bound - .lock() - .unwrap() - .clone() - .expect("extract_bounds should have set lower_bound") - } - - fn get_upper_bound(&self) -> Bound { - self.extract_bounds(); - self.upper_bound - .lock() - .unwrap() - .clone() - .expect("extract_bounds should have set upper_bound") - } - - fn clone_box(&self) -> Box<dyn ConstraintInterface> { - Box::new(self.clone()) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn is_constraint(&self) -> bool { - true - } - - fn get_operator(&self) -> &'static str { - Self::trans_op_int(self.operator) - } - - fn get_version(&self) -> &str { - &self.version + pub fn get_upper_bound(&self) -> Bound { + self.extract_bounds().1 } } -impl std::fmt::Display for Constraint { +impl std::fmt::Display for SimpleConstraint { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use crate::constraint::ConstraintInterface; - write!(f, "{}", ConstraintInterface::__to_string(self)) + write!(f, "{} {}", Self::trans_op_int(self.operator), self.version) } } |
