uv_configuration/
overrides.rs1use std::borrow::Cow;
2
3use either::Either;
4use rustc_hash::{FxBuildHasher, FxHashMap};
5
6use uv_distribution_types::Requirement;
7use uv_normalize::PackageName;
8use uv_pep508::MarkerTree;
9
10#[derive(Debug, Default, Clone)]
12pub struct Overrides(FxHashMap<PackageName, Vec<Requirement>>);
13
14impl Overrides {
15 pub fn from_requirements(requirements: Vec<Requirement>) -> Self {
17 let mut overrides: FxHashMap<PackageName, Vec<Requirement>> =
18 FxHashMap::with_capacity_and_hasher(requirements.len(), FxBuildHasher);
19 for requirement in requirements {
20 overrides
21 .entry(requirement.name.clone())
22 .or_default()
23 .push(requirement);
24 }
25 Self(overrides)
26 }
27
28 pub fn requirements(&self) -> impl Iterator<Item = &Requirement> {
30 self.0.values().flat_map(|requirements| requirements.iter())
31 }
32
33 pub fn get(&self, name: &PackageName) -> Option<&Vec<Requirement>> {
35 self.0.get(name)
36 }
37
38 pub fn apply<'a>(
42 &'a self,
43 requirements: impl IntoIterator<Item = &'a Requirement>,
44 ) -> impl Iterator<Item = Cow<'a, Requirement>> {
45 if self.0.is_empty() {
46 return Either::Left(requirements.into_iter().map(Cow::Borrowed));
48 }
49
50 Either::Right(requirements.into_iter().flat_map(|requirement| {
51 let Some(overrides) = self.get(&requirement.name) else {
52 return Either::Left(std::iter::once(Cow::Borrowed(requirement)));
54 };
55
56 let Some(extra_expression) = requirement.marker.top_level_extra() else {
59 return Either::Right(Either::Right(overrides.iter().map(Cow::Borrowed)));
61 };
62
63 Either::Right(Either::Left(overrides.iter().map(
68 move |override_requirement| {
69 let mut joint_marker = MarkerTree::expression(extra_expression.clone());
71 joint_marker.and(override_requirement.marker);
72 Cow::Owned(Requirement {
73 marker: joint_marker,
74 ..override_requirement.clone()
75 })
76 },
77 )))
78 }))
79 }
80}