forked from extern/nushell
allow into duration
to take an integer amount of ns (#10286)
related to - https://discord.com/channels/601130461678272522/615329862395101194/1149717458786197524 # Description because `1_234 | into datetime` takes an integer number of `ns` and `1_234 | into filesize` takes an integer amount of bytes, i think `1_234 | into duration` should also be valid and see `1_234` as an integer amount of `ns` 😋 # User-Facing Changes ## before either ```nushell 1234 | into string | $in ++ "ns" | into duration ``` ```nushell 1234 | $"($in)ns" | into duration ``` or ```nushell 1234 * 1ns ``` and ```nushell > 1_234 | into duration Error: nu::parser::input_type_mismatch × Command does not support int input. ╭─[entry #2:1:1] 1 │ 1_234 | into duration · ──────┬────── · ╰── command doesn't support int input ╰──── ``` ## after ```nushell > 1_234 | into duration 1µs 234ns ``` # Tests + Formatting new example test ```rust Example { description: "Convert a number of ns to duration", example: "1_234_567 | into duration", result: Some(Value::duration(1_234_567, span)), } ``` # After Submitting
This commit is contained in:
parent
40eca52ed5
commit
17abbdf6e0
@ -19,6 +19,7 @@ impl Command for SubCommand {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("into duration")
|
Signature::build("into duration")
|
||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
|
(Type::Int, Type::Duration),
|
||||||
(Type::String, Type::Duration),
|
(Type::String, Type::Duration),
|
||||||
(Type::Duration, Type::Duration),
|
(Type::Duration, Type::Duration),
|
||||||
(Type::Table(vec![]), Type::Table(vec![])),
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
@ -26,6 +27,12 @@ impl Command for SubCommand {
|
|||||||
//(Type::Record(vec![]), Type::Record(vec![])),
|
//(Type::Record(vec![]), Type::Record(vec![])),
|
||||||
])
|
])
|
||||||
//.allow_variants_without_examples(true)
|
//.allow_variants_without_examples(true)
|
||||||
|
.named(
|
||||||
|
"unit",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Unit to convert number into (will have an effect only with integer input)",
|
||||||
|
Some('u'),
|
||||||
|
)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
SyntaxShape::CellPath,
|
SyntaxShape::CellPath,
|
||||||
@ -107,6 +114,16 @@ impl Command for SubCommand {
|
|||||||
example: "420sec | into duration",
|
example: "420sec | into duration",
|
||||||
result: Some(Value::duration(7 * 60 * NS_PER_SEC, span)),
|
result: Some(Value::duration(7 * 60 * NS_PER_SEC, span)),
|
||||||
},
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert a number of ns to duration",
|
||||||
|
example: "1_234_567 | into duration",
|
||||||
|
result: Some(Value::duration(1_234_567, span)),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert a number of an arbitraty unit to duration",
|
||||||
|
example: "1_234 | into duration --unit ms",
|
||||||
|
result: Some(Value::duration(1_234 * 1_000_000, span)),
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,15 +140,39 @@ fn into_duration(
|
|||||||
};
|
};
|
||||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
|
|
||||||
|
let unit = match call.get_flag::<String>(engine_state, stack, "unit")? {
|
||||||
|
Some(sep) => {
|
||||||
|
if ["ns", "us", "µs", "ms", "sec", "min", "hr", "day", "wk"]
|
||||||
|
.iter()
|
||||||
|
.any(|d| d == &sep)
|
||||||
|
{
|
||||||
|
sep
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::CantConvertToDuration {
|
||||||
|
details: sep,
|
||||||
|
dst_span: span,
|
||||||
|
src_span: span,
|
||||||
|
help: Some(
|
||||||
|
"supported units are ns, us/µs, ms, sec, min, hr, day, and wk".to_string(),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => "ns".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
input.map(
|
input.map(
|
||||||
move |v| {
|
move |v| {
|
||||||
if column_paths.is_empty() {
|
if column_paths.is_empty() {
|
||||||
action(&v, span)
|
action(&v, &unit.clone(), span)
|
||||||
} else {
|
} else {
|
||||||
|
let unitclone = &unit.clone();
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
for path in &column_paths {
|
for path in &column_paths {
|
||||||
let r =
|
let r = ret.update_cell_path(
|
||||||
ret.update_cell_path(&path.members, Box::new(move |old| action(old, span)));
|
&path.members,
|
||||||
|
Box::new(move |old| action(old, unitclone, span)),
|
||||||
|
);
|
||||||
if let Err(error) = r {
|
if let Err(error) = r {
|
||||||
return Value::error(error, span);
|
return Value::error(error, span);
|
||||||
}
|
}
|
||||||
@ -202,7 +243,7 @@ fn string_to_duration(s: &str, span: Span) -> Result<i64, ShellError> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action(input: &Value, span: Span) -> Value {
|
fn action(input: &Value, unit: &str, span: Span) -> Value {
|
||||||
let value_span = input.span();
|
let value_span = input.span();
|
||||||
match input {
|
match input {
|
||||||
Value::Duration { .. } => input.clone(),
|
Value::Duration { .. } => input.clone(),
|
||||||
@ -210,6 +251,20 @@ fn action(input: &Value, span: Span) -> Value {
|
|||||||
Ok(val) => Value::duration(val, span),
|
Ok(val) => Value::duration(val, span),
|
||||||
Err(error) => Value::error(error, span),
|
Err(error) => Value::error(error, span),
|
||||||
},
|
},
|
||||||
|
Value::Int { val, .. } => {
|
||||||
|
let ns = match unit {
|
||||||
|
"ns" => 1,
|
||||||
|
"us" | "µs" => 1_000,
|
||||||
|
"ms" => 1_000_000,
|
||||||
|
"sec" => NS_PER_SEC,
|
||||||
|
"min" => NS_PER_SEC * 60,
|
||||||
|
"hr" => NS_PER_SEC * 60 * 60,
|
||||||
|
"day" => NS_PER_SEC * 60 * 60 * 24,
|
||||||
|
"wk" => NS_PER_SEC * 60 * 60 * 24 * 7,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
Value::duration(*val * ns, span)
|
||||||
|
}
|
||||||
// Propagate errors by explicitly matching them before the final case.
|
// Propagate errors by explicitly matching them before the final case.
|
||||||
Value::Error { .. } => input.clone(),
|
Value::Error { .. } => input.clone(),
|
||||||
other => Value::error(
|
other => Value::error(
|
||||||
@ -253,7 +308,11 @@ mod test {
|
|||||||
#[case("14ns 3hr 17sec", 14 + 3 * 3600 * NS_PER_SEC + 17 * NS_PER_SEC)] // compound string with units in random order
|
#[case("14ns 3hr 17sec", 14 + 3 * 3600 * NS_PER_SEC + 17 * NS_PER_SEC)] // compound string with units in random order
|
||||||
|
|
||||||
fn turns_string_to_duration(#[case] phrase: &str, #[case] expected_duration_val: i64) {
|
fn turns_string_to_duration(#[case] phrase: &str, #[case] expected_duration_val: i64) {
|
||||||
let actual = action(&Value::test_string(phrase), Span::new(0, phrase.len()));
|
let actual = action(
|
||||||
|
&Value::test_string(phrase),
|
||||||
|
"ns",
|
||||||
|
Span::new(0, phrase.len()),
|
||||||
|
);
|
||||||
match actual {
|
match actual {
|
||||||
Value::Duration {
|
Value::Duration {
|
||||||
val: observed_val, ..
|
val: observed_val, ..
|
||||||
|
Loading…
Reference in New Issue
Block a user