Skip to content

Commit 5f842f7

Browse files
committed
Permit '+' in feature name
We permit "c++20" and "dependency/c++20". But we do not permit "c++20/feature". In a Cargo.toml these would appear as: [features] default = ["c++20"] "c++20" = ["my-dependency/c++20"]
1 parent c982a71 commit 5f842f7

File tree

3 files changed

+20
-12
lines changed

3 files changed

+20
-12
lines changed

src/models/krate.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -269,26 +269,31 @@ impl Crate {
269269
.unwrap_or(false)
270270
}
271271

272+
/// Validates the THIS parts of `features = ["THIS", "and/THIS"]`.
272273
pub fn valid_feature_name(name: &str) -> bool {
273274
!name.is_empty()
274275
&& name
275276
.chars()
276-
.all(|c| c.is_alphanumeric() || c == '_' || c == '-')
277-
&& name.chars().all(|c| c.is_ascii())
277+
.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '+')
278278
}
279279

280+
/// Validates the prefix in front of the slash: `features = ["THIS/feature"]`.
281+
/// Normally this corresponds to the crate name of a dependency.
282+
fn valid_feature_prefix(name: &str) -> bool {
283+
!name.is_empty()
284+
&& name
285+
.chars()
286+
.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
287+
}
288+
289+
/// Validates a whole feature string, `features = ["THIS", "ALL/THIS"]`.
280290
pub fn valid_feature(name: &str) -> bool {
281291
let mut parts = name.split('/');
282-
match parts.next() {
283-
Some(part) if !Crate::valid_feature_name(part) => return false,
284-
None => return false,
285-
_ => {}
286-
}
287-
match parts.next() {
288-
Some(part) if !Crate::valid_feature_name(part) => return false,
289-
_ => {}
290-
}
292+
let name_part = parts.next_back(); // required
293+
let prefix_part = parts.next_back(); // optional
291294
parts.next().is_none()
295+
&& name_part.map_or(false, Crate::valid_feature_name)
296+
&& prefix_part.map_or(true, Crate::valid_feature_prefix)
292297
}
293298

294299
pub fn minimal_encodable(

src/tests/krate.rs

+3
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,9 @@ fn valid_feature_names() {
983983
assert!(!Crate::valid_feature("%/%"));
984984
assert!(Crate::valid_feature("a/a"));
985985
assert!(Crate::valid_feature("32-column-tables"));
986+
assert!(Crate::valid_feature("c++20"));
987+
assert!(Crate::valid_feature("krate/c++20"));
988+
assert!(!Crate::valid_feature("c++20/wow"));
986989
}
987990

988991
#[test]

src/views/krate_publish.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ impl<'de> Deserialize<'de> for EncodableFeatureName {
113113
if !Crate::valid_feature_name(&s) {
114114
let value = de::Unexpected::Str(&s);
115115
let expected = "a valid feature name containing only letters, \
116-
numbers, hyphens, or underscores";
116+
numbers, '-', '+', or '_'";
117117
Err(de::Error::invalid_value(value, &expected))
118118
} else {
119119
Ok(EncodableFeatureName(s))

0 commit comments

Comments
 (0)