diff --git a/crates/uv-python/src/installation.rs b/crates/uv-python/src/installation.rs index 9d558f3ff..611dc2007 100644 --- a/crates/uv-python/src/installation.rs +++ b/crates/uv-python/src/installation.rs @@ -483,8 +483,10 @@ impl Ord for PythonInstallationKey { .cmp(&other.implementation) .then_with(|| self.version().cmp(&other.version())) .then_with(|| self.os.to_string().cmp(&other.os.to_string())) - .then_with(|| self.arch.to_string().cmp(&other.arch.to_string())) + // Architectures are sorted in preferred order, with native architectures first + .then_with(|| self.arch.cmp(&other.arch).reverse()) .then_with(|| self.libc.to_string().cmp(&other.libc.to_string())) - .then_with(|| self.variant.cmp(&other.variant).reverse()) // we want Default to come first + // Python variants are sorted in preferred order, with `Default` first + .then_with(|| self.variant.cmp(&other.variant).reverse()) } } diff --git a/crates/uv-python/src/platform.rs b/crates/uv-python/src/platform.rs index 0e64a0fea..fc342550a 100644 --- a/crates/uv-python/src/platform.rs +++ b/crates/uv-python/src/platform.rs @@ -18,7 +18,7 @@ pub enum Error { } /// Architecture variants, e.g., with support for different instruction sets -#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)] +#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, Ord, PartialOrd)] pub enum ArchVariant { /// Targets 64-bit Intel/AMD CPUs newer than Nehalem (2008). /// Includes SSE3, SSE4 and other post-2003 CPU instructions. @@ -37,6 +37,33 @@ pub struct Arch { pub(crate) variant: Option, } +impl Ord for Arch { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + if self.family == other.family { + return self.variant.cmp(&other.variant); + } + + let native = Arch::from_env(); + + // Prefer native architectures + match (self.family == native.family, other.family == native.family) { + (true, true) => unreachable!(), + (true, false) => std::cmp::Ordering::Less, + (false, true) => std::cmp::Ordering::Greater, + (false, false) => { + // Both non-native, fallback to lexicographic order + self.family.to_string().cmp(&other.family.to_string()) + } + } + } +} + +impl PartialOrd for Arch { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + #[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)] pub struct Os(pub(crate) target_lexicon::OperatingSystem);