ConstraintSet

Struct ConstraintSet 

Source
pub struct ConstraintSet { /* private fields */ }
Expand description

A collection of version constraints that must all be satisfied simultaneously.

ConstraintSet manages multiple VersionConstraints for a single dependency, ensuring that all constraints are compatible and can be resolved together. It provides conflict detection, version matching, and best-match selection.

§Constraint Combination

When multiple constraints are added to a set, they create an intersection of requirements. For example:

  • >=1.0.0 AND <2.0.0 = versions in range [1.0.0, 2.0.0)
  • ^1.0.0 AND ~1.2.0 = versions compatible with both (e.g., 1.2.x)

§Conflict Detection

The constraint set detects and prevents conflicting constraints:

  • Multiple exact versions: 1.0.0 AND 2.0.0 (impossible to satisfy)
  • Conflicting Git refs: main AND develop (can’t be both branches)

§Resolution Strategy

When selecting from available versions, the set:

  1. Filters versions that satisfy ALL constraints
  2. Excludes prereleases unless explicitly allowed
  3. Selects the highest remaining version

§Examples

§Basic Usage

use agpm_cli::version::constraints::{ConstraintSet, VersionConstraint};
use semver::Version;

let mut set = ConstraintSet::new();
set.add(VersionConstraint::parse(">=1.0.0")?)?;
set.add(VersionConstraint::parse("<2.0.0")?)?;

let version = Version::parse("1.5.0")?;
assert!(set.satisfies(&version));

let version = Version::parse("2.0.0")?;
assert!(!set.satisfies(&version)); // Outside range

§Best Match Selection

use agpm_cli::version::constraints::{ConstraintSet, VersionConstraint};
use semver::Version;

let mut set = ConstraintSet::new();
set.add(VersionConstraint::parse("^1.0.0")?)?;

let versions = vec![
    Version::parse("0.9.0")?,  // Too old
    Version::parse("1.0.0")?,  // Matches
    Version::parse("1.5.0")?,  // Matches, higher
    Version::parse("2.0.0")?,  // Too new
];

let best = set.find_best_match(&versions).unwrap();
assert_eq!(best, &Version::parse("1.5.0")?); // Highest compatible

§Conflict Detection

use agpm_cli::version::constraints::{ConstraintSet, VersionConstraint};
use semver::Version;

let mut set = ConstraintSet::new();
set.add(VersionConstraint::parse("1.0.0")?)?; // Exact version

// This will fail - can't have two different exact versions
let result = set.add(VersionConstraint::parse("2.0.0")?);
assert!(result.is_err());

Implementations§

Source§

impl ConstraintSet

Source

pub const fn new() -> Self

Creates a new empty constraint set

§Returns

Returns a new ConstraintSet with no constraints

Source

pub fn add(&mut self, constraint: VersionConstraint) -> Result<()>

Add a constraint to this set with conflict detection.

This method adds a new constraint to the set after checking for conflicts with existing constraints. If the new constraint would create an impossible situation (like requiring two different exact versions), an error is returned.

§Arguments
§Returns

Returns Ok(()) if the constraint was added successfully, or Err if it conflicts with existing constraints.

§Conflict Detection

Current conflict detection covers:

  • Exact version conflicts: Different exact versions for the same dependency
  • Git ref conflicts: Different Git references for the same dependency

Future versions may add more sophisticated conflict detection for semantic version ranges.

§Examples
use agpm_cli::version::constraints::{ConstraintSet, VersionConstraint};

let mut set = ConstraintSet::new();

// These constraints are compatible
set.add(VersionConstraint::parse(">=1.0.0")?)?;
set.add(VersionConstraint::parse("<2.0.0")?)?;

// This would conflict with exact versions
set.add(VersionConstraint::parse("1.5.0")?)?;
let result = set.add(VersionConstraint::parse("1.6.0")?);
assert!(result.is_err()); // Conflict: can't be both 1.5.0 AND 1.6.0
Source

pub fn satisfies(&self, version: &Version) -> bool

Check if a version satisfies all constraints in this set.

This method tests whether a given version passes all the constraints in this set. For a version to be acceptable, it must satisfy every single constraint - this represents a logical AND operation.

§Arguments
  • version - The semantic version to test against all constraints
§Returns

Returns true if the version satisfies ALL constraints, false if it fails to satisfy any constraint.

