Skip to content

Commit ea3c207

Browse files
committed
Simplify checking feature syntax
1 parent ac8c6ab commit ea3c207

File tree

1 file changed

+56
-95
lines changed

1 file changed

+56
-95
lines changed

src/cargo/core/summary.rs

Lines changed: 56 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,15 @@ fn build_feature_map(
156156
dependencies: &[Dependency],
157157
) -> CargoResult<FeatureMap> {
158158
use self::FeatureValue::*;
159-
let mut dep_map = HashMap::new();
159+
// A map of dependency names to whether there are any that are optional.
160+
let mut dep_map: HashMap<InternedString, bool> = HashMap::new();
160161
for dep in dependencies.iter() {
161-
dep_map
162-
.entry(dep.name_in_toml())
163-
.or_insert_with(Vec::new)
164-
.push(dep);
162+
let has_optional = dep_map.entry(dep.name_in_toml()).or_insert(false);
163+
if dep.is_optional() {
164+
*has_optional = true;
165+
}
165166
}
167+
let dep_map = dep_map; // We are done mutating this variable
166168

167169
let mut map: FeatureMap = features
168170
.iter()
@@ -180,117 +182,78 @@ fn build_feature_map(
180182
let explicitly_listed: HashSet<_> = map
181183
.values()
182184
.flatten()
183-
.filter_map(|fv| match fv {
184-
Dep { dep_name } => Some(*dep_name),
185-
_ => None,
186-
})
185+
.filter_map(|fv| fv.explicitly_name())
187186
.collect();
188187
for dep in dependencies {
189188
if !dep.is_optional() {
190189
continue;
191190
}
192-
let dep_name_in_toml = dep.name_in_toml();
193-
if features.contains_key(&dep_name_in_toml) || explicitly_listed.contains(&dep_name_in_toml)
194-
{
191+
let dep_name = dep.name_in_toml();
192+
if features.contains_key(&dep_name) || explicitly_listed.contains(&dep_name) {
195193
continue;
196194
}
197-
let fv = Dep {
198-
dep_name: dep_name_in_toml,
199-
};
200-
map.insert(dep_name_in_toml, vec![fv]);
195+
map.insert(dep_name, vec![Dep { dep_name }]);
201196
}
197+
let map = map; // We are done mutating this variable
202198

203199
// Validate features are listed properly.
204200
for (feature, fvs) in &map {
205201
FeatureName::new(feature)?;
206202
for fv in fvs {
207203
// Find data for the referenced dependency...
208-
let dep_data = {
209-
match fv {
210-
Feature(dep_name) | Dep { dep_name, .. } | DepFeature { dep_name, .. } => {
211-
dep_map.get(dep_name)
212-
}
213-
}
214-
};
215-
let is_optional_dep = dep_data
216-
.iter()
217-
.flat_map(|d| d.iter())
218-
.any(|d| d.is_optional());
204+
let dep_data = dep_map.get(&fv.dep_name());
219205
let is_any_dep = dep_data.is_some();
206+
let is_optional_dep = dep_data.is_some_and(|&o| o);
220207
match fv {
221208
Feature(f) => {
222209
if !features.contains_key(f) {
223210
if !is_any_dep {
224211
bail!(
225-
"feature `{}` includes `{}` which is neither a dependency \
226-
nor another feature",
227-
feature,
228-
fv
229-
);
212+
"feature `{feature}` includes `{fv}` which is neither a dependency \
213+
nor another feature"
214+
);
230215
}
231216
if is_optional_dep {
232217
if !map.contains_key(f) {
233218
bail!(
234-
"feature `{}` includes `{}`, but `{}` is an \
219+
"feature `{feature}` includes `{fv}`, but `{f}` is an \
235220
optional dependency without an implicit feature\n\
236-
Use `dep:{}` to enable the dependency.",
237-
feature,
238-
fv,
239-
f,
240-
f
221+
Use `dep:{f}` to enable the dependency."
241222
);
242223
}
243224
} else {
244-
bail!("feature `{}` includes `{}`, but `{}` is not an optional dependency\n\
225+
bail!("feature `{feature}` includes `{fv}`, but `{f}` is not an optional dependency\n\
245226
A non-optional dependency of the same name is defined; \
246-
consider adding `optional = true` to its definition.",
247-
feature, fv, f);
227+
consider adding `optional = true` to its definition.");
248228
}
249229
}
250230
}
251231
Dep { dep_name } => {
252232
if !is_any_dep {
253-
bail!(
254-
"feature `{}` includes `{}`, but `{}` is not listed as a dependency",
255-
feature,
256-
fv,
257-
dep_name
258-
);
233+
bail!("feature `{feature}` includes `{fv}`, but `{dep_name}` is not listed as a dependency");
259234
}
260235
if !is_optional_dep {
261236
bail!(
262-
"feature `{}` includes `{}`, but `{}` is not an optional dependency\n\
237+
"feature `{feature}` includes `{fv}`, but `{dep_name}` is not an optional dependency\n\
263238
A non-optional dependency of the same name is defined; \
264-
consider adding `optional = true` to its definition.",
265-
feature,
266-
fv,
267-
dep_name
239+
consider adding `optional = true` to its definition."
268240
);
269241
}
270242
}
271243
DepFeature {
272244
dep_name,
273245
dep_feature,
274246
weak,
275-
..
276247
} => {
277248
// Early check for some unlikely syntax.
278249
if dep_feature.contains('/') {
279-
bail!(
280-
"multiple slashes in feature `{}` (included by feature `{}`) are not allowed",
281-
fv,
282-
feature
283-
);
250+
bail!("multiple slashes in feature `{fv}` (included by feature `{feature}`) are not allowed");
284251
}
285252

286253
// dep: cannot be combined with /
287254
if let Some(stripped_dep) = dep_name.strip_prefix("dep:") {
288255
let has_other_dep = explicitly_listed.contains(stripped_dep);
289-
let is_optional = dep_map
290-
.get(stripped_dep)
291-
.iter()
292-
.flat_map(|d| d.iter())
293-
.any(|d| d.is_optional());
256+
let is_optional = dep_map.get(stripped_dep).is_some_and(|&o| o);
294257
let extra_help = if *weak || has_other_dep || !is_optional {
295258
// In this case, the user should just remove dep:.
296259
// Note that "hiding" an optional dependency
@@ -314,18 +277,14 @@ fn build_feature_map(
314277

315278
// Validation of the feature name will be performed in the resolver.
316279
if !is_any_dep {
317-
bail!(
318-
"feature `{}` includes `{}`, but `{}` is not a dependency",
319-
feature,
320-
fv,
321-
dep_name
322-
);
280+
bail!("feature `{feature}` includes `{fv}`, but `{dep_name}` is not a dependency");
323281
}
324282
if *weak && !is_optional_dep {
325-
bail!("feature `{}` includes `{}` with a `?`, but `{}` is not an optional dependency\n\
283+
bail!(
284+
"feature `{feature}` includes `{fv}` with a `?`, but `{dep_name}` is not an optional dependency\n\
326285
A non-optional dependency of the same name is defined; \
327-
consider removing the `?` or changing the dependency to be optional",
328-
feature, fv, dep_name);
286+
consider removing the `?` or changing the dependency to be optional"
287+
);
329288
}
330289
}
331290
}
@@ -341,15 +300,13 @@ fn build_feature_map(
341300
_ => None,
342301
})
343302
.collect();
344-
if let Some(dep) = dependencies
303+
if let Some((dep, _)) = dep_map
345304
.iter()
346-
.find(|dep| dep.is_optional() && !used.contains(&dep.name_in_toml()))
305+
.find(|&(dep, &is_optional)| is_optional && !used.contains(dep))
347306
{
348307
bail!(
349-
"optional dependency `{}` is not included in any feature\n\
350-
Make sure that `dep:{}` is included in one of features in the [features] table.",
351-
dep.name_in_toml(),
352-
dep.name_in_toml(),
308+
"optional dependency `{dep}` is not included in any feature\n\
309+
Make sure that `dep:{dep}` is included in one of features in the [features] table."
353310
);
354311
}
355312

@@ -376,19 +333,13 @@ pub enum FeatureValue {
376333

377334
impl FeatureValue {
378335
pub fn new(feature: InternedString) -> FeatureValue {
379-
match feature.find('/') {
380-
Some(pos) => {
381-
let (dep, dep_feat) = feature.split_at(pos);
382-
let dep_feat = &dep_feat[1..];
383-
let (dep, weak) = if let Some(dep) = dep.strip_suffix('?') {
384-
(dep, true)
385-
} else {
386-
(dep, false)
387-
};
336+
match feature.split_once('/') {
337+
Some((dep, dep_feat)) => {
338+
let dep_name = dep.strip_suffix('?');
388339
FeatureValue::DepFeature {
389-
dep_name: InternedString::new(dep),
340+
dep_name: InternedString::new(dep_name.unwrap_or(dep)),
390341
dep_feature: InternedString::new(dep_feat),
391-
weak,
342+
weak: dep_name.is_some(),
392343
}
393344
}
394345
None => {
@@ -403,25 +354,35 @@ impl FeatureValue {
403354
}
404355
}
405356

406-
/// Returns `true` if this feature explicitly used `dep:` syntax.
407-
pub fn has_dep_prefix(&self) -> bool {
408-
matches!(self, FeatureValue::Dep { .. })
357+
fn explicitly_name(&self) -> Option<InternedString> {
358+
match self {
359+
FeatureValue::Dep { dep_name, .. } => Some(*dep_name),
360+
_ => None,
361+
}
362+
}
363+
364+
fn dep_name(&self) -> InternedString {
365+
match self {
366+
FeatureValue::Feature(dep_name)
367+
| FeatureValue::Dep { dep_name, .. }
368+
| FeatureValue::DepFeature { dep_name, .. } => *dep_name,
369+
}
409370
}
410371
}
411372

412373
impl fmt::Display for FeatureValue {
413374
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
414375
use self::FeatureValue::*;
415376
match self {
416-
Feature(feat) => write!(f, "{}", feat),
417-
Dep { dep_name } => write!(f, "dep:{}", dep_name),
377+
Feature(feat) => write!(f, "{feat}"),
378+
Dep { dep_name } => write!(f, "dep:{dep_name}"),
418379
DepFeature {
419380
dep_name,
420381
dep_feature,
421382
weak,
422383
} => {
423384
let weak = if *weak { "?" } else { "" };
424-
write!(f, "{}{}/{}", dep_name, weak, dep_feature)
385+
write!(f, "{dep_name}{weak}/{dep_feature}")
425386
}
426387
}
427388
}

0 commit comments

Comments
 (0)