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#[derive(Debug, Clone, Hash)]
19#[allow(clippy::large_enum_variant)]
20pub enum ResolvedDist {
21 Installed {
22 dist: Arc<InstalledDist>,
23 },
24 Installable {
25 dist: Arc<Dist>,
26 version: Option<Version>,
27 },
28}
29
30#[derive(Debug, Clone)]
32pub enum ResolvedDistRef<'a> {
33 Installed {
34 dist: &'a InstalledDist,
35 },
36 InstallableRegistrySourceDist {
37 sdist: &'a RegistrySourceDist,
39 prioritized: &'a PrioritizedDist,
41 },
42 InstallableRegistryBuiltDist {
43 wheel: &'a RegistryBuiltWheel,
45 prioritized: &'a PrioritizedDist,
47 },
48}
49
50impl ResolvedDist {
51 pub fn is_editable(&self) -> bool {
53 match self {
54 Self::Installable { dist, .. } => dist.is_editable(),
55 Self::Installed { dist } => dist.is_editable(),
56 }
57 }
58
59 pub fn is_local(&self) -> bool {
61 match self {
62 Self::Installable { dist, .. } => dist.is_local(),
63 Self::Installed { dist } => dist.is_local(),
64 }
65 }
66
67 pub fn index(&self) -> Option<&IndexUrl> {
69 match self {
70 Self::Installable { dist, .. } => dist.index(),
71 Self::Installed { .. } => None,
72 }
73 }
74
75 pub fn yanked(&self) -> Option<&Yanked> {
77 match self {
78 Self::Installable { dist, .. } => match dist.as_ref() {
79 Dist::Source(SourceDist::Registry(sdist)) => sdist.file.yanked.as_deref(),
80 Dist::Built(BuiltDist::Registry(wheel)) => {
81 wheel.best_wheel().file.yanked.as_deref()
82 }
83 _ => None,
84 },
85 Self::Installed { .. } => None,
86 }
87 }
88
89 pub fn version(&self) -> Option<&Version> {
91 match self {
92 Self::Installable { version, dist } => dist.version().or(version.as_ref()),
93 Self::Installed { dist } => Some(dist.version()),
94 }
95 }
96
97 pub fn source_tree(&self) -> Option<&Path> {
99 match self {
100 Self::Installable { dist, .. } => dist.source_tree(),
101 Self::Installed { .. } => None,
102 }
103 }
104}
105
106impl ResolvedDistRef<'_> {
107 pub fn to_owned(&self) -> ResolvedDist {
108 match self {
109 Self::InstallableRegistrySourceDist { sdist, prioritized } => {
110 let source = prioritized.source_dist().expect("a source distribution");
113 assert_eq!(
114 (&sdist.name, &sdist.version),
115 (&source.name, &source.version),
116 "expected chosen sdist to match prioritized sdist"
117 );
118 ResolvedDist::Installable {
119 dist: Arc::new(Dist::Source(SourceDist::Registry(source))),
120 version: Some(sdist.version.clone()),
121 }
122 }
123 Self::InstallableRegistryBuiltDist {
124 wheel, prioritized, ..
125 } => {
126 assert_eq!(
127 Some(&wheel.filename),
128 prioritized.best_wheel().map(|(wheel, _)| &wheel.filename),
129 "expected chosen wheel to match best wheel"
130 );
131 let built = prioritized.built_dist().expect("at least one wheel");
134 ResolvedDist::Installable {
135 dist: Arc::new(Dist::Built(BuiltDist::Registry(built))),
136 version: Some(wheel.filename.version.clone()),
137 }
138 }
139 Self::Installed { dist } => ResolvedDist::Installed {
140 dist: Arc::new((*dist).clone()),
141 },
142 }
143 }
144
145 pub fn index(&self) -> Option<&IndexUrl> {
147 match self {
148 Self::InstallableRegistrySourceDist { sdist, .. } => Some(&sdist.index),
149 Self::InstallableRegistryBuiltDist { wheel, .. } => Some(&wheel.index),
150 Self::Installed { .. } => None,
151 }
152 }
153}
154
155impl Display for ResolvedDistRef<'_> {
156 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
157 match self {
158 Self::InstallableRegistrySourceDist { sdist, .. } => Display::fmt(sdist, f),
159 Self::InstallableRegistryBuiltDist { wheel, .. } => Display::fmt(wheel, f),
160 Self::Installed { dist } => Display::fmt(dist, f),
161 }
162 }
163}
164
165impl Name for ResolvedDistRef<'_> {
166 fn name(&self) -> &PackageName {
167 match self {
168 Self::InstallableRegistrySourceDist { sdist, .. } => sdist.name(),
169 Self::InstallableRegistryBuiltDist { wheel, .. } => wheel.name(),
170 Self::Installed { dist } => dist.name(),
171 }
172 }
173}
174
175impl DistributionMetadata for ResolvedDistRef<'_> {
176 fn version_or_url(&self) -> VersionOrUrlRef<'_> {
177 match self {
178 Self::Installed { dist } => VersionOrUrlRef::Version(dist.version()),
179 Self::InstallableRegistrySourceDist { sdist, .. } => sdist.version_or_url(),
180 Self::InstallableRegistryBuiltDist { wheel, .. } => wheel.version_or_url(),
181 }
182 }
183}
184
185impl Identifier for ResolvedDistRef<'_> {
186 fn distribution_id(&self) -> DistributionId {
187 match self {
188 Self::Installed { dist } => dist.distribution_id(),
189 Self::InstallableRegistrySourceDist { sdist, .. } => sdist.distribution_id(),
190 Self::InstallableRegistryBuiltDist { wheel, .. } => wheel.distribution_id(),
191 }
192 }
193
194 fn resource_id(&self) -> ResourceId {
195 match self {
196 Self::Installed { dist } => dist.resource_id(),
197 Self::InstallableRegistrySourceDist { sdist, .. } => sdist.resource_id(),
198 Self::InstallableRegistryBuiltDist { wheel, .. } => wheel.resource_id(),
199 }
200 }
201}
202
203impl Name for ResolvedDist {
204 fn name(&self) -> &PackageName {
205 match self {
206 Self::Installable { dist, .. } => dist.name(),
207 Self::Installed { dist } => dist.name(),
208 }
209 }
210}
211
212impl DistributionMetadata for ResolvedDist {
213 fn version_or_url(&self) -> VersionOrUrlRef<'_> {
214 match self {
215 Self::Installed { dist } => dist.version_or_url(),
216 Self::Installable { dist, .. } => dist.version_or_url(),
217 }
218 }
219}
220
221impl Identifier for ResolvedDist {
222 fn distribution_id(&self) -> DistributionId {
223 match self {
224 Self::Installed { dist } => dist.distribution_id(),
225 Self::Installable { dist, .. } => dist.distribution_id(),
226 }
227 }
228
229 fn resource_id(&self) -> ResourceId {
230 match self {
231 Self::Installed { dist } => dist.resource_id(),
232 Self::Installable { dist, .. } => dist.resource_id(),
233 }
234 }
235}
236
237impl Display for ResolvedDist {
238 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
239 match self {
240 Self::Installed { dist } => dist.fmt(f),
241 Self::Installable { dist, .. } => dist.fmt(f),
242 }
243 }
244}