From 00c688cad43e54fc103f979e97267e66600a32c7 Mon Sep 17 00:00:00 2001 From: Jacob Finkelman Date: Thu, 6 Feb 2025 13:03:39 -0500 Subject: [PATCH] move solver mod comment to resolver (#319) * move solver mod comment to resolver * Some nits * fix todos. removing the Version trait --- src/lib.rs | 35 +++++++-------- src/solver.rs | 115 ++++++++++++++++++++++++-------------------------- 2 files changed, 73 insertions(+), 77 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 87123373..9eb76bf2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,23 +8,6 @@ //! we should try to provide a very human-readable and clear //! explanation as to why that failed. //! -//! # Package and Version traits -//! -//! All the code in this crate is manipulating packages and versions, and for this to work -//! we defined a [Package] trait -//! that is used as bounds on most of the exposed types and functions. -//! -//! Package identifiers needs to implement our [Package] trait, -//! which is automatic if the type already implements -//! [Clone] + [Eq] + [Hash] + [Debug] + [Display](std::fmt::Display). -//! So things like [String] will work out of the box. -//! -//! TODO! This is all wrong. Need to talk about VS, not Version. -//! Our Version trait requires -//! [Clone] + [Ord] + [Debug] + [Display](std::fmt::Display). -//! For convenience, this library provides [SemanticVersion] -//! that implements semantic versioning rules. -//! //! # Basic example //! //! Let's imagine that we are building a user interface @@ -59,6 +42,24 @@ //! let solution = resolve(&dependency_provider, "root", 1u32).unwrap(); //! ``` //! +//! # Package and Version flexibility +//! +//! The [OfflineDependencyProvider] used in that example is generic over the way package names, +//! version requirements, and version numbers are represented. +//! +//! The first bound is the type of package names. It can be anything that implements our [Package] trait. +//! The [Package] trait is automatic if the type already implements +//! [Clone] + [Eq] + [Hash] + [Debug] + [Display](std::fmt::Display). +//! So things like [String] will work out of the box. +//! +//! The second bound is the type of package requirements. It can be anything that implements our [VersionSet] trait. +//! This trait is used to figure out how version requirements are combined. +//! If the normal [Ord]/[PartialEq] operations are all that is needed for requirements, our [Ranges] type will work. +//! +//! The chosen `VersionSet` in turn specifies what can be used for version numbers. +//! This type needs to at least implement [Clone] + [Ord] + [Debug] + [Display](std::fmt::Display). +//! For convenience, this library provides [SemanticVersion] that implements the basics of semantic versioning rules. +//! //! # DependencyProvider trait //! //! In our previous example we used the diff --git a/src/solver.rs b/src/solver.rs index e1d0b687..5d8c0560 100644 --- a/src/solver.rs +++ b/src/solver.rs @@ -1,64 +1,5 @@ // SPDX-License-Identifier: MPL-2.0 -//! PubGrub version solving algorithm. -//! -//! It consists in efficiently finding a set of packages and versions -//! that satisfy all the constraints of a given project dependencies. -//! In addition, when that is not possible, -//! PubGrub tries to provide a very human-readable and clear -//! explanation as to why that failed. -//! Below is an example of explanation present in -//! the introductory blog post about PubGrub -//! -//! ```txt -//! Because dropdown >=2.0.0 depends on icons >=2.0.0 and -//! root depends on icons <2.0.0, dropdown >=2.0.0 is forbidden. -//! -//! And because menu >=1.1.0 depends on dropdown >=2.0.0, -//! menu >=1.1.0 is forbidden. -//! -//! And because menu <1.1.0 depends on dropdown >=1.0.0 <2.0.0 -//! which depends on intl <4.0.0, every version of menu -//! requires intl <4.0.0. -//! -//! So, because root depends on both menu >=1.0.0 and intl >=5.0.0, -//! version solving failed. -//! ``` -//! -//! The algorithm is generic and works for any type of dependency system -//! as long as packages (P) and versions (V) implement -//! the [Package] and Version traits. -//! [Package] is strictly equivalent and automatically generated -//! for any type that implement [Clone] + [Eq] + [Hash] + [Debug] + [Display]. -//! -//! ## API -//! -//! ``` -//! # use std::convert::Infallible; -//! # use pubgrub::{resolve, OfflineDependencyProvider, PubGrubError, Ranges}; -//! # -//! # type NumVS = Ranges; -//! # -//! # fn try_main() -> Result<(), PubGrubError>> { -//! # let dependency_provider = OfflineDependencyProvider::<&str, NumVS>::new(); -//! # let package = "root"; -//! # let version = 1u32; -//! let solution = resolve(&dependency_provider, package, version)?; -//! # Ok(()) -//! # } -//! # fn main() { -//! # assert!(matches!(try_main(), Err(PubGrubError::NoSolution(_)))); -//! # } -//! ``` -//! -//! Where `dependency_provider` supplies the list of available packages and versions, -//! as well as the dependencies of every available package -//! by implementing the [DependencyProvider] trait. -//! The call to [resolve] for a given package at a given version -//! will compute the set of packages and versions needed -//! to satisfy the dependencies of that package and version pair. -//! If there is no solution, the reason will be provided as clear as possible. - use std::collections::BTreeSet as Set; use std::error::Error; use std::fmt::{Debug, Display}; @@ -107,8 +48,62 @@ impl PackageResolutionStatistics { } } -/// Main function of the library. /// Finds a set of packages satisfying dependency bounds for a given package + version pair. +/// +/// It consists in efficiently finding a set of packages and versions +/// that satisfy all the constraints of a given project dependencies. +/// In addition, when that is not possible, +/// PubGrub tries to provide a very human-readable and clear +/// explanation as to why that failed. +/// Below is an example of explanation present in +/// the introductory blog post about PubGrub +/// (Although this crate is not yet capable of building formatting quite this nice.) +/// +/// ```txt +/// Because dropdown >=2.0.0 depends on icons >=2.0.0 and +/// root depends on icons <2.0.0, dropdown >=2.0.0 is forbidden. +/// +/// And because menu >=1.1.0 depends on dropdown >=2.0.0, +/// menu >=1.1.0 is forbidden. +/// +/// And because menu <1.1.0 depends on dropdown >=1.0.0 <2.0.0 +/// which depends on intl <4.0.0, every version of menu +/// requires intl <4.0.0. +/// +/// So, because root depends on both menu >=1.0.0 and intl >=5.0.0, +/// version solving failed. +/// ``` +/// +/// Is generic over an implementation of [DependencyProvider] which represents where the dependency constraints come from. +/// The associated types on the DependencyProvider allow flexibility for the representation of +/// package names, version requirements, version numbers, and other things. +/// See its documentation for more details. +/// For simple cases [OfflineDependencyProvider](crate::OfflineDependencyProvider) may be sufficient. +/// +/// ## API +/// +/// ``` +/// # use std::convert::Infallible; +/// # use pubgrub::{resolve, OfflineDependencyProvider, PubGrubError, Ranges}; +/// # +/// # type NumVS = Ranges; +/// # +/// # fn try_main() -> Result<(), PubGrubError>> { +/// # let dependency_provider = OfflineDependencyProvider::<&str, NumVS>::new(); +/// # let package = "root"; +/// # let version = 1u32; +/// let solution = resolve(&dependency_provider, package, version)?; +/// # Ok(()) +/// # } +/// # fn main() { +/// # assert!(matches!(try_main(), Err(PubGrubError::NoSolution(_)))); +/// # } +/// ``` +/// +/// The call to [resolve] for a given package at a given version +/// will compute the set of packages and versions needed +/// to satisfy the dependencies of that package and version pair. +/// If there is no solution, the reason will be provided as clear as possible. #[cold] pub fn resolve( dependency_provider: &DP,