Skip to content

Commit 05fbc2f

Browse files
mpizenbergzanieb
authored andcommitted
feat: use a VersionSet trait instead of Range (pubgrub-rs#108)
* refactor: introduce a trait for sets of versions * refactor: port report and incompatibility to version set * refactor: port errors to version set * refactor: port partial solution to version set * refactor: move DependencyConstraints to type_aliases * refactor: port core to version set * refactor: port solver to version set * refactor: replace old modules with ones based on version_set * refactor: update tests to version_set * feat: add serde bounds to OfflineDependencyProvider * refactor: update proptest.rs to VersionSet * docs: fix links * refactor: allow clippy type_complexity * Small docs changes
1 parent 25147a3 commit 05fbc2f

21 files changed

+477
-364
lines changed

examples/branching_error_reporting.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ use pubgrub::report::{DefaultStringReporter, Reporter};
66
use pubgrub::solver::{resolve, OfflineDependencyProvider};
77
use pubgrub::version::SemanticVersion;
88

9+
type SemVS = Range<SemanticVersion>;
10+
911
// https://github.com/dart-lang/pub/blob/master/doc/solver.md#branching-error-reporting
1012
fn main() {
11-
let mut dependency_provider = OfflineDependencyProvider::<&str, SemanticVersion>::new();
13+
let mut dependency_provider = OfflineDependencyProvider::<&str, SemVS>::new();
1214
#[rustfmt::skip]
1315
// root 1.0.0 depends on foo ^1.0.0
1416
dependency_provider.add_dependencies(

examples/caching_dependency_provider.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@ use std::error::Error;
66
use pubgrub::package::Package;
77
use pubgrub::range::Range;
88
use pubgrub::solver::{resolve, Dependencies, DependencyProvider, OfflineDependencyProvider};
9-
use pubgrub::version::{NumberVersion, Version};
9+
use pubgrub::version::NumberVersion;
10+
use pubgrub::version_set::VersionSet;
11+
12+
type NumVS = Range<NumberVersion>;
1013

1114
// An example implementing caching dependency provider that will
1215
// store queried dependencies in memory and check them before querying more from remote.
13-
struct CachingDependencyProvider<P: Package, V: Version, DP: DependencyProvider<P, V>> {
16+
struct CachingDependencyProvider<P: Package, VS: VersionSet, DP: DependencyProvider<P, VS>> {
1417
remote_dependencies: DP,
15-
cached_dependencies: RefCell<OfflineDependencyProvider<P, V>>,
18+
cached_dependencies: RefCell<OfflineDependencyProvider<P, VS>>,
1619
}
1720

18-
impl<P: Package, V: Version, DP: DependencyProvider<P, V>> CachingDependencyProvider<P, V, DP> {
21+
impl<P: Package, VS: VersionSet, DP: DependencyProvider<P, VS>>
22+
CachingDependencyProvider<P, VS, DP>
23+
{
1924
pub fn new(remote_dependencies_provider: DP) -> Self {
2025
CachingDependencyProvider {
2126
remote_dependencies: remote_dependencies_provider,
@@ -24,22 +29,22 @@ impl<P: Package, V: Version, DP: DependencyProvider<P, V>> CachingDependencyProv
2429
}
2530
}
2631

27-
impl<P: Package, V: Version, DP: DependencyProvider<P, V>> DependencyProvider<P, V>
28-
for CachingDependencyProvider<P, V, DP>
32+
impl<P: Package, VS: VersionSet, DP: DependencyProvider<P, VS>> DependencyProvider<P, VS>
33+
for CachingDependencyProvider<P, VS, DP>
2934
{
30-
fn choose_package_version<T: std::borrow::Borrow<P>, U: std::borrow::Borrow<Range<V>>>(
35+
fn choose_package_version<T: std::borrow::Borrow<P>, U: std::borrow::Borrow<VS>>(
3136
&self,
3237
packages: impl Iterator<Item = (T, U)>,
33-
) -> Result<(T, Option<V>), Box<dyn Error>> {
38+
) -> Result<(T, Option<VS::V>), Box<dyn Error>> {
3439
self.remote_dependencies.choose_package_version(packages)
3540
}
3641

3742
// Caches dependencies if they were already queried
3843
fn get_dependencies(
3944
&self,
4045
package: &P,
41-
version: &V,
42-
) -> Result<Dependencies<P, V>, Box<dyn Error>> {
46+
version: &VS::V,
47+
) -> Result<Dependencies<P, VS>, Box<dyn Error>> {
4348
let mut cache = self.cached_dependencies.borrow_mut();
4449
match cache.get_dependencies(package, version) {
4550
Ok(Dependencies::Unknown) => {
@@ -65,7 +70,7 @@ impl<P: Package, V: Version, DP: DependencyProvider<P, V>> DependencyProvider<P,
6570

6671
fn main() {
6772
// Simulating remote provider locally.
68-
let mut remote_dependencies_provider = OfflineDependencyProvider::<&str, NumberVersion>::new();
73+
let mut remote_dependencies_provider = OfflineDependencyProvider::<&str, NumVS>::new();
6974

7075
// Add dependencies as needed. Here only root package is added.
7176
remote_dependencies_provider.add_dependencies("root", 1, Vec::new());

examples/doc_interface.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ use pubgrub::range::Range;
44
use pubgrub::solver::{resolve, OfflineDependencyProvider};
55
use pubgrub::version::NumberVersion;
66

7+
type NumVS = Range<NumberVersion>;
8+
79
// `root` depends on `menu` and `icons`
810
// `menu` depends on `dropdown`
911
// `dropdown` depends on `icons`
1012
// `icons` has no dependency
1113
#[rustfmt::skip]
1214
fn main() {
13-
let mut dependency_provider = OfflineDependencyProvider::<&str, NumberVersion>::new();
15+
let mut dependency_provider = OfflineDependencyProvider::<&str, NumVS>::new();
1416
dependency_provider.add_dependencies(
1517
"root", 1, [("menu", Range::any()), ("icons", Range::any())],
1618
);

examples/doc_interface_error.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use pubgrub::report::{DefaultStringReporter, Reporter};
66
use pubgrub::solver::{resolve, OfflineDependencyProvider};
77
use pubgrub::version::SemanticVersion;
88

9+
type SemVS = Range<SemanticVersion>;
10+
911
// `root` depends on `menu`, `icons 1.0.0` and `intl 5.0.0`
1012
// `menu 1.0.0` depends on `dropdown < 2.0.0`
1113
// `menu >= 1.1.0` depends on `dropdown >= 2.0.0`
@@ -15,7 +17,7 @@ use pubgrub::version::SemanticVersion;
1517
// `intl` has no dependency
1618
#[rustfmt::skip]
1719
fn main() {
18-
let mut dependency_provider = OfflineDependencyProvider::<&str, SemanticVersion>::new();
20+
let mut dependency_provider = OfflineDependencyProvider::<&str, SemVS>::new();
1921
// Direct dependencies: menu and icons.
2022
dependency_provider.add_dependencies("root", (1, 0, 0), [
2123
("menu", Range::any()),

examples/doc_interface_semantic.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use pubgrub::report::{DefaultStringReporter, Reporter};
66
use pubgrub::solver::{resolve, OfflineDependencyProvider};
77
use pubgrub::version::SemanticVersion;
88

9+
type SemVS = Range<SemanticVersion>;
10+
911
// `root` depends on `menu` and `icons 1.0.0`
1012
// `menu 1.0.0` depends on `dropdown < 2.0.0`
1113
// `menu >= 1.1.0` depends on `dropdown >= 2.0.0`
@@ -14,7 +16,7 @@ use pubgrub::version::SemanticVersion;
1416
// `icons` has no dependency
1517
#[rustfmt::skip]
1618
fn main() {
17-
let mut dependency_provider = OfflineDependencyProvider::<&str, SemanticVersion>::new();
19+
let mut dependency_provider = OfflineDependencyProvider::<&str, SemVS>::new();
1820
// Direct dependencies: menu and icons.
1921
dependency_provider.add_dependencies("root", (1, 0, 0), [
2022
("menu", Range::any()),

examples/linear_error_reporting.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ use pubgrub::report::{DefaultStringReporter, Reporter};
66
use pubgrub::solver::{resolve, OfflineDependencyProvider};
77
use pubgrub::version::SemanticVersion;
88

9+
type SemVS = Range<SemanticVersion>;
10+
911
// https://github.com/dart-lang/pub/blob/master/doc/solver.md#linear-error-reporting
1012
fn main() {
11-
let mut dependency_provider = OfflineDependencyProvider::<&str, SemanticVersion>::new();
13+
let mut dependency_provider = OfflineDependencyProvider::<&str, SemVS>::new();
1214
#[rustfmt::skip]
1315
// root 1.0.0 depends on foo ^1.0.0 and baz ^1.0.0
1416
dependency_provider.add_dependencies(

src/error.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ use thiserror::Error;
66

77
use crate::package::Package;
88
use crate::report::DerivationTree;
9-
use crate::version::Version;
9+
use crate::version_set::VersionSet;
1010

1111
/// Errors that may occur while solving dependencies.
1212
#[derive(Error, Debug)]
13-
pub enum PubGrubError<P: Package, V: Version> {
13+
pub enum PubGrubError<P: Package, VS: VersionSet> {
1414
/// There is no solution for this set of dependencies.
1515
#[error("No solution")]
16-
NoSolution(DerivationTree<P, V>),
16+
NoSolution(DerivationTree<P, VS>),
1717

1818
/// Error arising when the implementer of
1919
/// [DependencyProvider](crate::solver::DependencyProvider)
@@ -24,7 +24,7 @@ pub enum PubGrubError<P: Package, V: Version> {
2424
/// Package whose dependencies we want.
2525
package: P,
2626
/// Version of the package for which we want the dependencies.
27-
version: V,
27+
version: VS::V,
2828
/// Error raised by the implementer of
2929
/// [DependencyProvider](crate::solver::DependencyProvider).
3030
source: Box<dyn std::error::Error>,
@@ -40,7 +40,7 @@ pub enum PubGrubError<P: Package, V: Version> {
4040
/// Package whose dependencies we want.
4141
package: P,
4242
/// Version of the package for which we want the dependencies.
43-
version: V,
43+
version: VS::V,
4444
/// The dependent package that requires us to pick from the empty set.
4545
dependent: P,
4646
},
@@ -55,7 +55,7 @@ pub enum PubGrubError<P: Package, V: Version> {
5555
/// Package whose dependencies we want.
5656
package: P,
5757
/// Version of the package for which we want the dependencies.
58-
version: V,
58+
version: VS::V,
5959
},
6060

6161
/// Error arising when the implementer of

src/internal/core.rs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,38 +15,37 @@ use crate::internal::partial_solution::{DecisionLevel, PartialSolution};
1515
use crate::internal::small_vec::SmallVec;
1616
use crate::package::Package;
1717
use crate::report::DerivationTree;
18-
use crate::solver::DependencyConstraints;
19-
use crate::type_aliases::Map;
20-
use crate::version::Version;
18+
use crate::type_aliases::{DependencyConstraints, Map};
19+
use crate::version_set::VersionSet;
2120

2221
/// Current state of the PubGrub algorithm.
2322
#[derive(Clone)]
24-
pub struct State<P: Package, V: Version> {
23+
pub struct State<P: Package, VS: VersionSet> {
2524
root_package: P,
26-
root_version: V,
25+
root_version: VS::V,
2726

28-
incompatibilities: Map<P, Vec<IncompId<P, V>>>,
27+
incompatibilities: Map<P, Vec<IncompId<P, VS>>>,
2928

3029
/// Store the ids of incompatibilities that are already contradicted
3130
/// and will stay that way until the next conflict and backtrack is operated.
32-
contradicted_incompatibilities: rustc_hash::FxHashSet<IncompId<P, V>>,
31+
contradicted_incompatibilities: rustc_hash::FxHashSet<IncompId<P, VS>>,
3332

3433
/// Partial solution.
3534
/// TODO: remove pub.
36-
pub partial_solution: PartialSolution<P, V>,
35+
pub partial_solution: PartialSolution<P, VS>,
3736

3837
/// The store is the reference storage for all incompatibilities.
39-
pub incompatibility_store: Arena<Incompatibility<P, V>>,
38+
pub incompatibility_store: Arena<Incompatibility<P, VS>>,
4039

4140
/// This is a stack of work to be done in `unit_propagation`.
4241
/// It can definitely be a local variable to that method, but
4342
/// this way we can reuse the same allocation for better performance.
4443
unit_propagation_buffer: SmallVec<P>,
4544
}
4645

47-
impl<P: Package, V: Version> State<P, V> {
46+
impl<P: Package, VS: VersionSet> State<P, VS> {
4847
/// Initialization of PubGrub state.
49-
pub fn init(root_package: P, root_version: V) -> Self {
48+
pub fn init(root_package: P, root_version: VS::V) -> Self {
5049
let mut incompatibility_store = Arena::new();
5150
let not_root_id = incompatibility_store.alloc(Incompatibility::not_root(
5251
root_package.clone(),
@@ -66,7 +65,7 @@ impl<P: Package, V: Version> State<P, V> {
6665
}
6766

6867
/// Add an incompatibility to the state.
69-
pub fn add_incompatibility(&mut self, incompat: Incompatibility<P, V>) {
68+
pub fn add_incompatibility(&mut self, incompat: Incompatibility<P, VS>) {
7069
let id = self.incompatibility_store.alloc(incompat);
7170
self.merge_incompatibility(id);
7271
}
@@ -75,9 +74,9 @@ impl<P: Package, V: Version> State<P, V> {
7574
pub fn add_incompatibility_from_dependencies(
7675
&mut self,
7776
package: P,
78-
version: V,
79-
deps: &DependencyConstraints<P, V>,
80-
) -> std::ops::Range<IncompId<P, V>> {
77+
version: VS::V,
78+
deps: &DependencyConstraints<P, VS>,
79+
) -> std::ops::Range<IncompId<P, VS>> {
8180
// Create incompatibilities and allocate them in the store.
8281
let new_incompats_id_range = self
8382
.incompatibility_store
@@ -92,13 +91,13 @@ impl<P: Package, V: Version> State<P, V> {
9291
}
9392

9493
/// Check if an incompatibility is terminal.
95-
pub fn is_terminal(&self, incompatibility: &Incompatibility<P, V>) -> bool {
94+
pub fn is_terminal(&self, incompatibility: &Incompatibility<P, VS>) -> bool {
9695
incompatibility.is_terminal(&self.root_package, &self.root_version)
9796
}
9897

9998
/// Unit propagation is the core mechanism of the solving algorithm.
10099
/// CF <https://github.com/dart-lang/pub/blob/master/doc/solver.md#unit-propagation>
101-
pub fn unit_propagation(&mut self, package: P) -> Result<(), PubGrubError<P, V>> {
100+
pub fn unit_propagation(&mut self, package: P) -> Result<(), PubGrubError<P, VS>> {
102101
self.unit_propagation_buffer.clear();
103102
self.unit_propagation_buffer.push(package);
104103
while let Some(current_package) = self.unit_propagation_buffer.pop() {
@@ -162,8 +161,8 @@ impl<P: Package, V: Version> State<P, V> {
162161
/// CF <https://github.com/dart-lang/pub/blob/master/doc/solver.md#unit-propagation>
163162
fn conflict_resolution(
164163
&mut self,
165-
incompatibility: IncompId<P, V>,
166-
) -> Result<(P, IncompId<P, V>), PubGrubError<P, V>> {
164+
incompatibility: IncompId<P, VS>,
165+
) -> Result<(P, IncompId<P, VS>), PubGrubError<P, VS>> {
167166
let mut current_incompat_id = incompatibility;
168167
let mut current_incompat_changed = false;
169168
loop {
@@ -209,7 +208,7 @@ impl<P: Package, V: Version> State<P, V> {
209208
/// Backtracking.
210209
fn backtrack(
211210
&mut self,
212-
incompat: IncompId<P, V>,
211+
incompat: IncompId<P, VS>,
213212
incompat_changed: bool,
214213
decision_level: DecisionLevel,
215214
) {
@@ -240,7 +239,7 @@ impl<P: Package, V: Version> State<P, V> {
240239
/// Here we do the simple stupid thing of just growing the Vec.
241240
/// It may not be trivial since those incompatibilities
242241
/// may already have derived others.
243-
fn merge_incompatibility(&mut self, id: IncompId<P, V>) {
242+
fn merge_incompatibility(&mut self, id: IncompId<P, VS>) {
244243
for (pkg, _term) in self.incompatibility_store[id].iter() {
245244
self.incompatibilities
246245
.entry(pkg.clone())
@@ -251,12 +250,12 @@ impl<P: Package, V: Version> State<P, V> {
251250

252251
// Error reporting #########################################################
253252

254-
fn build_derivation_tree(&self, incompat: IncompId<P, V>) -> DerivationTree<P, V> {
253+
fn build_derivation_tree(&self, incompat: IncompId<P, VS>) -> DerivationTree<P, VS> {
255254
let shared_ids = self.find_shared_ids(incompat);
256255
Incompatibility::build_derivation_tree(incompat, &shared_ids, &self.incompatibility_store)
257256
}
258257

259-
fn find_shared_ids(&self, incompat: IncompId<P, V>) -> Set<IncompId<P, V>> {
258+
fn find_shared_ids(&self, incompat: IncompId<P, VS>) -> Set<IncompId<P, VS>> {
260259
let mut all_ids = Set::new();
261260
let mut shared_ids = Set::new();
262261
let mut stack = vec![incompat];

0 commit comments

Comments
 (0)