-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Dogfood str_split_once()
#79809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dogfood str_split_once()
#79809
Changes from all commits
12db222
d6baf38
7bd47bd
85e9ea0
d2de69d
f68cc68
a3174de
989edf4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1296,8 +1296,10 @@ fn parse_output_types( | |
if !debugging_opts.parse_only { | ||
for list in matches.opt_strs("emit") { | ||
for output_type in list.split(',') { | ||
let mut parts = output_type.splitn(2, '='); | ||
let shorthand = parts.next().unwrap(); | ||
let (shorthand, path) = match output_type.split_once('=') { | ||
None => (output_type, None), | ||
Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))), | ||
}; | ||
let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { | ||
early_error( | ||
error_format, | ||
|
@@ -1308,7 +1310,6 @@ fn parse_output_types( | |
), | ||
) | ||
}); | ||
let path = parts.next().map(PathBuf::from); | ||
output_types.insert(output_type, path); | ||
} | ||
} | ||
|
@@ -1452,11 +1453,10 @@ fn parse_opt_level( | |
let max_c = matches | ||
.opt_strs_pos("C") | ||
.into_iter() | ||
.flat_map( | ||
|(i, s)| { | ||
if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None } | ||
}, | ||
) | ||
.flat_map(|(i, s)| { | ||
// NB: This can match a string without `=`. | ||
if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None } | ||
}) | ||
.max(); | ||
if max_o > max_c { | ||
OptLevel::Default | ||
|
@@ -1491,11 +1491,10 @@ fn select_debuginfo( | |
let max_c = matches | ||
.opt_strs_pos("C") | ||
.into_iter() | ||
.flat_map( | ||
|(i, s)| { | ||
if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None } | ||
}, | ||
) | ||
.flat_map(|(i, s)| { | ||
// NB: This can match a string without `=`. | ||
if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None } | ||
}) | ||
.max(); | ||
if max_g > max_c { | ||
DebugInfo::Full | ||
|
@@ -1528,23 +1527,26 @@ fn parse_libs( | |
.map(|s| { | ||
// Parse string of the form "[KIND=]lib[:new_name]", | ||
// where KIND is one of "dylib", "framework", "static". | ||
let mut parts = s.splitn(2, '='); | ||
let kind = parts.next().unwrap(); | ||
let (name, kind) = match (parts.next(), kind) { | ||
(None, name) => (name, NativeLibKind::Unspecified), | ||
(Some(name), "dylib") => (name, NativeLibKind::Dylib), | ||
(Some(name), "framework") => (name, NativeLibKind::Framework), | ||
(Some(name), "static") => (name, NativeLibKind::StaticBundle), | ||
(Some(name), "static-nobundle") => (name, NativeLibKind::StaticNoBundle), | ||
(_, s) => { | ||
early_error( | ||
error_format, | ||
&format!( | ||
"unknown library kind `{}`, expected \ | ||
one of dylib, framework, or static", | ||
s | ||
), | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just writing my reasoning down for posterity: The previous version is more compact, so I am almost inclined to say that it was better. However, the new version doesn't have That said, would flattening the two matches into one work better here? match s.split_once('=') {
Some(("dylib", name)) => ()
} ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ack that this is less compact, but I refactored to use the nested match because it reduces duplication and imo makes this code easier to grok, albeit longer. We no longer have to put match s.split_once('=') {
Some(("dylib", name)) => (),
Some(("framework", name)) => (),
...
} Instead, what do you think about adding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Not |
||
let (name, kind) = match s.split_once('=') { | ||
None => (s, NativeLibKind::Unspecified), | ||
Some((kind, name)) => { | ||
let kind = match kind { | ||
"dylib" => NativeLibKind::Dylib, | ||
"framework" => NativeLibKind::Framework, | ||
"static" => NativeLibKind::StaticBundle, | ||
"static-nobundle" => NativeLibKind::StaticNoBundle, | ||
s => { | ||
early_error( | ||
error_format, | ||
&format!( | ||
"unknown library kind `{}`, expected \ | ||
one of dylib, framework, or static", | ||
s | ||
), | ||
); | ||
} | ||
}; | ||
(name.to_string(), kind) | ||
} | ||
}; | ||
if kind == NativeLibKind::StaticNoBundle | ||
|
@@ -1556,10 +1558,11 @@ fn parse_libs( | |
accepted on the nightly compiler", | ||
); | ||
} | ||
let mut name_parts = name.splitn(2, ':'); | ||
let name = name_parts.next().unwrap(); | ||
let new_name = name_parts.next(); | ||
(name.to_owned(), new_name.map(|n| n.to_owned()), kind) | ||
let (name, new_name) = match name.split_once(':') { | ||
None => (name, None), | ||
Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())), | ||
}; | ||
(name, new_name, kind) | ||
}) | ||
.collect() | ||
} | ||
|
@@ -1580,20 +1583,13 @@ pub fn parse_externs( | |
let is_unstable_enabled = debugging_opts.unstable_options; | ||
let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new(); | ||
for arg in matches.opt_strs("extern") { | ||
let mut parts = arg.splitn(2, '='); | ||
let name = parts | ||
.next() | ||
.unwrap_or_else(|| early_error(error_format, "--extern value must not be empty")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This case could never happen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Niiiice! |
||
let path = parts.next().map(|s| s.to_string()); | ||
|
||
let mut name_parts = name.splitn(2, ':'); | ||
let first_part = name_parts.next(); | ||
let second_part = name_parts.next(); | ||
let (options, name) = match (first_part, second_part) { | ||
(Some(opts), Some(name)) => (Some(opts), name), | ||
(Some(name), None) => (None, name), | ||
(None, None) => early_error(error_format, "--extern name must not be empty"), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This case could never happen, the first value is always |
||
_ => unreachable!(), | ||
let (name, path) = match arg.split_once('=') { | ||
None => (arg, None), | ||
Some((name, path)) => (name.to_string(), Some(path.to_string())), | ||
}; | ||
let (options, name) = match name.split_once(':') { | ||
None => (None, name), | ||
Some((opts, name)) => (Some(opts), name.to_string()), | ||
}; | ||
|
||
let entry = externs.entry(name.to_owned()); | ||
|
@@ -1682,17 +1678,12 @@ fn parse_remap_path_prefix( | |
matches | ||
.opt_strs("remap-path-prefix") | ||
.into_iter() | ||
.map(|remap| { | ||
let mut parts = remap.rsplitn(2, '='); // reverse iterator | ||
let to = parts.next(); | ||
let from = parts.next(); | ||
match (from, to) { | ||
(Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)), | ||
_ => early_error( | ||
error_format, | ||
"--remap-path-prefix must contain '=' between FROM and TO", | ||
), | ||
} | ||
.map(|remap| match remap.rsplit_once('=') { | ||
None => early_error( | ||
error_format, | ||
"--remap-path-prefix must contain '=' between FROM and TO", | ||
), | ||
Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)), | ||
}) | ||
.collect() | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,30 +105,24 @@ impl TimeThreshold { | |
/// value. | ||
pub fn from_env_var(env_var_name: &str) -> Option<Self> { | ||
let durations_str = env::var(env_var_name).ok()?; | ||
let (warn_str, critical_str) = durations_str.split_once(',').unwrap_or_else(|| { | ||
panic!( | ||
"Duration variable {} expected to have 2 numbers separated by comma, but got {}", | ||
env_var_name, durations_str | ||
) | ||
}); | ||
Comment on lines
+108
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this inverts the order of validation: now we first validate that the split works, and only then validate that they can be parsed as numbers. |
||
|
||
// Split string into 2 substrings by comma and try to parse numbers. | ||
let mut durations = durations_str.splitn(2, ',').map(|v| { | ||
let parse_u64 = |v| { | ||
u64::from_str(v).unwrap_or_else(|_| { | ||
panic!( | ||
"Duration value in variable {} is expected to be a number, but got {}", | ||
env_var_name, v | ||
) | ||
}) | ||
}); | ||
|
||
// Callback to be called if the environment variable has unexpected structure. | ||
let panic_on_incorrect_value = || { | ||
panic!( | ||
"Duration variable {} expected to have 2 numbers separated by comma, but got {}", | ||
env_var_name, durations_str | ||
); | ||
}; | ||
|
||
let (warn, critical) = ( | ||
durations.next().unwrap_or_else(panic_on_incorrect_value), | ||
durations.next().unwrap_or_else(panic_on_incorrect_value), | ||
); | ||
|
||
let warn = parse_u64(warn_str); | ||
let critical = parse_u64(critical_str); | ||
if warn > critical { | ||
panic!("Test execution warn time should be less or equal to the critical time"); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -397,12 +397,9 @@ impl Options { | |
matches | ||
.opt_strs("default-setting") | ||
.iter() | ||
.map(|s| { | ||
let mut kv = s.splitn(2, '='); | ||
// never panics because `splitn` always returns at least one element | ||
let k = kv.next().unwrap().to_string(); | ||
let v = kv.next().unwrap_or("true").to_string(); | ||
(k, v) | ||
.map(|s| match s.split_once('=') { | ||
None => (s.clone(), "true".to_string()), | ||
Some((k, v)) => (k.to_string(), v.to_string()), | ||
}) | ||
.collect(), | ||
]; | ||
|
@@ -707,11 +704,9 @@ fn parse_extern_html_roots( | |
) -> Result<BTreeMap<String, String>, &'static str> { | ||
let mut externs = BTreeMap::new(); | ||
for arg in &matches.opt_strs("extern-html-root-url") { | ||
let mut parts = arg.splitn(2, '='); | ||
let name = parts.next().ok_or("--extern-html-root-url must not be empty")?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
let url = parts.next().ok_or("--extern-html-root-url must be of the form name=url")?; | ||
let (name, url) = | ||
arg.split_once('=').ok_or("--extern-html-root-url must be of the form name=url")?; | ||
externs.insert(name.to_string(), url.to_string()); | ||
} | ||
|
||
Ok(externs) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original match was considering more than necessary.
setting.next()
was alwaysSome()
. Only thevalue
could beNone
.I kept
value
modeled as anOption
to avoid needing to change the related code likebool_option_val
.