uv_distribution_types/
traits.rs

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