Skip to content

Commit f1608ec

Browse files
committed
Add much doc on the crate home page
1 parent e24c0f4 commit f1608ec

File tree

2 files changed

+159
-1
lines changed

2 files changed

+159
-1
lines changed

examples/doc_interface.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ fn main() {
1818
solver.add_dependencies("icons", 1, vec![]);
1919

2020
// Run the solver.
21-
let _solution = solver.run("root", 1).unwrap();
21+
let solution = solver.run("root", 1).unwrap();
22+
println!("Solution: {:?}", solution);
2223
}

src/lib.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,163 @@
33
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

55
//! PubGrub version solving algorithm.
6+
//!
7+
//! Version solving consists in efficiently finding a set of packages and versions
8+
//! that satisfy all the constraints of a given project dependencies.
9+
//! In addition, when that is not possible,
10+
//! we should try to provide a very human-readable and clear
11+
//! explanation as to why that failed.
12+
//!
13+
//! # Package and Version traits
14+
//!
15+
//! All the code in this crate is manipulating packages and versions,
16+
//! and for this to work, we defined a `Package` and `Version` traits,
17+
//! that are used as bounds on most of the exposed types and functions.
18+
//!
19+
//! Package identifiers needs to implement our `Package` trait,
20+
//! which is automatic if the type already implements
21+
//! `Clone + Eq + Hash + Debug + Display`.
22+
//! So things like `String` will work out of the box.
23+
//!
24+
//! Our `Version` trait requires `Clone + Ord + Debug + Display`
25+
//! and also the definition of two methods,
26+
//! `lowest() -> Self` which returns the lowest version existing,
27+
//! and `bump(&self) -> Self` which returns the next smallest version
28+
//! strictly higher than the current one.
29+
//! For convenience, this library already provides two implementations of `Version`.
30+
//! The first one is `NumberVersion`, basically a newtype for `usize`.
31+
//! The second one is `SemanticVersion` that implements semantic versionning rules.
32+
//!
33+
//! # Basic example
34+
//!
35+
//! Let's imagine that we are building a user interface
36+
//! with a menu containing dropdowns with some icons,
37+
//! icons that we are also directly using in other parts of the interface.
38+
//! For this scenario our direct dependencies are `menu` and `icons`,
39+
//! but the complete set of dependencies looks like follows:
40+
//!
41+
//! - `root` depends on `menu` and `icons`
42+
//! - `menu` depends on `dropdown`
43+
//! - `dropdown` depends on `icons`
44+
//! - `icons` has no dependency
45+
//!
46+
//! We can model that scenario with this library as follows
47+
//! (don't worry about the `SimpleCache` name for now):
48+
//! ```ignore
49+
//! let mut solver = SimpleCache::<&str, NumberVersion>::new();
50+
//! solver.add_dependencies(
51+
//! "root", 1, vec![("menu", Range::any()), ("icons", Range::any())],
52+
//! );
53+
//! solver.add_dependencies("menu", 1, vec![("dropdown", Range::any())]);
54+
//! solver.add_dependencies("dropdown", 1, vec![("icons", Range::any())]);
55+
//! solver.add_dependencies("icons", 1, vec![]);
56+
//!
57+
//! // Run the solver.
58+
//! let _solution = solver.run("root", 1).unwrap();
59+
//! ```
60+
//!
61+
//! # Solver trait
62+
//!
63+
//! In our previous example we used the `SimpleCache` type
64+
//! to initialiaze the solver.
65+
//! `SimpleCache` is a basic implementation of the `Cache`
66+
//! trait, that we will explain in a moment and that automatically
67+
//! implements the `Solver` trait for convenience.
68+
//!
69+
//! But we might want to implement the `Solver` trait for our own type.
70+
//! Let's say that we will use `String` for packages,
71+
//! and `SemanticVersion` for versions.
72+
//! This may be done quite easily by implementing the two following functions.
73+
//! ```ignore
74+
//! impl Solver<String, SemanticVersion> for MySolver {
75+
//! fn list_available_versions(
76+
//! &mut self,
77+
//! package: &String
78+
//! ) -> Result<Vec<SemanticVersion>, Box<dyn Error>> {
79+
//! ...
80+
//! }
81+
//!
82+
//! fn get_dependencies(
83+
//! &mut self,
84+
//! package: &String,
85+
//! version: &SemanticVersion,
86+
//! ) -> Result<Option<Map<String, Range<SemanticVersion>>>, Box<dyn Error>> {
87+
//! ...
88+
//! }
89+
//! }
90+
//! ```
91+
//! The first method `list_available_versions` should return all available
92+
//! versions of a package.
93+
//! The second method `get_dependencies` aims at retrieving the dependencies
94+
//! of a given package at a given version.
95+
//! Return `None` if dependencies are unknown.
96+
//!
97+
//! On a real scenario, these two methods may involve reading the file system
98+
//! or doing network request, so you may want to hold a cache in your `MySolver` type.
99+
//! You could use the `SimpleCache` type provided by the crate as guidance,
100+
//! but you are free to use whatever approach
101+
//! makes sense in your situation.
102+
//!
103+
//! # Solution and error reporting
104+
//!
105+
//! When everything goes well, the solver finds and returns the complete
106+
//! set of direct and indirect dependencies satisfying all the constraints.
107+
//! The packages and versions selected are returned in a `HashMap<P, V>`.
108+
//! But sometimes there is no solution because dependencies are incompatible.
109+
//! In such cases, `solver.run(...)` returns a
110+
//! `PubGrubError::NoSolution(derivation_tree)`,
111+
//! where the provided derivation tree is a custom binary tree
112+
//! containing the full chain of reasons why there is no solution.
113+
//!
114+
//! All the items in the tree are called incompatibilities
115+
//! and may be of two types, either "external" or "derived".
116+
//! Leafs of the tree are external incompatibilities,
117+
//! and nodes are derived.
118+
//! External incompatibilities have reasons that are independent
119+
//! of the way this solver is implemented such as
120+
//! - dependencies: "package_a" at version 1 depends on "package_b" at version 4
121+
//! - missing dependencies: dependencies of "package_a" are unknown
122+
//! - absence of version: there is no version of "package_a" in the range [3.1.0 4.0.0[
123+
//!
124+
//! Derived incompatibilities are obtained by the solver by deduction,
125+
//! such as if "a" depends on "b" and "b" depends on "c", "a" depends on "c".
126+
//!
127+
//! This crate defines a `Reporter` trait, with an associated `Output` type
128+
//! and a single method
129+
//! ```ignore
130+
//! report(derivation_tree: &DerivationTree<P, V>) -> Output
131+
//! ```
132+
//! Implementing a `Reporter` may involve a lot of heuristics
133+
//! to make the output human-readable and natural.
134+
//! For convenience, we provide a default implementation
135+
//! `DefaultStringReporter`, that output the report as a String.
136+
//! You may use it as follows:
137+
//! ```ignore
138+
//! match solver.run(root_package, root_version) {
139+
//! Ok(solution) => println!("{:?}", solution),
140+
//! Err(PubGrubError::NoSolution(mut derivation_tree)) => {
141+
//! derivation_tree.collapse_noversion();
142+
//! eprintln!("{}", DefaultStringReporter::report(&derivation_tree));
143+
//! }
144+
//! Err(err) => panic!("{:?}", err),
145+
//! };
146+
//! ```
147+
//! Notice that we also used `collapse_noversion()` above.
148+
//! This method simplifies the derivation tree to get rid
149+
//! of the `NoVersion` external incompatibilities in the derivation tree.
150+
//! So instead of seing things like this in the report:
151+
//! ```txt
152+
//! Because there is no version of foo in 1.0.1 <= v < 2.0.0
153+
//! and foo 1.0.0 depends on bar 2.0.0 <= v < 3.0.0,
154+
//! foo 1.0.0 <= v < 2.0.0 depends on bar 2.0.0 <= v < 3.0.0.
155+
//! ```
156+
//! you may have directly:
157+
//! ```txt
158+
//! foo 1.0.0 <= v < 2.0.0 depends on bar 2.0.0 <= v < 3.0.0.
159+
//! ```
160+
//! Beware though that if you are using some kind of offline mode
161+
//! with a cache, you may want to know that some versions
162+
//! do not exist in your cache.
6163
7164
#![warn(missing_docs)]
8165

0 commit comments

Comments
 (0)