Skip to content

Commit

Permalink
Move offline provider into a separate module (#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
x-hgg-x authored Nov 20, 2024
1 parent 8a29d57 commit 4bde6d6
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 116 deletions.
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@

mod error;
mod package;
mod provider;
mod report;
mod solver;
mod term;
Expand All @@ -221,11 +222,12 @@ mod version_set;

pub use error::{NoSolutionError, PubGrubError};
pub use package::Package;
pub use provider::OfflineDependencyProvider;
pub use report::{
DefaultStringReportFormatter, DefaultStringReporter, DerivationTree, Derived, External,
ReportFormatter, Reporter,
};
pub use solver::{resolve, Dependencies, DependencyProvider, OfflineDependencyProvider};
pub use solver::{resolve, Dependencies, DependencyProvider};
pub use term::Term;
pub use type_aliases::{DependencyConstraints, Map, SelectedDependencies, Set};
pub use version::{SemanticVersion, VersionParseError};
Expand Down
120 changes: 120 additions & 0 deletions src/provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use std::cmp::Reverse;
use std::collections::BTreeMap;
use std::convert::Infallible;

use crate::{Dependencies, DependencyConstraints, DependencyProvider, Map, Package, VersionSet};

/// A basic implementation of [DependencyProvider].
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serde",
serde(bound(
serialize = "VS::V: serde::Serialize, VS: serde::Serialize, P: serde::Serialize",
deserialize = "VS::V: serde::Deserialize<'de>, VS: serde::Deserialize<'de>, P: serde::Deserialize<'de>"
))
)]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct OfflineDependencyProvider<P: Package, VS: VersionSet> {
dependencies: Map<P, BTreeMap<VS::V, DependencyConstraints<P, VS>>>,
}

impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> {
/// Creates an empty OfflineDependencyProvider with no dependencies.
pub fn new() -> Self {
Self {
dependencies: Map::default(),
}
}

/// Registers the dependencies of a package and version pair.
/// Dependencies must be added with a single call to
/// [add_dependencies](OfflineDependencyProvider::add_dependencies).
/// All subsequent calls to
/// [add_dependencies](OfflineDependencyProvider::add_dependencies) for a given
/// package version pair will replace the dependencies by the new ones.
///
/// The API does not allow to add dependencies one at a time to uphold an assumption that
/// [OfflineDependencyProvider.get_dependencies(p, v)](OfflineDependencyProvider::get_dependencies)
/// provides all dependencies of a given package (p) and version (v) pair.
pub fn add_dependencies<I: IntoIterator<Item = (P, VS)>>(
&mut self,
package: P,
version: impl Into<VS::V>,
dependencies: I,
) {
let package_deps = dependencies.into_iter().collect();
let v = version.into();
*self
.dependencies
.entry(package)
.or_default()
.entry(v)
.or_default() = package_deps;
}

/// Lists packages that have been saved.
pub fn packages(&self) -> impl Iterator<Item = &P> {
self.dependencies.keys()
}

/// Lists versions of saved packages in sorted order.
/// Returns [None] if no information is available regarding that package.
pub fn versions(&self, package: &P) -> Option<impl Iterator<Item = &VS::V>> {
self.dependencies.get(package).map(|k| k.keys())
}

/// 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()
}
}

/// An implementation of [DependencyProvider] that
/// contains all dependency information available in memory.
/// Currently packages are picked with the fewest versions contained in the constraints first.
/// But, that may change in new versions if better heuristics are found.
/// Versions are picked with the newest versions first.
impl<P: Package, VS: VersionSet> DependencyProvider for OfflineDependencyProvider<P, VS> {
type P = P;
type V = VS::V;
type VS = VS;
type M = String;

type Err = Infallible;

#[inline]
fn choose_version(&self, package: &P, range: &VS) -> Result<Option<VS::V>, Infallible> {
Ok(self
.dependencies
.get(package)
.and_then(|versions| versions.keys().rev().find(|v| range.contains(v)).cloned()))
}

type Priority = Reverse<usize>;

#[inline]
fn prioritize(&self, package: &P, range: &VS) -> Self::Priority {
Reverse(
self.dependencies
.get(package)
.map(|versions| versions.keys().filter(|v| range.contains(v)).count())
.unwrap_or(0),
)
}

#[inline]
fn get_dependencies(
&self,
package: &P,
version: &VS::V,
) -> Result<Dependencies<P, VS, Self::M>, Infallible> {
Ok(match self.dependencies(package, version) {
None => {
Dependencies::Unavailable("its dependencies could not be determined".to_string())
}
Some(dependencies) => Dependencies::Available(dependencies),
})
}
}
117 changes: 2 additions & 115 deletions src/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@
//! 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::cmp::Reverse;
use std::collections::{BTreeMap, BTreeSet as Set};
use std::convert::Infallible;
use std::collections::BTreeSet as Set;
use std::error::Error;
use std::fmt::{Debug, Display};

