uv_configuration/
extras.rs1use std::{borrow::Cow, sync::Arc};
2
3use uv_normalize::{DefaultExtras, ExtraName};
4
5#[derive(Debug, Default, Clone)]
9pub struct ExtrasSpecification(Arc<ExtrasSpecificationInner>);
10
11#[derive(Debug, Default, Clone)]
13pub struct ExtrasSpecificationInner {
14 include: IncludeExtras,
16 exclude: Vec<ExtraName>,
18 only_extras: bool,
24 history: ExtrasSpecificationHistory,
26}
27
28impl ExtrasSpecification {
29 fn from_history(history: ExtrasSpecificationHistory) -> Self {
34 let ExtrasSpecificationHistory {
35 mut extra,
36 mut only_extra,
37 no_extra,
38 all_extras,
39 no_default_extras,
40 mut defaults,
41 } = history.clone();
42
43 let only_extras = !only_extra.is_empty();
47 let default_extras = !no_default_extras && !only_extras;
49
50 let include = if all_extras {
51 IncludeExtras::All
53 } else {
54 extra.append(&mut only_extra);
56 if default_extras {
58 match &mut defaults {
59 DefaultExtras::All => IncludeExtras::All,
60 DefaultExtras::List(defaults) => {
61 extra.append(defaults);
62 IncludeExtras::Some(extra)
63 }
64 }
65 } else {
66 IncludeExtras::Some(extra)
67 }
68 };
69
70 Self(Arc::new(ExtrasSpecificationInner {
71 include,
72 exclude: no_extra,
73 only_extras,
74 history,
75 }))
76 }
77
78 pub fn from_args(
80 extra: Vec<ExtraName>,
81 no_extra: Vec<ExtraName>,
82 no_default_extras: bool,
83 only_extra: Vec<ExtraName>,
84 all_extras: bool,
85 ) -> Self {
86 Self::from_history(ExtrasSpecificationHistory {
87 extra,
88 only_extra,
89 no_extra,
90 all_extras,
91 no_default_extras,
92 defaults: DefaultExtras::default(),
94 })
95 }
96
97 pub fn from_extra(extra: Vec<ExtraName>) -> Self {
99 Self::from_history(ExtrasSpecificationHistory {
100 extra,
101 ..Default::default()
102 })
103 }
104
105 pub fn from_all_extras() -> Self {
107 Self::from_history(ExtrasSpecificationHistory {
108 all_extras: true,
109 ..Default::default()
110 })
111 }
112
113 pub fn with_defaults(&self, defaults: DefaultExtras) -> ExtrasSpecificationWithDefaults {
115 let mut history = self.0.history.clone();
117 history.defaults = defaults;
118
119 ExtrasSpecificationWithDefaults {
120 cur: Self::from_history(history),
121 }
122 }
123}
124
125impl std::ops::Deref for ExtrasSpecification {
126 type Target = ExtrasSpecificationInner;
127 fn deref(&self) -> &Self::Target {
128 &self.0
129 }
130}
131
132impl ExtrasSpecificationInner {
133 fn prod(&self) -> bool {
142 !self.only_extras
143 }
144
145 pub fn contains(&self, extra: &ExtraName) -> bool {
147 !self.exclude.contains(extra) && self.include.contains(extra)
149 }
150
151 pub fn extra_names<'a, Names>(
154 &'a self,
155 all_names: Names,
156 ) -> impl Iterator<Item = &'a ExtraName> + 'a
157 where
158 Names: Iterator<Item = &'a ExtraName> + 'a,
159 {
160 all_names.filter(move |name| self.contains(name))
161 }
162
163 pub fn explicit_names(&self) -> impl Iterator<Item = &ExtraName> {
165 let ExtrasSpecificationHistory {
166 extra,
167 only_extra,
168 no_extra,
169 all_extras: _,
171 no_default_extras: _,
172 defaults: _,
173 } = self.history();
174
175 extra.iter().chain(no_extra).chain(only_extra)
176 }
177
178 pub fn is_empty(&self) -> bool {
180 self.prod() && self.exclude.is_empty() && self.include.is_empty()
181 }
182
183 pub fn history(&self) -> &ExtrasSpecificationHistory {
185 &self.history
186 }
187}
188
189#[derive(Debug, Default, Clone)]
191pub struct ExtrasSpecificationHistory {
192 extra: Vec<ExtraName>,
193 only_extra: Vec<ExtraName>,
194 no_extra: Vec<ExtraName>,
195 all_extras: bool,
196 no_default_extras: bool,
197 defaults: DefaultExtras,
198}
199
200impl ExtrasSpecificationHistory {
201 pub fn as_flags_pretty(&self) -> Vec<Cow<'_, str>> {
210 let Self {
211 extra,
212 no_extra,
213 all_extras,
214 only_extra,
215 no_default_extras,
216 defaults: _,
218 } = self;
219
220 let mut flags = vec![];
221 if *all_extras {
222 flags.push(Cow::Borrowed("--all-extras"));
223 }
224 if *no_default_extras {
225 flags.push(Cow::Borrowed("--no-default-extras"));
226 }
227 match &**extra {
228 [] => {}
229 [extra] => flags.push(Cow::Owned(format!("--extra {extra}"))),
230 [..] => flags.push(Cow::Borrowed("--extra")),
231 }
232 match &**only_extra {
233 [] => {}
234 [extra] => flags.push(Cow::Owned(format!("--only-extra {extra}"))),
235 [..] => flags.push(Cow::Borrowed("--only-extra")),
236 }
237 match &**no_extra {
238 [] => {}
239 [extra] => flags.push(Cow::Owned(format!("--no-extra {extra}"))),
240 [..] => flags.push(Cow::Borrowed("--no-extra")),
241 }
242 flags
243 }
244}
245
246#[derive(Debug, Clone)]
248pub struct ExtrasSpecificationWithDefaults {
249 cur: ExtrasSpecification,
251}
252
253impl std::ops::Deref for ExtrasSpecificationWithDefaults {
254 type Target = ExtrasSpecification;
255 fn deref(&self) -> &Self::Target {
256 &self.cur
257 }
258}
259
260#[derive(Debug, Clone)]
261pub enum IncludeExtras {
262 Some(Vec<ExtraName>),
264 All,
266}
267
268impl IncludeExtras {
269 fn contains(&self, extra: &ExtraName) -> bool {
271 match self {
272 Self::Some(extras) => extras.contains(extra),
273 Self::All => true,
274 }
275 }
276
277 fn is_empty(&self) -> bool {
279 match self {
280 Self::Some(extras) => extras.is_empty(),
281 Self::All => false,
284 }
285 }
286}
287
288impl Default for IncludeExtras {
289 fn default() -> Self {
290 Self::Some(Vec::new())
291 }
292}