Skip to main content

uv_distribution_types/
resolved.rs

1use std::fmt::{Display, Formatter};
2use std::path::Path;
3use std::sync::Arc;
4
5use uv_normalize::PackageName;
6use uv_pep440::Version;
7use uv_pypi_types::Yanked;
8
9use crate::{
10    BuiltDist, Dist, DistributionId, DistributionMetadata, Identifier, IndexUrl, InstalledDist,
11    Name, PrioritizedDist, RegistryBuiltWheel, RegistrySourceDist, ResourceId, SourceDist,
12    VersionOrUrlRef,
13};
14
15/// A distribution that can be used for resolution and installation.
16///
17/// Either an already-installed distribution or a distribution that can be installed.
18#[derive(Debug, Clone, Hash)]
19pub enum ResolvedDist {
20    Installed {
21        dist: Arc<InstalledDist>,
22    },
23    Installable {
24        dist: Arc<Dist>,
25        version: Option<Version>,
26    },
27}
28
29/// A variant of [`ResolvedDist`] with borrowed inner distributions.
30#[derive(Debug, Clone)]
31pub enum ResolvedDistRef<'a> {
32    Installed {
33        dist: &'a InstalledDist,
34    },
35    InstallableRegistrySourceDist {
36        /// The source distribution that should be used.
37        sdist: &'a RegistrySourceDist,
38        /// The prioritized distribution that the wheel came from.
39        prioritized: &'a PrioritizedDist,
40    },
41    InstallableRegistryBuiltDist {
42        /// The wheel that should be used.
43        wheel: &'a RegistryBuiltWheel,
44        /// The prioritized distribution that the wheel came from.
45        prioritized: &'a PrioritizedDist,
46    },
47}
48
49impl ResolvedDist {
50    /// Return true if the distribution is editable.
51    pub fn is_editable(&self) -> bool {
52        match self {
53            Self::Installable { dist, .. } => dist.is_editable(),
54            Self::Installed { dist } => dist.is_editable(),
55        }
56    }
57
58    /// Return true if the distribution refers to a local file or directory.
59    pub fn is_local(&self) -> bool {
60        match self {
61            Self::Installable { dist, .. } => dist.is_local(),
62            Self::Installed { dist } => dist.is_local(),
63        }
64    }
65
66    /// Returns the [`IndexUrl`], if the distribution is from a registry.
67    pub fn index(&self) -> Option<&IndexUrl> {
68        match self {
69            Self::Installable { dist, .. } => dist.index(),
70            Self::Installed { .. } => None,
71        }
72    }
73
74    /// Returns the [`Yanked`] status of the distribution, if available.
75    pub fn yanked(&self) -> Option<&Yanked> {
76        match self {
77            Self::Installable { dist, .. } => match dist.as_ref() {
78                Dist::Source(SourceDist::Registry(sdist)) => sdist.file.yanked.as_deref(),
79                Dist::Built(BuiltDist::Registry(wheel)) => {
80                    wheel.best_wheel().file.yanked.as_deref()
81                }
82                _ => None,
83            },
84            Self::Installed { .. } => None,
85        }
86    }
87
88    /// Returns the version of the distribution, if available.
89    pub fn version(&self) -> Option<&Version> {
90        match self {
91            Self::Installable { version, dist } => dist.version().or(version.as_ref()),
92            Self::Installed { dist } => Some(dist.version()),
93        }
94    }
95
96    /// Return the source tree of the distribution, if available.
97    pub fn source_tree(&self) -> Option<&Path> {
98        match self {
99            Self::Installable { dist, .. } => dist.source_tree(),
100            Self::Installed { .. } => None,
101        }
102    }
103}
104
105impl ResolvedDistRef<'_> {
106    pub fn to_owned(&self) -> ResolvedDist {
107        match self {
108            Self::InstallableRegistrySourceDist { sdist, prioritized } => {
109                // This is okay because we're only here if the prioritized dist
110                // has an sdist, so this always succeeds.
111                let source = prioritized.source_dist().expect("a source distribution");
112                assert_eq!(
113                    (&sdist.name, &sdist.version),
114                    (&source.name, &source.version),
115                    "expected chosen sdist to match prioritized sdist"
116                );
117                ResolvedDist::Installable {
118                    dist: Arc::new(Dist::Source(SourceDist::Registry(source))),
119                    version: Some(sdist.version.clone()),
120                }
121            }
122            Self::InstallableRegistryBuiltDist {
123                wheel, prioritized, ..
124            } => {
125                assert_eq!(
126                    Some(&wheel.filename),
127                    prioritized.best_wheel().map(|(wheel, _)| &wheel.filename),
128                    "expected chosen wheel to match best wheel"
129                );
130                // This is okay because we're only here if the prioritized dist
131                // has at least one wheel, so this always succeeds.
132                let built = prioritized.built_dist().expect("at least one wheel");
133                ResolvedDist::Installable {
134                    dist: Arc::new(Dist::Built(BuiltDist::Registry(built))),
135                    version: Some(wheel.filename.version.clone()),
136                }
137            }
138            Self::Installed { dist } => ResolvedDist::Installed {
139                dist: Arc::new((*dist).clone()),
140            },
141        }
142    }
143
144    /// Returns the [`IndexUrl`], if the distribution is from a registry.
145    pub fn index(&self) -> Option<&IndexUrl> {
146        match self {
147            Self::InstallableRegistrySourceDist { sdist, .. } => Some(&sdist.index),
148            Self::InstallableRegistryBuiltDist { wheel, .. } => Some(&wheel.index),
149            Self::Installed { .. } => None,
150        }
151    }
152}
153
154impl Display for ResolvedDistRef<'_> {
155    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
156        match self {
157            Self::InstallableRegistrySourceDist { sdist, .. } => Display::fmt(sdist, f),
158            Self::InstallableRegistryBuiltDist { wheel, .. } => Display::fmt(wheel, f),
159            Self::Installed { dist } => Display::fmt(dist, f),
160        }
161    }
162}
163
164impl Name for ResolvedDistRef<'_> {
165    fn name(&self) -> &PackageName {
166        match self {
167            Self::InstallableRegistrySourceDist { sdist, .. } => sdist.name(),
168            Self::InstallableRegistryBuiltDist { wheel, .. } => wheel.name(),
169            Self::Installed { dist } => dist.name(),
170        }
171    }
172}
173
174impl DistributionMetadata for ResolvedDistRef<'_> {
175    fn version_or_url(&self) -> VersionOrUrlRef<'_> {
176        match self {
177            Self::Installed { dist } => VersionOrUrlRef::Version(dist.version()),
178            Self::InstallableRegistrySourceDist { sdist, .. } => sdist.version_or_url(),
179            Self::InstallableRegistryBuiltDist { wheel, .. } => wheel.version_or_url(),
180        }
181    }
182}
183
184impl Identifier for ResolvedDistRef<'_> {
185    fn distribution_id(&self) -> DistributionId {
186        match self {
187            Self::Installed { dist } => dist.distribution_id(),
188            Self::InstallableRegistrySourceDist { sdist, .. } => sdist.distribution_id(),
189            Self::InstallableRegistryBuiltDist { wheel, .. } => wheel.distribution_id(),
190        }
191    }
192
193    fn resource_id(&self) -> ResourceId {
194        match self {
195            Self::Installed { dist } => dist.resource_id(),
196            Self::InstallableRegistrySourceDist { sdist, .. } => sdist.resource_id(),
197            Self::InstallableRegistryBuiltDist { wheel, .. } => wheel.resource_id(),
198        }
199    }
200}
201
202impl Name for ResolvedDist {
203    fn name(&self) -> &PackageName {
204        match self {
205            Self::Installable { dist, .. } => dist.name(),
206            Self::Installed { dist } => dist.name(),
207        }
208    }
209}
210
211impl DistributionMetadata for ResolvedDist {
212    fn version_or_url(&self) -> VersionOrUrlRef<'_> {
213        match self {
214            Self::Installed { dist } => dist.version_or_url(),
215            Self::Installable { dist, .. } => dist.version_or_url(),
216        }
217    }
218}
219
220impl Identifier for ResolvedDist {
221    fn distribution_id(&self) -> DistributionId {
222        match self {
223            Self::Installed { dist } => dist.distribution_id(),
224            Self::Installable { dist, .. } => dist.distribution_id(),
225        }
226    }
227
228    fn resource_id(&self) -> ResourceId {
229        match self {
230            Self::Installed { dist } => dist.resource_id(),
231            Self::Installable { dist, .. } => dist.resource_id(),
232        }
233    }
234}
235
236impl Display for ResolvedDist {
237    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
238        match self {
239            Self::Installed { dist } => dist.fmt(f),
240            Self::Installable { dist, .. } => dist.fmt(f),
241        }
242    }
243}