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 #[allow(clippy::fn_params_excessive_bools)]
80 pub fn from_args(
81 extra: Vec<ExtraName>,
82 no_extra: Vec<ExtraName>,
83 no_default_extras: bool,
84 only_extra: Vec<ExtraName>,
85 all_extras: bool,
86 ) -> Self {
87 Self::from_history(ExtrasSpecificationHistory {
88 extra,
89 only_extra,
90 no_extra,
91 all_extras,
92 no_default_extras,
93 defaults: DefaultExtras::default(),
95 })
96 }
97
98 pub fn from_extra(extra: Vec<ExtraName>) -> Self {
100 Self::from_history(ExtrasSpecificationHistory {
101 extra,
102 ..Default::default()
103 })
104 }
105
106 pub fn from_all_extras() -> Self {
108 Self::from_history(ExtrasSpecificationHistory {
109 all_extras: true,
110 ..Default::default()
111 })
112 }
113
114 pub fn with_defaults(&self, defaults: DefaultExtras) -> ExtrasSpecificationWithDefaults {
116 let mut history = self.0.history.clone();
118 history.defaults = defaults;
119
120 ExtrasSpecificationWithDefaults {
121 cur: Self::from_history(history),
122 prev: self.clone(),
123 }
124 }
125}
126
127impl std::ops::Deref for ExtrasSpecification {
128 type Target = ExtrasSpecificationInner;
129 fn deref(&self) -> &Self::Target {
130 &self.0
131 }
132}
133
134impl ExtrasSpecificationInner {
135 pub fn prod(&self) -> bool {
144 !self.only_extras
145 }
146
147 pub fn contains(&self, extra: &ExtraName) -> bool {
149 !self.exclude.contains(extra) && self.include.contains(extra)
151 }
152
153 pub fn desugarred_names(&self) -> impl Iterator<Item = &ExtraName> {
155 self.include.names().chain(&self.exclude)
156 }
157
158 pub fn extra_names<'a, Names>(
161 &'a self,
162 all_names: Names,
163 ) -> impl Iterator<Item = &'a ExtraName> + 'a
164 where
165 Names: Iterator<Item = &'a ExtraName> + 'a,
166 {
167 all_names.filter(move |name| self.contains(name))
168 }
169
170 pub fn explicit_names(&self) -> impl Iterator<Item = &ExtraName> {
172 let ExtrasSpecificationHistory {
173 extra,
174 only_extra,
175 no_extra,
176 all_extras: _,
178 no_default_extras: _,
179 defaults: _,
180 } = self.history();
181
182 extra.iter().chain(no_extra).chain(only_extra)
183 }
184
185 pub fn is_empty(&self) -> bool {
187 self.prod() && self.exclude.is_empty() && self.include.is_empty()
188 }
189
190 pub fn history(&self) -> &ExtrasSpecificationHistory {
192 &self.history
193 }
194}
195
196#[derive(Debug, Default, Clone)]
198pub struct ExtrasSpecificationHistory {
199 pub extra: Vec<ExtraName>,
200 pub only_extra: Vec<ExtraName>,
201 pub no_extra: Vec<ExtraName>,
202 pub all_extras: bool,
203 pub no_default_extras: bool,
204 pub defaults: DefaultExtras,
205}
206
207impl ExtrasSpecificationHistory {
208 pub fn as_flags_pretty(&self) -> Vec<Cow<'_, str>> {
217 let Self {
218 extra,
219 no_extra,
220 all_extras,
221 only_extra,
222 no_default_extras,
223 defaults: _,
225 } = self;
226
227 let mut flags = vec![];
228 if *all_extras {
229 flags.push(Cow::Borrowed("--all-extras"));
230 }
231 if *no_default_extras {
232 flags.push(Cow::Borrowed("--no-default-extras"));
233 }
234 match &**extra {
235 [] => {}
236 [extra] => flags.push(Cow::Owned(format!("--extra {extra}"))),
237 [..] => flags.push(Cow::Borrowed("--extra")),
238 }
239 match &**only_extra {
240 [] => {}
241 [extra] => flags.push(Cow::Owned(format!("--only-extra {extra}"))),
242 [..] => flags.push(Cow::Borrowed("--only-extra")),
243 }
244 match &**no_extra {
245 [] => {}
246 [extra] => flags.push(Cow::Owned(format!("--no-extra {extra}"))),
247 [..] => flags.push(Cow::Borrowed("--no-extra")),
248 }
249 flags
250 }
251}
252
253#[derive(Debug, Clone)]
259pub struct ExtrasSpecificationWithDefaults {
260 cur: ExtrasSpecification,
262 prev: ExtrasSpecification,
264}
265
266impl ExtrasSpecificationWithDefaults {
267 pub fn none() -> Self {
273 ExtrasSpecification::default().with_defaults(DefaultExtras::default())
274 }
275 pub fn contains_because_default(&self, extra: &ExtraName) -> bool {
277 self.cur.contains(extra) && !self.prev.contains(extra)
278 }
279}
280impl std::ops::Deref for ExtrasSpecificationWithDefaults {
281 type Target = ExtrasSpecification;
282 fn deref(&self) -> &Self::Target {
283 &self.cur
284 }
285}
286
287#[derive(Debug, Clone)]
288pub enum IncludeExtras {
289 Some(Vec<ExtraName>),
291 All,
293}
294
295impl IncludeExtras {
296 pub fn contains(&self, extra: &ExtraName) -> bool {
298 match self {
299 Self::Some(extras) => extras.contains(extra),
300 Self::All => true,
301 }
302 }
303
304 pub fn is_empty(&self) -> bool {
306 match self {
307 Self::Some(extras) => extras.is_empty(),
308 Self::All => false,
311 }
312 }
313
314 pub fn names(&self) -> std::slice::Iter<'_, ExtraName> {
316 match self {
317 Self::Some(extras) => extras.iter(),
318 Self::All => [].iter(),
319 }
320 }
321}
322
323impl Default for IncludeExtras {
324 fn default() -> Self {
325 Self::Some(Vec::new())
326 }
327}