§Examples
use agpm_cli::version::constraints::{ConstraintSet, VersionConstraint};
use semver::Version;

let mut set = ConstraintSet::new();
set.add(VersionConstraint::parse(">=1.0.0")?)?; // Must be at least 1.0.0
set.add(VersionConstraint::parse("<2.0.0")?)?;  // Must be less than 2.0.0
set.add(VersionConstraint::parse("^1.0.0")?)?;  // Must be compatible with 1.0.0

assert!(set.satisfies(&Version::parse("1.5.0")?)); // Satisfies all three
assert!(!set.satisfies(&Version::parse("0.9.0")?)); // Fails >=1.0.0
assert!(!set.satisfies(&Version::parse("2.0.0")?)); // Fails <2.0.0
§Performance Note

This method short-circuits on the first constraint that fails, making it efficient even with many constraints.

Source

pub fn find_best_match<'a>( &self, versions: &'a [Version], ) -> Option<&'a Version>

Find the best matching version from a list of available versions.

This method filters provided versions to find those that satisfy all constraints, then selects the “best” match according to AGPM’s resolution strategy. The selection prioritizes newer versions while respecting prerelease preferences.

§Resolution Strategy
  1. Filter candidates: Keep only versions that satisfy all constraints
  2. Sort by version: Order candidates from highest to lowest version
  3. Apply prerelease policy: Remove prereleases unless explicitly allowed
  4. Select best: Return the highest remaining version
§Arguments
  • versions - Slice of available versions to choose from
§Returns

Returns Some(&Version) with the best matching version, or None if no version satisfies all constraints.

§Examples
use agpm_cli::version::constraints::{ConstraintSet, VersionConstraint};
use semver::Version;

let mut set = ConstraintSet::new();
set.add(VersionConstraint::parse("^1.0.0")?)?;

let versions = vec![
    Version::parse("0.9.0")?,    // Too old
    Version::parse("1.0.0")?,    // Compatible
    Version::parse("1.2.0")?,    // Compatible, newer
    Version::parse("1.5.0")?,    // Compatible, newest
    Version::parse("2.0.0")?,    // Too new
];

let best = set.find_best_match(&versions).unwrap();
assert_eq!(best, &Version::parse("1.5.0")?); // Highest compatible version
§Prerelease Handling
use agpm_cli::version::constraints::{ConstraintSet, VersionConstraint};
use semver::Version;

let mut set = ConstraintSet::new();
set.add(VersionConstraint::parse("^1.0.0")?)?; // Doesn't allow prereleases

let versions = vec![
    Version::parse("1.0.0")?,
    Version::parse("1.1.0-alpha.1")?,  // Prerelease
    Version::parse("1.1.0")?,           // Stable
];

let best = set.find_best_match(&versions).unwrap();
assert_eq!(best, &Version::parse("1.1.0")?); // Stable version preferred
Source

pub fn allows_prerelease(&self) -> bool

Check if any constraint in this set allows prerelease versions.

This method determines the prerelease policy for the entire constraint set. If ANY constraint in the set allows prereleases, the entire set is considered to allow prereleases. This ensures that explicit prerelease constraints (like latest-prerelease or Git refs) are respected.

§Returns

Returns true if any constraint allows prereleases, false if all constraints exclude prereleases.

§Examples
use agpm_cli::version::constraints::{ConstraintSet, VersionConstraint};

let mut stable_set = ConstraintSet::new();
stable_set.add(VersionConstraint::parse("^1.0.0")?)?;
stable_set.add(VersionConstraint::parse("~1.2.0")?)?;
assert!(!stable_set.allows_prerelease()); // All constraints exclude prereleases

let mut prerelease_set = ConstraintSet::new();
prerelease_set.add(VersionConstraint::parse("^1.0.0")?)?;
prerelease_set.add(VersionConstraint::parse("main")?)?; // Git ref allows prereleases
assert!(prerelease_set.allows_prerelease()); // One constraint allows prereleases
§Impact on Resolution

This setting affects find_best_match behavior:

  • If false: Prerelease versions are filtered out before selection
  • If true: Prerelease versions are included in selection

Trait Implementations§

Source§

impl Clone for ConstraintSet

Source§

fn clone(&self) -> ConstraintSet

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ConstraintSet

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ConstraintSet

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more