Skip to content

Commit

Permalink
Switch pubgrub to experimental iter commit 02a19f7
Browse files Browse the repository at this point in the history
  • Loading branch information
zanieb committed Nov 8, 2023
1 parent e952557 commit 5aa15dd
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 171 deletions.
6 changes: 3 additions & 3 deletions vendor/pubgrub/Cargo.toml
Expand Up @@ -8,7 +8,7 @@ authors = [
"Alex Tokarev <aleksator@gmail.com>",
"Jacob Finkelman <Eh2406@wayne.edu>",
]
edition = "2018"
edition = "2021"
description = "PubGrub version solving algorithm"
readme = "README.md"
repository = "https://github.com/pubgrub-rs/pubgrub"
Expand All @@ -20,10 +20,10 @@ include = ["Cargo.toml", "LICENSE", "README.md", "src/**", "tests/**", "examples
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
thiserror = "1.0"
rustc-hash = "1.1.0"
indexmap = "2.0.2"
priority-queue = "1.1.1"
thiserror = "1.0"
rustc-hash = "1.1.0"
serde = { version = "1.0", features = ["derive"], optional = true }
log = "0.4.14" # for debug logs in tests

Expand Down
8 changes: 4 additions & 4 deletions vendor/pubgrub/src/internal/core.rs
Expand Up @@ -15,7 +15,7 @@ use crate::internal::partial_solution::{DecisionLevel, PartialSolution};
use crate::internal::small_vec::SmallVec;
use crate::package::Package;
use crate::report::DerivationTree;
use crate::type_aliases::{DependencyConstraints, Map};
use crate::type_aliases::Map;
use crate::version_set::VersionSet;

/// Current state of the PubGrub algorithm.
Expand All @@ -24,7 +24,7 @@ pub struct State<P: Package, VS: VersionSet, Priority: Ord + Clone> {
root_package: P,
root_version: VS::V,

pub incompatibilities: Map<P, Vec<IncompId<P, VS>>>,
incompatibilities: Map<P, Vec<IncompId<P, VS>>>,

/// Store the ids of incompatibilities that are already contradicted
/// and will stay that way until the next conflict and backtrack is operated.
Expand Down Expand Up @@ -75,12 +75,12 @@ impl<P: Package, VS: VersionSet, Priority: Ord + Clone> State<P, VS, Priority> {
&mut self,
package: P,
version: VS::V,
deps: &DependencyConstraints<P, VS>,
deps: impl IntoIterator<Item = (P, VS)>,
) -> std::ops::Range<IncompId<P, VS>> {
// Create incompatibilities and allocate them in the store.
let new_incompats_id_range = self
.incompatibility_store
.alloc_iter(deps.iter().map(|dep| {
.alloc_iter(deps.into_iter().map(|dep| {
Incompatibility::from_dependency(package.clone(), version.clone(), dep)
}));
// Merge the newly created incompatibilities with the older ones.
Expand Down
12 changes: 6 additions & 6 deletions vendor/pubgrub/src/internal/incompatibility.rs
Expand Up @@ -30,15 +30,15 @@ use crate::version_set::VersionSet;
/// [PubGrub documentation](https://github.com/dart-lang/pub/blob/master/doc/solver.md#incompatibility).
#[derive(Debug, Clone)]
pub struct Incompatibility<P: Package, VS: VersionSet> {
pub package_terms: SmallMap<P, Term<VS>>,
pub kind: Kind<P, VS>,
package_terms: SmallMap<P, Term<VS>>,
kind: Kind<P, VS>,
}

/// Type alias of unique identifiers for incompatibilities.
pub type IncompId<P, VS> = Id<Incompatibility<P, VS>>;

#[derive(Debug, Clone)]
pub enum Kind<P: Package, VS: VersionSet> {
enum Kind<P: Package, VS: VersionSet> {
/// Initial incompatibility aiming at picking the root package for the first decision.
NotRoot(P, VS::V),
/// There are no versions in the given range for this package.
Expand Down Expand Up @@ -105,19 +105,19 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> {
}

/// Build an incompatibility from a given dependency.
pub fn from_dependency(package: P, version: VS::V, dep: (&P, &VS)) -> Self {
pub fn from_dependency(package: P, version: VS::V, dep: (P, VS)) -> Self {
let set1 = VS::singleton(version);
let (p2, set2) = dep;
Self {
package_terms: if set2 == &VS::empty() {
package_terms: if set2 == VS::empty() {
SmallMap::One([(package.clone(), Term::Positive(set1.clone()))])
} else {
SmallMap::Two([
(package.clone(), Term::Positive(set1.clone())),
(p2.clone(), Term::Negative(set2.clone())),
])
},
kind: Kind::FromDependencyOf(package, set1, p2.clone(), set2.clone()),
kind: Kind::FromDependencyOf(package, set1, p2, set2),
}
}

Expand Down
26 changes: 7 additions & 19 deletions vendor/pubgrub/src/internal/partial_solution.rs
Expand Up @@ -165,7 +165,13 @@ impl<P: Package, VS: VersionSet, Priority: Ord + Clone> PartialSolution<P, VS, P
AssignmentsIntersection::Decision(_) => panic!("Already existing decision"),
// Cannot be called if the versions is not contained in the terms intersection.
AssignmentsIntersection::Derivations(term) => {
debug_assert!(term.contains(&version))
debug_assert!(
term.contains(&version),
"{}: {} was expected to be contained in {}",
package,
version,
term,
)
}
},
}
Expand Down Expand Up @@ -246,24 +252,6 @@ impl<P: Package, VS: VersionSet, Priority: Ord + Clone> PartialSolution<P, VS, P
}
}

pub fn prioritized_packages(&self) -> impl Iterator<Item = (&P, &VS)> {
let check_all = self.changed_this_decision_level
== self.current_decision_level.0.saturating_sub(1) as usize;
let current_decision_level = self.current_decision_level;
self.package_assignments
.get_range(self.changed_this_decision_level..)
.unwrap()
.iter()
.filter(move |(_, pa)| {
// We only actually need to update the package if its Been changed
// since the last time we called prioritize.
// Which means it's highest decision level is the current decision level,
// or if we backtracked in the mean time.
check_all || pa.highest_decision_level == current_decision_level
})
.filter_map(|(p, pa)| pa.assignments_intersection.potential_package_filter(p))
}

pub fn pick_highest_priority_pkg(
&mut self,
prioritizer: impl Fn(&P, &VS) -> Priority,
Expand Down
6 changes: 3 additions & 3 deletions vendor/pubgrub/src/internal/small_vec.rs
Expand Up @@ -166,9 +166,9 @@ impl<T> IntoIterator for SmallVec<T> {
fn into_iter(self) -> Self::IntoIter {
match self {
SmallVec::Empty => SmallVecIntoIter::Empty,
SmallVec::One(a) => SmallVecIntoIter::One(IntoIterator::into_iter(a)),
SmallVec::Two(a) => SmallVecIntoIter::Two(IntoIterator::into_iter(a)),
SmallVec::Flexible(v) => SmallVecIntoIter::Flexible(IntoIterator::into_iter(v)),
SmallVec::One(a) => SmallVecIntoIter::One(a.into_iter()),
SmallVec::Two(a) => SmallVecIntoIter::Two(a.into_iter()),
SmallVec::Flexible(v) => SmallVecIntoIter::Flexible(v.into_iter()),
}
}
}
Expand Down
9 changes: 6 additions & 3 deletions vendor/pubgrub/src/lib.rs
Expand Up @@ -102,8 +102,10 @@
//! &self,
//! package: &String,
//! version: &SemanticVersion,
//! ) -> Result<Dependencies<String, SemVS>, Box<dyn Error + Send + Sync>> {
//! unimplemented!()
//! ) -> Result<Dependencies<impl IntoIterator<Item = (String, SemVS)> + Clone>, Box<dyn Error + Send + Sync>>
//! {
//! unimplemented!();
//! Ok(Dependencies::Known([]))
//! }
//! }
//! ```
Expand Down Expand Up @@ -217,7 +219,8 @@
//! with a cache, you may want to know that some versions
//! do not exist in your cache.

#![allow(clippy::all, unreachable_pub)]
#![allow(clippy::rc_buffer)]
#![warn(missing_docs)]

pub mod error;
pub mod package;
Expand Down
21 changes: 6 additions & 15 deletions vendor/pubgrub/src/range.rs
Expand Up @@ -195,7 +195,7 @@ impl<V: Ord> Range<V> {
.segments
.last()
.expect("if there is a first element, there must be a last element");
(bound_as_ref(start), bound_as_ref(&end.1))
(start.as_ref(), end.1.as_ref())
})
}

Expand Down Expand Up @@ -264,15 +264,6 @@ impl<V: Ord> Range<V> {
}
}

/// Implementation of [`Bound::as_ref`] which is currently marked as unstable.
fn bound_as_ref<V>(bound: &Bound<V>) -> Bound<&V> {
match bound {
Included(v) => Included(v),
Excluded(v) => Excluded(v),
Unbounded => Unbounded,
}
}

fn valid_segment<T: PartialOrd>(start: &Bound<T>, end: &Bound<T>) -> bool {
match (start, end) {
(Included(s), Included(e)) => s <= e,
Expand Down Expand Up @@ -307,7 +298,7 @@ impl<V: Ord + Clone> Range<V> {

(Included(i), Excluded(e)) | (Excluded(e), Included(i)) if i <= e => Excluded(e),
(Included(i), Excluded(e)) | (Excluded(e), Included(i)) if e < i => Included(i),
(s, Unbounded) | (Unbounded, s) => bound_as_ref(s),
(s, Unbounded) | (Unbounded, s) => s.as_ref(),
_ => unreachable!(),
}
.cloned();
Expand All @@ -317,7 +308,7 @@ impl<V: Ord + Clone> Range<V> {

(Included(i), Excluded(e)) | (Excluded(e), Included(i)) if i >= e => Excluded(e),
(Included(i), Excluded(e)) | (Excluded(e), Included(i)) if e > i => Included(i),
(s, Unbounded) | (Unbounded, s) => bound_as_ref(s),
(s, Unbounded) | (Unbounded, s) => s.as_ref(),
_ => unreachable!(),
}
.cloned();
Expand Down Expand Up @@ -373,7 +364,7 @@ impl<V: Display + Eq> Display for Range<V> {
} else {
for (idx, segment) in self.segments.iter().enumerate() {
if idx > 0 {
write!(f, ", ")?;
write!(f, " | ")?;
}
match segment {
(Unbounded, Unbounded) => write!(f, "*")?,
Expand All @@ -382,9 +373,9 @@ impl<V: Display + Eq> Display for Range<V> {
(Included(v), Unbounded) => write!(f, ">={v}")?,
(Included(v), Included(b)) => {
if v == b {
write!(f, "=={v}")?
write!(f, "{v}")?
} else {
write!(f, ">={v},<={b}")?
write!(f, ">={v}, <={b}")?
}
}
(Included(v), Excluded(b)) => write!(f, ">={v}, <{b}")?,
Expand Down
35 changes: 20 additions & 15 deletions vendor/pubgrub/src/solver.rs
Expand Up @@ -73,10 +73,10 @@ use std::collections::{BTreeMap, BTreeSet as Set};
use std::error::Error;

use crate::error::PubGrubError;
pub use crate::internal::core::State;
pub use crate::internal::incompatibility::{Incompatibility, Kind};
use crate::internal::core::State;
use crate::internal::incompatibility::Incompatibility;
use crate::package::Package;
use crate::type_aliases::{DependencyConstraints, Map, SelectedDependencies};
use crate::type_aliases::{Map, SelectedDependencies};
use crate::version_set::VersionSet;
use log::{debug, info};

Expand Down Expand Up @@ -162,7 +162,7 @@ pub fn resolve<P: Package, VS: VersionSet>(
));
continue;
}
Dependencies::Known(x) if x.contains_key(p) => {
Dependencies::Known(x) if x.clone().into_iter().any(|(d, _)| &d == p) => {
return Err(PubGrubError::SelfDependency {
package: p.clone(),
version: v.clone(),
Expand All @@ -175,12 +175,12 @@ pub fn resolve<P: Package, VS: VersionSet>(
let dep_incompats = state.add_incompatibility_from_dependencies(
p.clone(),
v.clone(),
&known_dependencies,
known_dependencies,
);

state.partial_solution.add_version(
p.clone(),
v,
v.clone(),
dep_incompats,
&state.incompatibility_store,
);
Expand All @@ -196,11 +196,11 @@ pub fn resolve<P: Package, VS: VersionSet>(
/// An enum used by [DependencyProvider] that holds information about package dependencies.
/// For each [Package] there is a set of versions allowed as a dependency.
#[derive(Clone)]
pub enum Dependencies<P: Package, VS: VersionSet> {
pub enum Dependencies<T> {
/// Package dependencies are unavailable.
Unknown,
/// Container for all available package versions.
Known(DependencyConstraints<P, VS>),
Known(T),
}

/// Trait that allows the algorithm to retrieve available packages and their dependencies.
Expand Down Expand Up @@ -255,7 +255,7 @@ pub trait DependencyProvider<P: Package, VS: VersionSet> {
&self,
package: &P,
version: &VS::V,
) -> Result<Dependencies<P, VS>, Box<dyn Error + Send + Sync>>;
) -> Result<Dependencies<impl IntoIterator<Item = (P, VS)> + Clone>, Box<dyn Error + Send + Sync>>;

/// This is called fairly regularly during the resolution,
/// if it returns an Err then resolution will be terminated.
Expand All @@ -279,7 +279,7 @@ pub trait DependencyProvider<P: Package, VS: VersionSet> {
)]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct OfflineDependencyProvider<P: Package, VS: VersionSet> {
dependencies: Map<P, BTreeMap<VS::V, DependencyConstraints<P, VS>>>,
dependencies: Map<P, BTreeMap<VS::V, Map<P, VS>>>,
}

impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> {
Expand Down Expand Up @@ -329,8 +329,8 @@ impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> {

/// Lists dependencies of a given package and version.
/// Returns [None] if no information is available regarding that package and version pair.
fn dependencies(&self, package: &P, version: &VS::V) -> Option<DependencyConstraints<P, VS>> {
self.dependencies.get(package)?.get(version).cloned()
fn dependencies(&self, package: &P, version: &VS::V) -> Option<&Map<P, VS>> {
self.dependencies.get(package)?.get(version)
}
}

Expand Down Expand Up @@ -364,11 +364,16 @@ impl<P: Package, VS: VersionSet> DependencyProvider<P, VS> for OfflineDependency
fn get_dependencies(
&self,
package: &P,
version: &VS::V,
) -> Result<Dependencies<P, VS>, Box<dyn Error + Send + Sync>> {
version: &<VS as VersionSet>::V,
) -> Result<Dependencies<impl IntoIterator<Item = (P, VS)> + Clone>, Box<dyn Error + Send + Sync>>
{
Ok(match self.dependencies(package, version) {
None => Dependencies::Unknown,
Some(dependencies) => Dependencies::Known(dependencies),
Some(dependencies) => Dependencies::Known(
dependencies
.into_iter()
.map(|(p, vs)| (p.clone(), vs.clone())),
),
})
}
}
2 changes: 1 addition & 1 deletion vendor/pubgrub/src/term.rs
Expand Up @@ -64,7 +64,7 @@ impl<VS: VersionSet> Term<VS> {

/// Unwrap the set contained in a positive term.
/// Will panic if used on a negative set.
pub fn unwrap_positive(&self) -> &VS {
pub(crate) fn unwrap_positive(&self) -> &VS {
match self {
Self::Positive(set) => set,
_ => panic!("Negative term cannot unwrap positive set"),
Expand Down
7 changes: 0 additions & 7 deletions vendor/pubgrub/src/type_aliases.rs
Expand Up @@ -8,10 +8,3 @@ pub type Map<K, V> = rustc_hash::FxHashMap<K, V>;
/// Concrete dependencies picked by the library during [resolve](crate::solver::resolve)
/// from [DependencyConstraints].
pub type SelectedDependencies<P, V> = Map<P, V>;

/// Holds information about all possible versions a given package can accept.
/// There is a difference in semantics between an empty map
/// inside [DependencyConstraints] and [Dependencies::Unknown](crate::solver::Dependencies::Unknown):
/// the former means the package has no dependency and it is a known fact,
/// while the latter means they could not be fetched by the [DependencyProvider](crate::solver::DependencyProvider).
pub type DependencyConstraints<P, VS> = Map<P, VS>;

0 comments on commit 5aa15dd

Please sign in to comment.