From c9fd99a8a20f4f6a5cd16bb3ef5d33903999f834 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 7 Jul 2026 11:32:08 -0400 Subject: [PATCH] Avoid allocating expanded compatibility tags --- .../src/expanded_tags.rs | 10 ++--- .../uv-distribution-filename/src/wheel_tag.rs | 6 +-- crates/uv-platform-tags/src/tags.rs | 40 ++++++++++--------- crates/uv-resolver/src/lock/mod.rs | 6 +-- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/crates/uv-distribution-filename/src/expanded_tags.rs b/crates/uv-distribution-filename/src/expanded_tags.rs index ab4e2d309e6..e5417d22b36 100644 --- a/crates/uv-distribution-filename/src/expanded_tags.rs +++ b/crates/uv-distribution-filename/src/expanded_tags.rs @@ -46,12 +46,12 @@ impl ExpandedTags { } /// Return the ABI tags in this expanded tag set. - pub fn abi_tags(&self) -> impl Iterator { + pub fn abi_tags(&self) -> impl Iterator + Clone { self.0.iter().flat_map(WheelTag::abi_tags) } /// Return the platform tags in this expanded tag set. - pub fn platform_tags(&self) -> impl Iterator { + pub fn platform_tags(&self) -> impl Iterator + Clone { self.0.iter().flat_map(WheelTag::platform_tags) } @@ -61,11 +61,7 @@ impl ExpandedTags { return tag.compatibility(compatible_tags); } - compatible_tags.compatibility( - self.python_tags().copied().collect::>().as_slice(), - self.abi_tags().copied().collect::>().as_slice(), - self.platform_tags().cloned().collect::>().as_slice(), - ) + compatible_tags.compatibility(self.python_tags(), self.abi_tags(), self.platform_tags()) } } diff --git a/crates/uv-distribution-filename/src/wheel_tag.rs b/crates/uv-distribution-filename/src/wheel_tag.rs index f88fc0a46ce..f1f86a51492 100644 --- a/crates/uv-distribution-filename/src/wheel_tag.rs +++ b/crates/uv-distribution-filename/src/wheel_tag.rs @@ -47,9 +47,9 @@ impl WheelTag { &small.platform_tag, ), Self::Large { large } => compatible_tags.compatibility( - large.python_tag.as_slice(), - large.abi_tag.as_slice(), - large.platform_tag.as_slice(), + large.python_tag.iter(), + large.abi_tag.iter(), + large.platform_tag.iter(), ), } } diff --git a/crates/uv-platform-tags/src/tags.rs b/crates/uv-platform-tags/src/tags.rs index 86555bf411e..ddbf7d86bc7 100644 --- a/crates/uv-platform-tags/src/tags.rs +++ b/crates/uv-platform-tags/src/tags.rs @@ -358,22 +358,26 @@ impl Tags { false } - /// Returns the [`TagCompatibility`] of the given tags. + /// Returns the [`TagCompatibility`] of the given tag iterators. /// /// If compatible, includes the score of the most-compatible platform tag. /// If incompatible, includes the tag part which was a closest match. - pub fn compatibility( + /// + /// The ABI and platform iterators are cloned to restart the Cartesian product. + pub fn compatibility<'a>( &self, - wheel_python_tags: &[LanguageTag], - wheel_abi_tags: &[AbiTag], - wheel_platform_tags: &[PlatformTag], + wheel_python_tags: impl Iterator, + wheel_abi_tags: impl Iterator + Clone, + wheel_platform_tags: impl Iterator + Clone, ) -> TagCompatibility { + let wheel_abi_tags = move || wheel_abi_tags.clone(); + let wheel_platform_tags = move || wheel_platform_tags.clone(); + // On free-threaded Python, check if any wheel ABI tag is compatible. // Only `none` (pure Python), `abi3t`, and free-threaded CPython ABIs // (e.g., `cp313t`) are compatible. if self.is_freethreaded { - let has_compatible_abi = wheel_abi_tags - .iter() + let has_compatible_abi = wheel_abi_tags() .copied() .any(is_freethreaded_compatible_abi); if !has_compatible_abi { @@ -389,13 +393,13 @@ impl Tags { max_compatibility.max(TagCompatibility::Incompatible(IncompatibleTag::Python)); continue; }; - for wheel_abi in wheel_abi_tags { + for wheel_abi in wheel_abi_tags() { let Some(platforms) = abis.get(wheel_abi) else { max_compatibility = max_compatibility.max(TagCompatibility::Incompatible(IncompatibleTag::Abi)); continue; }; - for wheel_platform in wheel_platform_tags { + for wheel_platform in wheel_platform_tags() { let priority = platforms.get(wheel_platform).copied(); if let Some(priority) = priority { max_compatibility = @@ -3005,14 +3009,14 @@ mod tests { .unwrap(); let debug_compatibility = tags.compatibility( - &[LanguageTag::from_str("cp314").unwrap()], - &[AbiTag::from_str("cp314d").unwrap()], - &[PlatformTag::from_str("manylinux_2_28_x86_64").unwrap()], + [LanguageTag::from_str("cp314").unwrap()].iter(), + [AbiTag::from_str("cp314d").unwrap()].iter(), + [PlatformTag::from_str("manylinux_2_28_x86_64").unwrap()].iter(), ); let non_debug_compatibility = tags.compatibility( - &[LanguageTag::from_str("cp314").unwrap()], - &[AbiTag::from_str("cp314").unwrap()], - &[PlatformTag::from_str("manylinux_2_28_x86_64").unwrap()], + [LanguageTag::from_str("cp314").unwrap()].iter(), + [AbiTag::from_str("cp314").unwrap()].iter(), + [PlatformTag::from_str("manylinux_2_28_x86_64").unwrap()].iter(), ); (debug_compatibility, non_debug_compatibility) } @@ -3058,9 +3062,9 @@ mod tests { assert_eq!( tags.compatibility_tag(&python_tag, &abi_tag, &platform_tag), tags.compatibility( - std::slice::from_ref(&python_tag), - std::slice::from_ref(&abi_tag), - std::slice::from_ref(&platform_tag), + std::iter::once(&python_tag), + std::iter::once(&abi_tag), + std::iter::once(&platform_tag), ) ); } diff --git a/crates/uv-resolver/src/lock/mod.rs b/crates/uv-resolver/src/lock/mod.rs index 672b2829cf6..16916848ee1 100644 --- a/crates/uv-resolver/src/lock/mod.rs +++ b/crates/uv-resolver/src/lock/mod.rs @@ -6312,9 +6312,9 @@ impl WheelTagHint { .iter() .map(|filename| { tags.compatibility( - filename.python_tags(), - filename.abi_tags(), - filename.platform_tags(), + filename.python_tags().iter(), + filename.abi_tags().iter(), + filename.platform_tags().iter(), ) }) .max()?;