Expand Down Expand Up @@ -244,7 +242,7 @@ pub trait DependencyProvider {
/// The type returned from `prioritize`. The resolver does not care what type this is
/// as long as it can pick a largest one and clone it.
///
/// [Reverse] can be useful if you want to pick the package with
/// [`Reverse`](std::cmp::Reverse) can be useful if you want to pick the package with
/// the fewest versions that match the outstanding constraint.
type Priority: Ord + Clone;

Expand Down Expand Up @@ -280,114 +278,3 @@ pub trait DependencyProvider {
Ok(())
}
}

/// A basic implementation of [DependencyProvider].
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serde",
serde(bound(
serialize = "VS::V: serde::Serialize, VS: serde::Serialize, P: serde::Serialize",
deserialize = "VS::V: serde::Deserialize<'de>, VS: serde::Deserialize<'de>, P: serde::Deserialize<'de>"
))
)]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct OfflineDependencyProvider<P: Package, VS: VersionSet> {
dependencies: Map<P, BTreeMap<VS::V, DependencyConstraints<P, VS>>>,
}

impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> {
/// Creates an empty OfflineDependencyProvider with no dependencies.
pub fn new() -> Self {
Self {
dependencies: Map::default(),
}
}

/// Registers the dependencies of a package and version pair.
/// Dependencies must be added with a single call to
/// [add_dependencies](OfflineDependencyProvider::add_dependencies).
/// All subsequent calls to
/// [add_dependencies](OfflineDependencyProvider::add_dependencies) for a given
/// package version pair will replace the dependencies by the new ones.
///
/// The API does not allow to add dependencies one at a time to uphold an assumption that
/// [OfflineDependencyProvider.get_dependencies(p, v)](OfflineDependencyProvider::get_dependencies)
/// provides all dependencies of a given package (p) and version (v) pair.
pub fn add_dependencies<I: IntoIterator<Item = (P, VS)>>(
&mut self,
package: P,
version: impl Into<VS::V>,
dependencies: I,
) {
let package_deps = dependencies.into_iter().collect();
let v = version.into();
*self
.dependencies
.entry(package)
.or_default()
.entry(v)
.or_default() = package_deps;
}

/// Lists packages that have been saved.
pub fn packages(&self) -> impl Iterator<Item = &P> {
self.dependencies.keys()
}

/// Lists versions of saved packages in sorted order.
/// Returns [None] if no information is available regarding that package.
pub fn versions(&self, package: &P) -> Option<impl Iterator<Item = &VS::V>> {
self.dependencies.get(package).map(|k| k.keys())
}

/// 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()
}
}

/// An implementation of [DependencyProvider] that
/// contains all dependency information available in memory.
/// Currently packages are picked with the fewest versions contained in the constraints first.
/// But, that may change in new versions if better heuristics are found.
/// Versions are picked with the newest versions first.
impl<P: Package, VS: VersionSet> DependencyProvider for OfflineDependencyProvider<P, VS> {
type P = P;
type V = VS::V;
type VS = VS;
type M = String;

type Err = Infallible;

fn choose_version(&self, package: &P, range: &VS) -> Result<Option<VS::V>, Infallible> {
Ok(self
.dependencies
.get(package)
.and_then(|versions| versions.keys().rev().find(|v| range.contains(v)).cloned()))
}

type Priority = Reverse<usize>;
fn prioritize(&self, package: &P, range: &VS) -> Self::Priority {
Reverse(
self.dependencies
.get(package)
.map(|versions| versions.keys().filter(|v| range.contains(v)).count())
.unwrap_or(0),
)
}

fn get_dependencies(
&self,
package: &P,
version: &VS::V,
) -> Result<Dependencies<P, VS, Self::M>, Infallible> {
Ok(match self.dependencies(package, version) {
None => {
Dependencies::Unavailable("its dependencies could not be determined".to_string())
}
Some(dependencies) => Dependencies::Available(dependencies),
})
}
}

0 comments on commit 4bde6d6

Please sign in to comment.