Skip to main content

uv_distribution_types/
traits.rs

1use std::borrow::Cow;
2
3use uv_normalize::PackageName;
4use uv_pep508::VerbatimUrl;
5use uv_redacted::policy::SerializationPolicy;
6
7use crate::error::Error;
8use crate::{
9    BuiltDist, CachedDirectUrlDist, CachedDist, CachedRegistryDist, DirectUrlBuiltDist,
10    DirectUrlSourceDist, DirectorySourceDist, Dist, DistributionId, GitDirectorySourceDist,
11    GitPathBuiltDist, GitPathSourceDist, InstalledDirectUrlDist, InstalledDist,
12    InstalledEggInfoDirectory, InstalledEggInfoFile, InstalledLegacyEditable,
13    InstalledRegistryDist, InstalledVersion, LocalDist, PackageId, PathBuiltDist, PathSourceDist,
14    RegistryBuiltWheel, RegistrySourceDist, ResourceId, SourceDist, VersionId, VersionOrUrlRef,
15};
16
17pub trait Name {
18    /// Return the normalized [`PackageName`] of the distribution.
19    fn name(&self) -> &PackageName;
20}
21
22/// Metadata that can be resolved from a requirements specification alone (i.e., prior to building
23/// or installing the distribution).
24pub trait DistributionMetadata: Name {
25    /// Return a [`uv_pep440::Version`], for registry-based distributions, or a [`url::Url`],
26    /// for URL-based distributions.
27    fn version_or_url(&self) -> VersionOrUrlRef<'_>;
28
29    /// Returns a unique identifier for the package at the given version (e.g., `black==23.10.0`).
30    ///
31    /// Note that this is not equivalent to a unique identifier for the _distribution_, as multiple
32    /// registry-based distributions (e.g., different wheels for the same package and version)
33    /// will return the same version ID, but different distribution IDs.
34    fn version_id(&self) -> VersionId {
35        match self.version_or_url() {
36            VersionOrUrlRef::Version(version) => {
37                VersionId::from_registry(self.name().clone(), version.clone())
38            }
39            VersionOrUrlRef::Url(url) => VersionId::from_url(url),
40        }
41    }
42
43    /// Returns a unique identifier for a package. A package can either be identified by a name
44    /// (e.g., `black`) or a URL (e.g., `git+https://github.com/psf/black`).
45    ///
46    /// Note that this is not equivalent to a unique identifier for the _distribution_, as multiple
47    /// registry-based distributions (e.g., different wheels for the same package and version)
48    /// will return the same version ID, but different distribution IDs.
49    fn package_id(&self) -> PackageId {
50        match self.version_or_url() {
51            VersionOrUrlRef::Version(_) => PackageId::from_registry(self.name().clone()),
52            VersionOrUrlRef::Url(url) => PackageId::from_url(url.raw().clone()),
53        }
54    }
55}
56
57/// Metadata that can be resolved from a built distribution.
58pub trait InstalledMetadata: Name {
59    /// Return the resolved version of the installed distribution.
60    fn installed_version(&self) -> InstalledVersion<'_>;
61}
62
63pub trait RemoteSource {
64    /// Return an appropriate filename for the distribution.
65    fn filename(&self) -> Result<Cow<'_, str>, Error>;
66
67    /// Return the size of the distribution, if known.
68    fn size(&self) -> Option<u64>;
69}
70
71pub trait Identifier {
72    /// Return a unique resource identifier for the distribution, like a SHA-256 hash of the
73    /// distribution's contents.
74    ///
75    /// A distribution is a specific archive of a package at a specific version. For a given package
76    /// version, there may be multiple distributions, e.g., source distribution, along with
77    /// multiple binary distributions (wheels) for different platforms. As a concrete example,
78    /// `black-23.10.0-py3-none-any.whl` would represent a (binary) distribution of the `black` package
79    /// at version `23.10.0`.
80    ///
81    /// The distribution ID is used to uniquely identify a distribution. Ideally, the distribution
82    /// ID should be a hash of the distribution's contents, though in practice, it's only required
83    /// that the ID is unique within a single invocation of the resolver (and so, e.g., a hash of
84    /// the URL would also be sufficient).
85    fn distribution_id(&self) -> DistributionId;
86
87    /// Return a unique resource identifier for the underlying resource backing the distribution.
88    ///
89    /// This is often equivalent to the distribution ID, but may differ in some cases. For example,
90    /// if the same Git repository is used for two different distributions, at two different
91    /// subdirectories or two different commits, then those distributions would share a resource ID,
92    /// but have different distribution IDs.
93    fn resource_id(&self) -> ResourceId;
94}
95
96pub trait Verbatim {
97    /// Return the verbatim representation of the distribution.
98    fn verbatim(&self) -> Cow<'_, str>;
99}
100
101impl<P: SerializationPolicy> Verbatim for VerbatimUrl<P> {
102    fn verbatim(&self) -> Cow<'_, str> {
103        if let Some(given) = self.given() {
104            Cow::Borrowed(given)
105        } else {
106            Cow::Owned(self.to_string())
107        }
108    }
109}
110
111impl<T: DistributionMetadata> Verbatim for T {
112    fn verbatim(&self) -> Cow<'_, str> {
113        Cow::Owned(format!(
114            "{}{}",
115            self.name(),
116            self.version_or_url().verbatim()
117        ))
118    }
119}
120
121// Implement `Display` for all known types that implement `Metadata`.
122impl std::fmt::Display for LocalDist {
123    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124        write!(f, "{}{}", self.name(), self.installed_version())
125    }
126}
127
128impl std::fmt::Display for BuiltDist {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        write!(f, "{}{}", self.name(), self.version_or_url())
131    }
132}
133
134impl std::fmt::Display for CachedDist {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        write!(f, "{}{}", self.name(), self.installed_version())
137    }
138}
139
140impl std::fmt::Display for CachedDirectUrlDist {
141    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142        write!(f, "{}{}", self.name(), self.installed_version())
143    }
144}
145
146impl std::fmt::Display for CachedRegistryDist {
147    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148        write!(f, "{}{}", self.name(), self.installed_version())
149    }
150}
151
152impl std::fmt::Display for DirectUrlBuiltDist {
153    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154        write!(f, "{}{}", self.name(), self.version_or_url())
155    }
156}
157
158impl std::fmt::Display for DirectUrlSourceDist {
159    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160        write!(f, "{}{}", self.name(), self.version_or_url())
161    }
162}
163
164impl std::fmt::Display for Dist {
165    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166        write!(f, "{}{}", self.name(), self.version_or_url())
167    }
168}
169
170impl std::fmt::Display for GitPathBuiltDist {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        write!(f, "{}{}", self.name(), self.version_or_url())
173    }
174}
175
176impl std::fmt::Display for GitPathSourceDist {
177    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178        write!(f, "{}{}", self.name(), self.version_or_url())
179    }
180}
181
182impl std::fmt::Display for GitDirectorySourceDist {
183    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184        write!(f, "{}{}", self.name(), self.version_or_url())
185    }
186}
187
188impl std::fmt::Display for InstalledDist {
189    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190        write!(f, "{}{}", self.name(), self.installed_version())
191    }
192}
193
194impl std::fmt::Display for InstalledDirectUrlDist {
195    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
196        write!(f, "{}{}", self.name(), self.installed_version())
197    }
198}
199
200impl std::fmt::Display for InstalledRegistryDist {
201    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202        write!(f, "{}{}", self.name(), self.installed_version())
203    }
204}
205
206impl std::fmt::Display for InstalledEggInfoFile {
207    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208        write!(f, "{}{}", self.name(), self.installed_version())
209    }
210}
211
212impl std::fmt::Display for InstalledEggInfoDirectory {
213    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214        write!(f, "{}{}", self.name(), self.installed_version())
215    }
216}
217
218impl std::fmt::Display for InstalledLegacyEditable {
219    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220        write!(f, "{}{}", self.name(), self.installed_version())
221    }
222}
223
224impl std::fmt::Display for PathBuiltDist {
225    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226        write!(f, "{}{}", self.name(), self.version_or_url())
227    }
228}
229
230impl std::fmt::Display for PathSourceDist {
231    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232        write!(f, "{}{}", self.name(), self.version_or_url())
233    }
234}
235
236impl std::fmt::Display for DirectorySourceDist {
237    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238        write!(f, "{}{}", self.name(), self.version_or_url())
239    }
240}
241
242impl std::fmt::Display for RegistryBuiltWheel {
243    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244        write!(f, "{}{}", self.name(), self.version_or_url())
245    }
246}
247
248impl std::fmt::Display for RegistrySourceDist {
249    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250        write!(f, "{}{}", self.name(), self.version_or_url())
251    }
252}
253
254impl std::fmt::Display for SourceDist {
255    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256        write!(f, "{}{}", self.name(), self.version_or_url())
257    }
258}