1use std::cmp::Reverse;
2use std::collections::BTreeMap;
3use std::convert::Infallible;
4
5use crate::{
6 Dependencies, DependencyConstraints, DependencyProvider, Map, Package,
7 PackageResolutionStatistics, VersionSet,
8};
9
10#[derive(Debug, Clone, Default)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13#[cfg_attr(
14 feature = "serde",
15 serde(bound(
16 serialize = "VS::V: serde::Serialize, VS: serde::Serialize, P: serde::Serialize",
17 deserialize = "VS::V: serde::Deserialize<'de>, VS: serde::Deserialize<'de>, P: serde::Deserialize<'de>"
18 ))
19)]
20#[cfg_attr(feature = "serde", serde(transparent))]
21pub struct OfflineDependencyProvider<P: Package, VS: VersionSet> {
22 dependencies: Map<P, BTreeMap<VS::V, DependencyConstraints<P, VS>>>,
23}
24
25impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> {
26 pub fn new() -> Self {
28 Self {
29 dependencies: Map::default(),
30 }
31 }
32
33 pub fn add_dependencies<I: IntoIterator<Item = (P, VS)>>(
44 &mut self,
45 package: P,
46 version: impl Into<VS::V>,
47 dependencies: I,
48 ) {
49 let package_deps = dependencies.into_iter().collect();
50 let v = version.into();
51 *self
52 .dependencies
53 .entry(package)
54 .or_default()
55 .entry(v)
56 .or_default() = package_deps;
57 }
58
59 pub fn packages(&self) -> impl Iterator<Item = &P> {
61 self.dependencies.keys()
62 }
63
64 pub fn versions(&self, package: &P) -> Option<impl Iterator<Item = &VS::V>> {
67 self.dependencies.get(package).map(|k| k.keys())
68 }
69
70 fn dependencies(&self, package: &P, version: &VS::V) -> Option<DependencyConstraints<P, VS>> {
73 self.dependencies.get(package)?.get(version).cloned()
74 }
75}
76
77impl<P: Package, VS: VersionSet> DependencyProvider for OfflineDependencyProvider<P, VS> {
83 type P = P;
84 type V = VS::V;
85 type VS = VS;
86 type M = String;
87
88 type Err = Infallible;
89
90 #[inline]
91 fn choose_version(&self, package: &P, range: &VS) -> Result<Option<VS::V>, Infallible> {
92 Ok(self
93 .dependencies
94 .get(package)
95 .and_then(|versions| versions.keys().rev().find(|v| range.contains(v)).cloned()))
96 }
97
98 type Priority = (u32, Reverse<usize>);
99
100 #[inline]
101 fn prioritize(
102 &self,
103 package: &Self::P,
104 range: &Self::VS,
105 package_statistics: &PackageResolutionStatistics,
106 ) -> Self::Priority {
107 let version_count = self
108 .dependencies
109 .get(package)
110 .map(|versions| versions.keys().filter(|v| range.contains(v)).count())
111 .unwrap_or(0);
112 if version_count == 0 {
113 return (u32::MAX, Reverse(0));
114 }
115 (package_statistics.conflict_count(), Reverse(version_count))
116 }
117
118 #[inline]
119 fn get_dependencies(
120 &self,
121 package: &P,
122 version: &VS::V,
123 ) -> Result<Dependencies<P, VS, Self::M>, Infallible> {
124 Ok(match self.dependencies(package, version) {
125 None => {
126 Dependencies::Unavailable("its dependencies could not be determined".to_string())
127 }
128 Some(dependencies) => Dependencies::Available(dependencies),
129 })
130 }
131}