Use a boxed slice for various requirement types (#12514)

## Summary

Sorry I had five mins in between things.
This commit is contained in:
Charlie Marsh 2025-03-27 17:09:26 -04:00 committed by GitHub
parent daeae612aa
commit 50cf7d19b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 163 additions and 148 deletions

View File

@ -100,7 +100,7 @@ pub struct StaticMetadata {
pub version: Option<Version>, pub version: Option<Version>,
// Optional fields // Optional fields
#[serde(default)] #[serde(default)]
pub requires_dist: Vec<Requirement<VerbatimParsedUrl>>, pub requires_dist: Box<[Requirement<VerbatimParsedUrl>]>,
#[cfg_attr( #[cfg_attr(
feature = "schemars", feature = "schemars",
schemars( schemars(
@ -110,5 +110,5 @@ pub struct StaticMetadata {
)] )]
pub requires_python: Option<VersionSpecifiers>, pub requires_python: Option<VersionSpecifiers>,
#[serde(default)] #[serde(default)]
pub provides_extras: Vec<ExtraName>, pub provides_extras: Box<[ExtraName]>,
} }

View File

@ -46,10 +46,10 @@ pub struct Metadata {
pub name: PackageName, pub name: PackageName,
pub version: Version, pub version: Version,
// Optional fields // Optional fields
pub requires_dist: Vec<Requirement>, pub requires_dist: Box<[Requirement]>,
pub requires_python: Option<VersionSpecifiers>, pub requires_python: Option<VersionSpecifiers>,
pub provides_extras: Vec<ExtraName>, pub provides_extras: Box<[ExtraName]>,
pub dependency_groups: BTreeMap<GroupName, Vec<Requirement>>, pub dependency_groups: BTreeMap<GroupName, Box<[Requirement]>>,
pub dynamic: bool, pub dynamic: bool,
} }
@ -60,9 +60,7 @@ impl Metadata {
Self { Self {
name: metadata.name, name: metadata.name,
version: metadata.version, version: metadata.version,
requires_dist: metadata requires_dist: Box::into_iter(metadata.requires_dist)
.requires_dist
.into_iter()
.map(Requirement::from) .map(Requirement::from)
.collect(), .collect(),
requires_python: metadata.requires_python, requires_python: metadata.requires_python,

View File

@ -18,9 +18,9 @@ use crate::Metadata;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RequiresDist { pub struct RequiresDist {
pub name: PackageName, pub name: PackageName,
pub requires_dist: Vec<Requirement>, pub requires_dist: Box<[Requirement]>,
pub provides_extras: Vec<ExtraName>, pub provides_extras: Box<[ExtraName]>,
pub dependency_groups: BTreeMap<GroupName, Vec<Requirement>>, pub dependency_groups: BTreeMap<GroupName, Box<[Requirement]>>,
pub dynamic: bool, pub dynamic: bool,
} }
@ -30,9 +30,7 @@ impl RequiresDist {
pub fn from_metadata23(metadata: uv_pypi_types::RequiresDist) -> Self { pub fn from_metadata23(metadata: uv_pypi_types::RequiresDist) -> Self {
Self { Self {
name: metadata.name, name: metadata.name,
requires_dist: metadata requires_dist: Box::into_iter(metadata.requires_dist)
.requires_dist
.into_iter()
.map(Requirement::from) .map(Requirement::from)
.collect(), .collect(),
provides_extras: metadata.provides_extras, provides_extras: metadata.provides_extras,
@ -183,17 +181,17 @@ impl RequiresDist {
}, },
) )
}) })
.collect::<Result<Vec<_>, _>>(), .collect::<Result<Box<_>, _>>(),
SourceStrategy::Disabled => { SourceStrategy::Disabled => {
Ok(requirements.into_iter().map(Requirement::from).collect()) Ok(requirements.into_iter().map(Requirement::from).collect())
} }
}?; }?;
Ok::<(GroupName, Vec<Requirement>), MetadataError>((name, requirements)) Ok::<(GroupName, Box<_>), MetadataError>((name, requirements))
}) })
.collect::<Result<BTreeMap<_, _>, _>>()?; .collect::<Result<BTreeMap<_, _>, _>>()?;
// Lower the requirements. // Lower the requirements.
let requires_dist = metadata.requires_dist.into_iter(); let requires_dist = Box::into_iter(metadata.requires_dist);
let requires_dist = match source_strategy { let requires_dist = match source_strategy {
SourceStrategy::Enabled => requires_dist SourceStrategy::Enabled => requires_dist
.flat_map(|requirement| { .flat_map(|requirement| {
@ -220,7 +218,7 @@ impl RequiresDist {
)), )),
}) })
}) })
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<Box<_>, _>>()?,
SourceStrategy::Disabled => requires_dist.into_iter().map(Requirement::from).collect(), SourceStrategy::Disabled => requires_dist.into_iter().map(Requirement::from).collect(),
}; };
@ -351,11 +349,11 @@ impl From<Metadata> for RequiresDist {
/// The [`FlatRequiresDist`] struct is used to flatten out the recursive dependencies, i.e., convert /// The [`FlatRequiresDist`] struct is used to flatten out the recursive dependencies, i.e., convert
/// from the former to the latter. /// from the former to the latter.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct FlatRequiresDist(Vec<Requirement>); pub struct FlatRequiresDist(Box<[Requirement]>);
impl FlatRequiresDist { impl FlatRequiresDist {
/// Flatten a set of requirements, resolving any self-references. /// Flatten a set of requirements, resolving any self-references.
pub fn from_requirements(requirements: Vec<Requirement>, name: &PackageName) -> Self { pub fn from_requirements(requirements: Box<[Requirement]>, name: &PackageName) -> Self {
// If there are no self-references, we can return early. // If there are no self-references, we can return early.
if requirements.iter().all(|req| req.name != *name) { if requirements.iter().all(|req| req.name != *name) {
return Self(requirements); return Self(requirements);
@ -368,7 +366,7 @@ impl FlatRequiresDist {
.collect(); .collect();
// Transitively process all extras that are recursively included. // Transitively process all extras that are recursively included.
let mut flattened = requirements.clone(); let mut flattened = requirements.to_vec();
let mut seen = FxHashSet::<(ExtraName, MarkerTree)>::default(); let mut seen = FxHashSet::<(ExtraName, MarkerTree)>::default();
let mut queue: VecDeque<_> = flattened let mut queue: VecDeque<_> = flattened
.iter() .iter()
@ -434,21 +432,21 @@ impl FlatRequiresDist {
} }
} }
Self(flattened) Self(flattened.into_boxed_slice())
} }
/// Consume the [`FlatRequiresDist`] and return the inner vector. /// Consume the [`FlatRequiresDist`] and return the inner requirements.
pub fn into_inner(self) -> Vec<Requirement> { pub fn into_inner(self) -> Box<[Requirement]> {
self.0 self.0
} }
} }
impl IntoIterator for FlatRequiresDist { impl IntoIterator for FlatRequiresDist {
type Item = Requirement; type Item = Requirement;
type IntoIter = std::vec::IntoIter<Requirement>; type IntoIter = <Box<[Requirement]> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
self.0.into_iter() Box::into_iter(self.0)
} }
} }
@ -748,7 +746,7 @@ mod test {
#[test] #[test]
fn test_flat_requires_dist_noop() { fn test_flat_requires_dist_noop() {
let name = PackageName::from_str("pkg").unwrap(); let name = PackageName::from_str("pkg").unwrap();
let requirements = vec![ let requirements = [
Requirement::from_str("requests>=2.0.0").unwrap().into(), Requirement::from_str("requests>=2.0.0").unwrap().into(),
Requirement::from_str("pytest; extra == 'test'") Requirement::from_str("pytest; extra == 'test'")
.unwrap() .unwrap()
@ -758,7 +756,8 @@ mod test {
.into(), .into(),
]; ];
let expected = FlatRequiresDist(vec![ let expected = FlatRequiresDist(
[
Requirement::from_str("requests>=2.0.0").unwrap().into(), Requirement::from_str("requests>=2.0.0").unwrap().into(),
Requirement::from_str("pytest; extra == 'test'") Requirement::from_str("pytest; extra == 'test'")
.unwrap() .unwrap()
@ -766,9 +765,11 @@ mod test {
Requirement::from_str("black; extra == 'dev'") Requirement::from_str("black; extra == 'dev'")
.unwrap() .unwrap()
.into(), .into(),
]); ]
.into(),
);
let actual = FlatRequiresDist::from_requirements(requirements, &name); let actual = FlatRequiresDist::from_requirements(requirements.into(), &name);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
@ -776,7 +777,7 @@ mod test {
#[test] #[test]
fn test_flat_requires_dist_basic() { fn test_flat_requires_dist_basic() {
let name = PackageName::from_str("pkg").unwrap(); let name = PackageName::from_str("pkg").unwrap();
let requirements = vec![ let requirements = [
Requirement::from_str("requests>=2.0.0").unwrap().into(), Requirement::from_str("requests>=2.0.0").unwrap().into(),
Requirement::from_str("pytest; extra == 'test'") Requirement::from_str("pytest; extra == 'test'")
.unwrap() .unwrap()
@ -789,7 +790,8 @@ mod test {
.into(), .into(),
]; ];
let expected = FlatRequiresDist(vec![ let expected = FlatRequiresDist(
[
Requirement::from_str("requests>=2.0.0").unwrap().into(), Requirement::from_str("requests>=2.0.0").unwrap().into(),
Requirement::from_str("pytest; extra == 'test'") Requirement::from_str("pytest; extra == 'test'")
.unwrap() .unwrap()
@ -800,9 +802,11 @@ mod test {
Requirement::from_str("black; extra == 'test'") Requirement::from_str("black; extra == 'test'")
.unwrap() .unwrap()
.into(), .into(),
]); ]
.into(),
);
let actual = FlatRequiresDist::from_requirements(requirements, &name); let actual = FlatRequiresDist::from_requirements(requirements.into(), &name);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
@ -823,7 +827,8 @@ mod test {
.into(), .into(),
]; ];
let expected = FlatRequiresDist(vec![ let expected = FlatRequiresDist(
[
Requirement::from_str("requests>=2.0.0").unwrap().into(), Requirement::from_str("requests>=2.0.0").unwrap().into(),
Requirement::from_str("pytest; extra == 'test'") Requirement::from_str("pytest; extra == 'test'")
.unwrap() .unwrap()
@ -834,9 +839,11 @@ mod test {
Requirement::from_str("black; extra == 'test' and sys_platform == 'win32'") Requirement::from_str("black; extra == 'test' and sys_platform == 'win32'")
.unwrap() .unwrap()
.into(), .into(),
]); ]
.into(),
);
let actual = FlatRequiresDist::from_requirements(requirements, &name); let actual = FlatRequiresDist::from_requirements(requirements.into(), &name);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
@ -844,7 +851,7 @@ mod test {
#[test] #[test]
fn test_flat_requires_dist_self_constraint() { fn test_flat_requires_dist_self_constraint() {
let name = PackageName::from_str("pkg").unwrap(); let name = PackageName::from_str("pkg").unwrap();
let requirements = vec![ let requirements = [
Requirement::from_str("requests>=2.0.0").unwrap().into(), Requirement::from_str("requests>=2.0.0").unwrap().into(),
Requirement::from_str("pytest; extra == 'test'") Requirement::from_str("pytest; extra == 'test'")
.unwrap() .unwrap()
@ -855,7 +862,8 @@ mod test {
Requirement::from_str("pkg[async]==1.0.0").unwrap().into(), Requirement::from_str("pkg[async]==1.0.0").unwrap().into(),
]; ];
let expected = FlatRequiresDist(vec![ let expected = FlatRequiresDist(
[
Requirement::from_str("requests>=2.0.0").unwrap().into(), Requirement::from_str("requests>=2.0.0").unwrap().into(),
Requirement::from_str("pytest; extra == 'test'") Requirement::from_str("pytest; extra == 'test'")
.unwrap() .unwrap()
@ -864,9 +872,11 @@ mod test {
.unwrap() .unwrap()
.into(), .into(),
Requirement::from_str("pkg==1.0.0").unwrap().into(), Requirement::from_str("pkg==1.0.0").unwrap().into(),
]); ]
.into(),
);
let actual = FlatRequiresDist::from_requirements(requirements, &name); let actual = FlatRequiresDist::from_requirements(requirements.into(), &name);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }

View File

@ -26,9 +26,9 @@ pub struct ResolutionMetadata {
pub name: PackageName, pub name: PackageName,
pub version: Version, pub version: Version,
// Optional fields // Optional fields
pub requires_dist: Vec<Requirement<VerbatimParsedUrl>>, pub requires_dist: Box<[Requirement<VerbatimParsedUrl>]>,
pub requires_python: Option<VersionSpecifiers>, pub requires_python: Option<VersionSpecifiers>,
pub provides_extras: Vec<ExtraName>, pub provides_extras: Box<[ExtraName]>,
/// Whether the version field is dynamic. /// Whether the version field is dynamic.
#[serde(default)] #[serde(default)]
pub dynamic: bool, pub dynamic: bool,
@ -55,7 +55,7 @@ impl ResolutionMetadata {
.get_all_values("Requires-Dist") .get_all_values("Requires-Dist")
.map(|requires_dist| LenientRequirement::from_str(&requires_dist)) .map(|requires_dist| LenientRequirement::from_str(&requires_dist))
.map_ok(Requirement::from) .map_ok(Requirement::from)
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Box<_>, _>>()?;
let requires_python = headers let requires_python = headers
.get_first_value("Requires-Python") .get_first_value("Requires-Python")
.map(|requires_python| LenientVersionSpecifiers::from_str(&requires_python)) .map(|requires_python| LenientVersionSpecifiers::from_str(&requires_python))
@ -72,7 +72,7 @@ impl ResolutionMetadata {
} }
}, },
) )
.collect::<Vec<_>>(); .collect::<Box<_>>();
let dynamic = headers let dynamic = headers
.get_all_values("Dynamic") .get_all_values("Dynamic")
.any(|field| field == "Version"); .any(|field| field == "Version");
@ -135,7 +135,7 @@ impl ResolutionMetadata {
.get_all_values("Requires-Dist") .get_all_values("Requires-Dist")
.map(|requires_dist| LenientRequirement::from_str(&requires_dist)) .map(|requires_dist| LenientRequirement::from_str(&requires_dist))
.map_ok(Requirement::from) .map_ok(Requirement::from)
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Box<_>, _>>()?;
let requires_python = headers let requires_python = headers
.get_first_value("Requires-Python") .get_first_value("Requires-Python")
.map(|requires_python| LenientVersionSpecifiers::from_str(&requires_python)) .map(|requires_python| LenientVersionSpecifiers::from_str(&requires_python))
@ -152,7 +152,7 @@ impl ResolutionMetadata {
} }
}, },
) )
.collect::<Vec<_>>(); .collect::<Box<_>>();
Ok(Self { Ok(Self {
name, name,
@ -223,27 +223,35 @@ impl ResolutionMetadata {
.transpose()?; .transpose()?;
// Extract the requirements. // Extract the requirements.
let mut requires_dist = project let requires_dist = project
.dependencies .dependencies
.unwrap_or_default() .unwrap_or_default()
.into_iter() .into_iter()
.map(|requires_dist| LenientRequirement::from_str(&requires_dist)) .map(|requires_dist| LenientRequirement::from_str(&requires_dist))
.map_ok(Requirement::from) .map_ok(Requirement::from)
.collect::<Result<Vec<_>, _>>()?; .chain(
project
.optional_dependencies
.as_ref()
.iter()
.flat_map(|index| {
index.iter().flat_map(|(extras, requirements)| {
requirements
.iter()
.map(|requires_dist| LenientRequirement::from_str(requires_dist))
.map_ok(Requirement::from)
.map_ok(move |requirement| requirement.with_extra_marker(extras))
})
}),
)
.collect::<Result<Box<_>, _>>()?;
// Extract the optional dependencies. // Extract the optional dependencies.
let mut provides_extras: Vec<ExtraName> = Vec::new(); let provides_extras = project
for (extra, requirements) in project.optional_dependencies.unwrap_or_default() { .optional_dependencies
requires_dist.extend( .unwrap_or_default()
requirements .into_keys()
.into_iter() .collect::<Box<_>>();
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
.map_ok(Requirement::from)
.map_ok(|requirement| requirement.with_extra_marker(&extra))
.collect::<Result<Vec<_>, _>>()?,
);
provides_extras.push(extra);
}
Ok(Self { Ok(Self {
name, name,
@ -326,7 +334,7 @@ mod tests {
let meta = ResolutionMetadata::parse_pkg_info(s.as_bytes()).unwrap(); let meta = ResolutionMetadata::parse_pkg_info(s.as_bytes()).unwrap();
assert_eq!(meta.name, PackageName::from_str("asdf").unwrap()); assert_eq!(meta.name, PackageName::from_str("asdf").unwrap());
assert_eq!(meta.version, Version::new([1, 0])); assert_eq!(meta.version, Version::new([1, 0]));
assert_eq!(meta.requires_dist, vec!["foo".parse().unwrap()]); assert_eq!(*meta.requires_dist, ["foo".parse().unwrap()]);
} }
#[test] #[test]
@ -387,7 +395,7 @@ mod tests {
assert_eq!(meta.name, PackageName::from_str("asdf").unwrap()); assert_eq!(meta.name, PackageName::from_str("asdf").unwrap());
assert_eq!(meta.version, Version::new([1, 0])); assert_eq!(meta.version, Version::new([1, 0]));
assert_eq!(meta.requires_python, Some(">=3.6".parse().unwrap())); assert_eq!(meta.requires_python, Some(">=3.6".parse().unwrap()));
assert_eq!(meta.requires_dist, vec!["foo".parse().unwrap()]); assert_eq!(*meta.requires_dist, ["foo".parse().unwrap()]);
assert!(meta.provides_extras.is_empty()); assert!(meta.provides_extras.is_empty());
let s = r#" let s = r#"
@ -406,12 +414,12 @@ mod tests {
assert_eq!(meta.version, Version::new([1, 0])); assert_eq!(meta.version, Version::new([1, 0]));
assert_eq!(meta.requires_python, Some(">=3.6".parse().unwrap())); assert_eq!(meta.requires_python, Some(">=3.6".parse().unwrap()));
assert_eq!( assert_eq!(
meta.requires_dist, *meta.requires_dist,
vec![ [
"foo".parse().unwrap(), "foo".parse().unwrap(),
"bar; extra == \"dotenv\"".parse().unwrap() "bar; extra == \"dotenv\"".parse().unwrap()
] ]
); );
assert_eq!(meta.provides_extras, vec!["dotenv".parse().unwrap()]); assert_eq!(*meta.provides_extras, ["dotenv".parse().unwrap()]);
} }
} }

View File

@ -19,8 +19,8 @@ use crate::{LenientRequirement, MetadataError, VerbatimParsedUrl};
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct RequiresDist { pub struct RequiresDist {
pub name: PackageName, pub name: PackageName,
pub requires_dist: Vec<Requirement<VerbatimParsedUrl>>, pub requires_dist: Box<[Requirement<VerbatimParsedUrl>]>,
pub provides_extras: Vec<ExtraName>, pub provides_extras: Box<[ExtraName]>,
#[serde(default)] #[serde(default)]
pub dynamic: bool, pub dynamic: bool,
} }
@ -62,27 +62,35 @@ impl RequiresDist {
let name = project.name; let name = project.name;
// Extract the requirements. // Extract the requirements.
let mut requires_dist = project let requires_dist = project
.dependencies .dependencies
.unwrap_or_default() .unwrap_or_default()
.into_iter() .into_iter()
.map(|requires_dist| LenientRequirement::from_str(&requires_dist)) .map(|requires_dist| LenientRequirement::from_str(&requires_dist))
.map_ok(Requirement::from) .map_ok(Requirement::from)
.collect::<Result<Vec<_>, _>>()?; .chain(
project
.optional_dependencies
.as_ref()
.iter()
.flat_map(|index| {
index.iter().flat_map(|(extras, requirements)| {
requirements
.iter()
.map(|requires_dist| LenientRequirement::from_str(requires_dist))
.map_ok(Requirement::from)
.map_ok(move |requirement| requirement.with_extra_marker(extras))
})
}),
)
.collect::<Result<Box<_>, _>>()?;
// Extract the optional dependencies. // Extract the optional dependencies.
let mut provides_extras: Vec<ExtraName> = Vec::new(); let provides_extras = project
for (extra, requirements) in project.optional_dependencies.unwrap_or_default() { .optional_dependencies
requires_dist.extend( .unwrap_or_default()
requirements .into_keys()
.into_iter() .collect::<Box<_>>();
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
.map_ok(Requirement::from)
.map_ok(|requirement| requirement.with_extra_marker(&extra))
.collect::<Result<Vec<_>, _>>()?,
);
provides_extras.push(extra);
}
Ok(Self { Ok(Self {
name, name,

View File

@ -113,7 +113,7 @@ impl<'a, Context: BuildContext> ExtrasResolver<'a, Context> {
// Sort extras for consistency. // Sort extras for consistency.
let extras = { let extras = {
let mut extras = metadata.provides_extras; let mut extras = metadata.provides_extras.to_vec();
extras.sort_unstable(); extras.sort_unstable();
extras extras
}; };

View File

@ -178,9 +178,7 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> {
}; };
// Respect recursive extras by propagating the source extras to the dependencies. // Respect recursive extras by propagating the source extras to the dependencies.
let requires_dist = metadata let requires_dist = Box::into_iter(metadata.requires_dist)
.requires_dist
.into_iter()
.chain( .chain(
metadata metadata
.dependency_groups .dependency_groups

View File

@ -22,11 +22,11 @@ use uv_types::{BuildContext, HashStrategy};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SourceTreeResolution { pub struct SourceTreeResolution {
/// The requirements sourced from the source trees. /// The requirements sourced from the source trees.
pub requirements: Vec<Requirement>, pub requirements: Box<[Requirement]>,
/// The names of the projects that were resolved. /// The names of the projects that were resolved.
pub project: PackageName, pub project: PackageName,
/// The extras used when resolving the requirements. /// The extras used when resolving the requirements.
pub extras: Vec<ExtraName>, pub extras: Box<[ExtraName]>,
} }
/// A resolver for requirements specified via source trees. /// A resolver for requirements specified via source trees.
@ -141,6 +141,7 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> {
} }
} }
let requirements = requirements.into_boxed_slice();
let project = metadata.name; let project = metadata.name;
let extras = metadata.provides_extras; let extras = metadata.provides_extras;

View File

@ -1072,7 +1072,7 @@ impl Lock {
/// Return a [`SatisfiesResult`] if the given extras do not match the [`Package`] metadata. /// Return a [`SatisfiesResult`] if the given extras do not match the [`Package`] metadata.
fn satisfies_provides_extra<'lock>( fn satisfies_provides_extra<'lock>(
&self, &self,
provides_extra: Vec<ExtraName>, provides_extra: Box<[ExtraName]>,
package: &'lock Package, package: &'lock Package,
) -> SatisfiesResult<'lock> { ) -> SatisfiesResult<'lock> {
if !self.supports_provides_extra() { if !self.supports_provides_extra() {
@ -1083,7 +1083,7 @@ impl Lock {
let actual: BTreeSet<_> = package.metadata.provides_extras.iter().collect(); let actual: BTreeSet<_> = package.metadata.provides_extras.iter().collect();
if expected != actual { if expected != actual {
let expected = provides_extra.into_iter().collect(); let expected = Box::into_iter(provides_extra).collect();
return SatisfiesResult::MismatchedPackageProvidesExtra( return SatisfiesResult::MismatchedPackageProvidesExtra(
&package.id.name, &package.id.name,
package.id.version.as_ref(), package.id.version.as_ref(),
@ -1099,8 +1099,8 @@ impl Lock {
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
fn satisfies_requires_dist<'lock>( fn satisfies_requires_dist<'lock>(
&self, &self,
requires_dist: Vec<Requirement>, requires_dist: Box<[Requirement]>,
dependency_groups: BTreeMap<GroupName, Vec<Requirement>>, dependency_groups: BTreeMap<GroupName, Box<[Requirement]>>,
package: &'lock Package, package: &'lock Package,
root: &Path, root: &Path,
) -> Result<SatisfiesResult<'lock>, LockError> { ) -> Result<SatisfiesResult<'lock>, LockError> {
@ -1117,8 +1117,7 @@ impl Lock {
}; };
// Validate the `requires-dist` metadata. // Validate the `requires-dist` metadata.
let expected: BTreeSet<_> = requires_dist let expected: BTreeSet<_> = Box::into_iter(requires_dist)
.into_iter()
.map(|requirement| normalize_requirement(requirement, root)) .map(|requirement| normalize_requirement(requirement, root))
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
let actual: BTreeSet<_> = package let actual: BTreeSet<_> = package
@ -1145,8 +1144,7 @@ impl Lock {
.map(|(group, requirements)| { .map(|(group, requirements)| {
Ok::<_, LockError>(( Ok::<_, LockError>((
group, group,
requirements Box::into_iter(requirements)
.into_iter()
.map(|requirement| normalize_requirement(requirement, root)) .map(|requirement| normalize_requirement(requirement, root))
.collect::<Result<_, _>>()?, .collect::<Result<_, _>>()?,
)) ))
@ -1977,7 +1975,7 @@ impl Package {
.map_err(LockErrorKind::RequirementRelativePath)? .map_err(LockErrorKind::RequirementRelativePath)?
}; };
let provides_extras = if id.source.is_immutable() { let provides_extras = if id.source.is_immutable() {
Vec::default() Box::default()
} else { } else {
annotated_dist annotated_dist
.metadata .metadata
@ -2863,7 +2861,7 @@ struct PackageMetadata {
#[serde(default)] #[serde(default)]
requires_dist: BTreeSet<Requirement>, requires_dist: BTreeSet<Requirement>,
#[serde(default)] #[serde(default)]
provides_extras: Vec<ExtraName>, provides_extras: Box<[ExtraName]>,
#[serde(default, rename = "requires-dev", alias = "dependency-groups")] #[serde(default, rename = "requires-dev", alias = "dependency-groups")]
dependency_groups: BTreeMap<GroupName, BTreeSet<Requirement>>, dependency_groups: BTreeMap<GroupName, BTreeSet<Requirement>>,
} }

View File

@ -58,10 +58,9 @@ impl PubGrubDependency {
} else { } else {
Either::Right(iter::empty()) Either::Right(iter::empty())
}; };
let extras = requirement.extras.to_vec(); Either::Left(Either::Left(base.chain(
Either::Left(Either::Left( Box::into_iter(requirement.extras.clone()).map(|extra| (Some(extra), None)),
base.chain(extras.into_iter().map(|extra| (Some(extra), None))), )))
))
} else if !requirement.groups.is_empty() { } else if !requirement.groups.is_empty() {
let base = if requirement let base = if requirement
.groups .groups
@ -72,10 +71,9 @@ impl PubGrubDependency {
} else { } else {
Either::Right(iter::empty()) Either::Right(iter::empty())
}; };
let groups = requirement.groups.to_vec(); Either::Left(Either::Right(base.chain(
Either::Left(Either::Right( Box::into_iter(requirement.groups.clone()).map(|group| (None, Some(group))),
base.chain(groups.into_iter().map(|group| (None, Some(group)))), )))
))
} else { } else {
Either::Right(iter::once((None, None))) Either::Right(iter::once((None, None)))
}; };

View File

@ -1849,7 +1849,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
fn flatten_requirements<'a>( fn flatten_requirements<'a>(
&'a self, &'a self,
dependencies: &'a [Requirement], dependencies: &'a [Requirement],
dev_dependencies: &'a BTreeMap<GroupName, Vec<Requirement>>, dev_dependencies: &'a BTreeMap<GroupName, Box<[Requirement]>>,
extra: Option<&'a ExtraName>, extra: Option<&'a ExtraName>,
dev: Option<&'a GroupName>, dev: Option<&'a GroupName>,
name: Option<&PackageName>, name: Option<&PackageName>,

View File

@ -97,9 +97,7 @@ pub(crate) fn pip_show(
if let Ok(metadata) = dist.metadata() { if let Ok(metadata) = dist.metadata() {
requires_map.insert( requires_map.insert(
dist.name(), dist.name(),
metadata Box::into_iter(metadata.requires_dist)
.requires_dist
.into_iter()
.filter(|req| req.evaluate_markers(&markers, &[])) .filter(|req| req.evaluate_markers(&markers, &[]))
.map(|req| req.name) .map(|req| req.name)
.sorted_unstable() .sorted_unstable()
@ -115,9 +113,7 @@ pub(crate) fn pip_show(
continue; continue;
} }
if let Ok(metadata) = installed.metadata() { if let Ok(metadata) = installed.metadata() {
let requires = metadata let requires = Box::into_iter(metadata.requires_dist)
.requires_dist
.into_iter()
.filter(|req| req.evaluate_markers(&markers, &[])) .filter(|req| req.evaluate_markers(&markers, &[]))
.map(|req| req.name) .map(|req| req.name)
.collect_vec(); .collect_vec();