uv_distribution_types/
any.rs

1use std::hash::Hash;
2
3use uv_cache_key::CanonicalUrl;
4use uv_normalize::PackageName;
5use uv_pep440::Version;
6
7use crate::cached::CachedDist;
8use crate::installed::InstalledDist;
9use crate::{InstalledMetadata, InstalledVersion, Name};
10
11/// A distribution which is either installable, is a wheel in our cache or is already installed.
12///
13/// Note equality and hash operations are only based on the name and canonical version, not the
14/// kind.
15#[derive(Debug, Clone, Eq)]
16#[allow(clippy::large_enum_variant)]
17pub enum LocalDist {
18    Cached(CachedDist, CanonicalVersion),
19    Installed(InstalledDist, CanonicalVersion),
20}
21
22impl LocalDist {
23    fn canonical_version(&self) -> &CanonicalVersion {
24        match self {
25            Self::Cached(_, version) => version,
26            Self::Installed(_, version) => version,
27        }
28    }
29}
30
31impl Name for LocalDist {
32    fn name(&self) -> &PackageName {
33        match self {
34            Self::Cached(dist, _) => dist.name(),
35            Self::Installed(dist, _) => dist.name(),
36        }
37    }
38}
39
40impl InstalledMetadata for LocalDist {
41    fn installed_version(&self) -> InstalledVersion<'_> {
42        match self {
43            Self::Cached(dist, _) => dist.installed_version(),
44            Self::Installed(dist, _) => dist.installed_version(),
45        }
46    }
47}
48
49impl From<CachedDist> for LocalDist {
50    fn from(dist: CachedDist) -> Self {
51        let version = CanonicalVersion::from(dist.installed_version());
52        Self::Cached(dist, version)
53    }
54}
55
56impl From<InstalledDist> for LocalDist {
57    fn from(dist: InstalledDist) -> Self {
58        let version = CanonicalVersion::from(dist.installed_version());
59        Self::Installed(dist, version)
60    }
61}
62
63impl Hash for LocalDist {
64    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
65        self.name().hash(state);
66        self.canonical_version().hash(state);
67    }
68}
69
70impl PartialEq for LocalDist {
71    fn eq(&self, other: &Self) -> bool {
72        self.name() == other.name() && self.canonical_version() == other.canonical_version()
73    }
74}
75
76/// Like [`InstalledVersion`], but with [`CanonicalUrl`] to ensure robust URL comparisons.
77#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
78pub enum CanonicalVersion {
79    Version(Version),
80    Url(CanonicalUrl, Version),
81}
82
83impl From<InstalledVersion<'_>> for CanonicalVersion {
84    fn from(installed_version: InstalledVersion<'_>) -> Self {
85        match installed_version {
86            InstalledVersion::Version(version) => Self::Version(version.clone()),
87            InstalledVersion::Url(url, version) => {
88                Self::Url(CanonicalUrl::new(url), version.clone())
89            }
90        }
91    }
92}