uv_configuration/
constraints.rs1use std::borrow::Cow;
2
3use either::Either;
4use rustc_hash::FxHashMap;
5
6use uv_distribution_types::{Requirement, RequirementSource};
7use uv_normalize::PackageName;
8use uv_pep508::MarkerTree;
9
10#[derive(Debug, Default, Clone)]
12pub struct Constraints(FxHashMap<PackageName, Vec<Requirement>>);
13
14impl Constraints {
15 pub fn from_requirements(requirements: impl Iterator<Item = Requirement>) -> Self {
17 let mut constraints: FxHashMap<PackageName, Vec<Requirement>> = FxHashMap::default();
18 for requirement in requirements {
19 if let RequirementSource::Registry { specifier, .. } = &requirement.source {
21 if specifier.is_empty() {
22 continue;
23 }
24 }
25
26 constraints
27 .entry(requirement.name.clone())
28 .or_default()
29 .push(Requirement {
30 extras: Box::new([]),
32 ..requirement
33 });
34 }
35 Self(constraints)
36 }
37
38 pub fn requirements(&self) -> impl Iterator<Item = &Requirement> {
40 self.0.values().flat_map(|requirements| requirements.iter())
41 }
42
43 pub fn get(&self, name: &PackageName) -> Option<&Vec<Requirement>> {
45 self.0.get(name)
46 }
47
48 pub fn apply<'a>(
52 &'a self,
53 requirements: impl IntoIterator<Item = Cow<'a, Requirement>>,
54 ) -> impl Iterator<Item = Cow<'a, Requirement>> {
55 requirements.into_iter().flat_map(|requirement| {
56 let Some(constraints) = self.get(&requirement.name) else {
57 return Either::Left(std::iter::once(requirement));
59 };
60
61 let Some(extra_expression) = requirement.marker.top_level_extra() else {
64 return Either::Right(Either::Right(
66 std::iter::once(requirement).chain(constraints.iter().map(Cow::Borrowed)),
67 ));
68 };
69
70 Either::Right(Either::Left(std::iter::once(requirement).chain(
75 constraints.iter().cloned().map(move |constraint| {
76 let mut joint_marker = MarkerTree::expression(extra_expression.clone());
78 joint_marker.and(constraint.marker);
79 Cow::Owned(Requirement {
80 marker: joint_marker,
81 ..constraint
82 })
83 }),
84 )))
85 })
86 }
87}