Skip to content

Commit

Permalink
Add Value::coerce_str (nushell#11885)
Browse files Browse the repository at this point in the history
# Description
Following nushell#11851, this PR adds one final conversion function for
`Value`. `Value::coerce_str` takes a `&Value` and converts it to a
`Cow<str>`, creating an owned `String` for types that needed converting.
Otherwise, it returns a borrowed `str` for `String` and `Binary`
`Value`s which avoids a clone/allocation. Where possible, `coerce_str`
and `coerce_into_string` should be used instead of `coerce_string`,
since `coerce_string` always allocates a new `String`.
  • Loading branch information
IanManske authored and dmatos2012 committed Feb 20, 2024
1 parent cf15799 commit d1e8ded
Show file tree
Hide file tree
Showing 34 changed files with 113 additions and 81 deletions.
4 changes: 2 additions & 2 deletions crates/nu-cli/src/completions/command_completions.rs
Expand Up @@ -43,9 +43,9 @@ impl CommandCompletion {
if let Some(paths) = paths {
if let Ok(paths) = paths.as_list() {
for path in paths {
let path = path.coerce_string().unwrap_or_default();
let path = path.coerce_str().unwrap_or_default();

if let Ok(mut contents) = std::fs::read_dir(path) {
if let Ok(mut contents) = std::fs::read_dir(path.as_ref()) {
while let Some(Ok(item)) = contents.next() {
if self.engine_state.config.max_external_completion_results
> executables.len() as i64
Expand Down
4 changes: 2 additions & 2 deletions crates/nu-cli/src/eval_cmds.rs
Expand Up @@ -28,7 +28,7 @@ pub fn evaluate_commands(
let (block, delta) = {
if let Some(ref t_mode) = table_mode {
let mut config = engine_state.get_config().clone();
config.table_mode = t_mode.coerce_string()?.parse().unwrap_or_default();
config.table_mode = t_mode.coerce_str()?.parse().unwrap_or_default();
engine_state.set_config(config);
}

Expand Down Expand Up @@ -59,7 +59,7 @@ pub fn evaluate_commands(
Ok(pipeline_data) => {
let mut config = engine_state.get_config().clone();
if let Some(t_mode) = table_mode {
config.table_mode = t_mode.coerce_string()?.parse().unwrap_or_default();
config.table_mode = t_mode.coerce_str()?.parse().unwrap_or_default();
}
crate::eval_file::print_table_or_error(engine_state, stack, pipeline_data, &mut config)
}
Expand Down
25 changes: 11 additions & 14 deletions crates/nu-cli/src/reedline_config.rs
Expand Up @@ -459,21 +459,18 @@ pub(crate) fn add_ide_menu(
};

ide_menu = match extract_value("description_mode", val, span) {
Ok(description_mode) => {
let description_mode_str = description_mode.coerce_string()?;
match description_mode_str.as_str() {
"left" => ide_menu.with_description_mode(DescriptionMode::Left),
"right" => ide_menu.with_description_mode(DescriptionMode::Right),
"prefer_right" => ide_menu.with_description_mode(DescriptionMode::PreferRight),
_ => {
return Err(ShellError::UnsupportedConfigValue {
expected: "\"left\", \"right\" or \"prefer_right\"".to_string(),
value: description_mode.to_abbreviated_string(config),
span: description_mode.span(),
});
}
Ok(description_mode) => match description_mode.coerce_str()?.as_ref() {
"left" => ide_menu.with_description_mode(DescriptionMode::Left),
"right" => ide_menu.with_description_mode(DescriptionMode::Right),
"prefer_right" => ide_menu.with_description_mode(DescriptionMode::PreferRight),
_ => {
return Err(ShellError::UnsupportedConfigValue {
expected: "\"left\", \"right\" or \"prefer_right\"".to_string(),
value: description_mode.to_abbreviated_string(config),
span: description_mode.span(),
});
}
}
},
Err(_) => ide_menu,
};

Expand Down
2 changes: 1 addition & 1 deletion crates/nu-color-config/src/matching_brackets_style.rs
Expand Up @@ -6,7 +6,7 @@ pub fn get_matching_brackets_style(default_style: Style, conf: &Config) -> Style
const MATCHING_BRACKETS_CONFIG_KEY: &str = "shape_matching_brackets";

match conf.color_config.get(MATCHING_BRACKETS_CONFIG_KEY) {
Some(int_color) => match int_color.coerce_string() {
Some(int_color) => match int_color.coerce_str() {
Ok(int_color) => merge_styles(default_style, lookup_ansi_color_style(&int_color)),
Err(_) => default_style,
},
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/conversions/into/datetime.rs
Expand Up @@ -262,7 +262,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
// Let's try dtparse first
if matches!(input, Value::String { .. }) && dateformat.is_none() {
let span = input.span();
if let Ok(input_val) = input.coerce_string() {
if let Ok(input_val) = input.coerce_str() {
match parse_date_from_string(&input_val, span) {
Ok(date) => return Value::date(date, span),
Err(_) => {
Expand Down
4 changes: 2 additions & 2 deletions crates/nu-command/src/conversions/into/value.rs
Expand Up @@ -142,7 +142,7 @@ impl Iterator for UpdateCellIterator {
// for a particular datatype. If it does, it will convert the cell to that datatype.
fn process_cell(val: Value, display_as_filesizes: bool, span: Span) -> Result<Value, ShellError> {
// step 1: convert value to string
let val_str = val.coerce_string().unwrap_or_default();
let val_str = val.coerce_str().unwrap_or_default();

// step 2: bounce string up against regexes
if BOOLEAN_RE.is_match(&val_str) {
Expand Down Expand Up @@ -189,7 +189,7 @@ fn process_cell(val: Value, display_as_filesizes: bool, span: Span) -> Result<Va
Ok(Value::int(ival, span))
}
} else if INTEGER_WITH_DELIMS_RE.is_match(&val_str) {
let mut val_str = val_str;
let mut val_str = val_str.into_owned();
val_str.retain(|x| !['_', ','].contains(&x));

let ival = val_str
Expand Down
4 changes: 1 addition & 3 deletions crates/nu-command/src/filters/move_.rs
Expand Up @@ -222,9 +222,7 @@ fn move_record_columns(

// Find indices of columns to be moved
for column in columns.iter() {
let column_str = column.coerce_string()?;

if let Some(idx) = record.index_of(&column_str) {
if let Some(idx) = record.index_of(&column.coerce_str()?) {
column_idx.push(idx);
} else {
return Err(ShellError::GenericError {
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/filters/sort.rs
Expand Up @@ -288,7 +288,7 @@ pub fn sort(
.unwrap_or(Ordering::Equal)
}
} else if natural {
match (a.coerce_string(), b.coerce_string()) {
match (a.coerce_str(), b.coerce_str()) {
(Ok(left), Ok(right)) => compare_str(left, right),
_ => Ordering::Equal,
}
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/filters/transpose.rs
Expand Up @@ -194,7 +194,7 @@ pub fn transpose(
match &i.get_data_by_key(desc) {
Some(x) => {
if let Ok(s) = x.coerce_string() {
headers.push(s.to_string());
headers.push(s);
} else {
return Err(ShellError::GenericError {
error: "Header row needs string headers".into(),
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/network/url/build_query.rs
Expand Up @@ -72,7 +72,7 @@ fn to_url(input: PipelineData, head: Span) -> Result<PipelineData, ShellError> {
for (k, v) in val {
match v.coerce_string() {
Ok(s) => {
row_vec.push((k.clone(), s.to_string()));
row_vec.push((k.clone(), s));
}
_ => {
return Err(ShellError::UnsupportedInput {
Expand Down
12 changes: 6 additions & 6 deletions crates/nu-command/src/path/join.rs
Expand Up @@ -262,29 +262,29 @@ fn merge_record(record: &Record, head: Span, span: Span) -> Result<PathBuf, Shel

#[cfg(windows)]
if let Some(val) = record.get("prefix") {
let p = val.coerce_string()?;
let p = val.coerce_str()?;
if !p.is_empty() {
result.push(p);
result.push(p.as_ref());
}
}

if let Some(val) = record.get("parent") {
let p = val.coerce_string()?;
let p = val.coerce_str()?;
if !p.is_empty() {
result.push(p);
result.push(p.as_ref());
}
}

let mut basename = String::new();
if let Some(val) = record.get("stem") {
let p = val.coerce_string()?;
let p = val.coerce_str()?;
if !p.is_empty() {
basename.push_str(&p);
}
}

if let Some(val) = record.get("extension") {
let p = val.coerce_string()?;
let p = val.coerce_str()?;
if !p.is_empty() {
basename.push('.');
basename.push_str(&p);
Expand Down
4 changes: 2 additions & 2 deletions crates/nu-command/src/platform/ansi/ansi_.rs
Expand Up @@ -738,9 +738,9 @@ fn heavy_lifting(code: Value, escape: bool, osc: bool, call: &Call) -> Result<St
});
}
let code_string = if param_is_string {
code.coerce_string().expect("error getting code as string")
code.coerce_str().expect("error getting code as string")
} else {
"".to_string()
"".into()
};
let param_is_valid_string = param_is_string && !code_string.is_empty();
if (escape || osc) && (param_is_valid_string) {
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/sort_utils.rs
Expand Up @@ -150,7 +150,7 @@ pub fn sort(
.unwrap_or(Ordering::Equal)
}
} else if natural {
match (a.coerce_string(), b.coerce_string()) {
match (a.coerce_str(), b.coerce_str()) {
(Ok(left), Ok(right)) => compare_str(left, right),
_ => Ordering::Equal,
}
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/stor/create.rs
Expand Up @@ -89,7 +89,7 @@ fn process(
new_table_name
);
for (column_name, column_datatype) in record {
match column_datatype.coerce_string()?.as_str() {
match column_datatype.coerce_str()?.as_ref() {
"int" => {
create_stmt.push_str(&format!("{} INTEGER, ", column_name));
}
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/strings/detect_columns.rs
Expand Up @@ -226,7 +226,7 @@ fn detect_columns(
.iter()
.take(end_index)
.skip(start_index)
.map(|v| v.coerce_string().unwrap_or_default())
.map(|v| v.coerce_str().unwrap_or_default())
.join(" ");
let binding = Value::string(combined, Span::unknown());
let last_seg = vals.split_off(end_index);
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/strings/split/chars.rs
Expand Up @@ -124,7 +124,7 @@ fn split_chars_helper(v: &Value, name: Span, graphemes: bool) -> Value {
Value::Error { error, .. } => Value::error(*error.clone(), span),
v => {
let v_span = v.span();
if let Ok(s) = v.coerce_string() {
if let Ok(s) = v.coerce_str() {
Value::list(
if graphemes {
s.graphemes(true)
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/strings/split/column.rs
Expand Up @@ -148,7 +148,7 @@ fn split_column_helper(
collapse_empty: bool,
head: Span,
) -> Vec<Value> {
if let Ok(s) = v.coerce_string() {
if let Ok(s) = v.coerce_str() {
let split_result: Vec<_> = separator
.split(&s)
.filter(|x| !(collapse_empty && x.is_empty()))
Expand Down
4 changes: 2 additions & 2 deletions crates/nu-command/src/strings/split/list.rs
Expand Up @@ -160,7 +160,7 @@ enum Matcher {
impl Matcher {
pub fn new(regex: bool, lhs: Value) -> Result<Self, ShellError> {
if regex {
Ok(Matcher::Regex(Regex::new(&lhs.coerce_string()?).map_err(
Ok(Matcher::Regex(Regex::new(&lhs.coerce_str()?).map_err(
|e| ShellError::GenericError {
error: "Error with regular expression".into(),
msg: e.to_string(),
Expand All @@ -180,7 +180,7 @@ impl Matcher {
pub fn compare(&self, rhs: &Value) -> Result<bool, ShellError> {
Ok(match self {
Matcher::Regex(regex) => {
if let Ok(rhs_str) = rhs.coerce_string() {
if let Ok(rhs_str) = rhs.coerce_str() {
regex.is_match(&rhs_str)
} else {
false
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/strings/split/row.rs
Expand Up @@ -152,7 +152,7 @@ fn split_row_helper(v: &Value, regex: &Regex, max_split: Option<usize>, name: Sp
v => {
let v_span = v.span();

if let Ok(s) = v.coerce_string() {
if let Ok(s) = v.coerce_str() {
match max_split {
Some(max_split) => regex
.splitn(&s, max_split)
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-command/src/strings/split/words.rs
Expand Up @@ -158,7 +158,7 @@ fn split_words_helper(v: &Value, word_length: Option<usize>, span: Span, graphem
Value::Error { error, .. } => Value::error(*error.clone(), v_span),
v => {
let v_span = v.span();
if let Ok(s) = v.coerce_string() {
if let Ok(s) = v.coerce_str() {
// let splits = s.unicode_words();
// let words = trim_to_words(s);
// let words: Vec<&str> = s.split_whitespace().collect();
Expand Down
4 changes: 2 additions & 2 deletions crates/nu-engine/src/env.rs
Expand Up @@ -110,10 +110,10 @@ pub fn env_to_string(
Value::List { vals, .. } => {
let paths = vals
.iter()
.map(|v| v.coerce_string())
.map(Value::coerce_str)
.collect::<Result<Vec<_>, _>>()?;

match std::env::join_paths(paths) {
match std::env::join_paths(paths.iter().map(AsRef::as_ref)) {
Ok(p) => Ok(p.to_string_lossy().to_string()),
Err(_) => Err(ShellError::EnvVarNotAString {
envvar_name: env_name.to_string(),
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-explore/src/pager/mod.rs
Expand Up @@ -1008,7 +1008,7 @@ fn cmd_input_key_event(buf: &mut CommandBuf, key: &KeyEvent) -> bool {
}

fn value_as_style(style: &mut nu_ansi_term::Style, value: &Value) -> bool {
match value.coerce_string() {
match value.coerce_str() {
Ok(s) => {
*style = lookup_ansi_color_style(&s);
true
Expand Down
6 changes: 3 additions & 3 deletions crates/nu-explore/src/views/record/mod.rs
Expand Up @@ -331,8 +331,8 @@ impl View for RecordView<'_> {
if let Some(hm) = cfg.config.get("table").and_then(create_map) {
self.theme = theme_from_config(&hm);

if let Some(orientation) = hm.get("orientation").and_then(|v| v.coerce_string().ok()) {
let orientation = match orientation.as_str() {
if let Some(orientation) = hm.get("orientation").and_then(|v| v.coerce_str().ok()) {
let orientation = match orientation.as_ref() {
"left" => Some(Orientation::Left),
"top" => Some(Orientation::Top),
_ => None,
Expand Down Expand Up @@ -859,7 +859,7 @@ fn config_get_bool(config: &ConfigMap, key: &str, default: bool) -> bool {
fn config_get_usize(config: &ConfigMap, key: &str, default: usize) -> usize {
config
.get(key)
.and_then(|v| v.coerce_string().ok())
.and_then(|v| v.coerce_str().ok())
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(default)
}
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-protocol/src/config/helper.rs
Expand Up @@ -15,7 +15,7 @@ pub(super) fn process_string_enum<T, E>(
E: Display,
{
let span = value.span();
if let Ok(v) = value.coerce_string() {
if let Ok(v) = value.coerce_str() {
match v.parse() {
Ok(format) => {
*config_point = format;
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-protocol/src/config/mod.rs
Expand Up @@ -539,7 +539,7 @@ impl Value {
process_bool_config(value, &mut errors, &mut config.filesize_metric);
}
"format" => {
if let Ok(v) = value.coerce_string() {
if let Ok(v) = value.coerce_str() {
config.filesize_format = v.to_lowercase();
} else {
report_invalid_value("should be a string", span, &mut errors);
Expand Down
2 changes: 1 addition & 1 deletion crates/nu-protocol/src/config/table.rs
Expand Up @@ -272,7 +272,7 @@ pub(super) fn try_parse_trim_strategy(
}

fn try_parse_trim_methodology(value: &Value) -> Option<TrimStrategy> {
if let Ok(value) = value.coerce_string() {
if let Ok(value) = value.coerce_str() {
match value.to_lowercase().as_str() {
"wrapping" => {
return Some(TrimStrategy::Wrap {
Expand Down

0 comments on commit d1e8ded

Please sign in to comment.