From dd578926c3129c342988da4d5a07392e9e6d1bfd Mon Sep 17 00:00:00 2001 From: Darren Schroeder <343840+fdncred@users.noreply.github.com> Date: Wed, 28 Sep 2022 17:07:50 -0500 Subject: [PATCH] add some float operations with filesize (#6618) * add some float operations with filesize * more changes * update return values on filesize-filesize, duration-duration * missed filesize in floordiv * missed float * duration --- crates/nu-command/tests/commands/math/mod.rs | 60 ++++++++++ .../nu-command/tests/commands/run_external.rs | 1 + crates/nu-parser/src/type_check.rs | 19 +-- crates/nu-protocol/src/value/mod.rs | 110 ++++++++++++++++-- 4 files changed, 171 insertions(+), 19 deletions(-) diff --git a/crates/nu-command/tests/commands/math/mod.rs b/crates/nu-command/tests/commands/math/mod.rs index 0e48c32a71..76f71c700a 100644 --- a/crates/nu-command/tests/commands/math/mod.rs +++ b/crates/nu-command/tests/commands/math/mod.rs @@ -282,6 +282,66 @@ fn modulo() { assert_eq!(actual.out, "1"); } +#[test] +fn unit_multiplication_math() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + 1mb * 2 + "# + )); + + assert_eq!(actual.out, "1.9 MiB"); +} + +#[test] +fn unit_multiplication_float_math() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + 1mb * 1.2 + "# + )); + + assert_eq!(actual.out, "1.1 MiB"); +} + +#[test] +fn unit_float_floor_division_math() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + 1mb // 3.0 + "# + )); + + assert_eq!(actual.out, "325.5 KiB"); +} + +#[test] +fn unit_division_math() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + 1mb / 4 + "# + )); + + assert_eq!(actual.out, "244.1 KiB"); +} + +#[test] +fn unit_float_division_math() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + 1mb / 3.1 + "# + )); + + assert_eq!(actual.out, "315.0 KiB"); +} + #[test] fn duration_math() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/run_external.rs b/crates/nu-command/tests/commands/run_external.rs index d92573426e..94798e32bd 100644 --- a/crates/nu-command/tests/commands/run_external.rs +++ b/crates/nu-command/tests/commands/run_external.rs @@ -186,6 +186,7 @@ fn external_arg_with_variable_name() { }) } +#[cfg(not(windows))] #[test] fn external_command_escape_args() { Playground::setup("external failed command with semicolon", |dirs, _| { diff --git a/crates/nu-parser/src/type_check.rs b/crates/nu-parser/src/type_check.rs index ac2a937f68..eaba67220f 100644 --- a/crates/nu-parser/src/type_check.rs +++ b/crates/nu-parser/src/type_check.rs @@ -101,11 +101,14 @@ pub fn math_result_type( (Type::Float, Type::Int) => (Type::Float, None), (Type::Int, Type::Float) => (Type::Float, None), (Type::Float, Type::Float) => (Type::Float, None), - (Type::Filesize, Type::Int) => (Type::Filesize, None), (Type::Int, Type::Filesize) => (Type::Filesize, None), - (Type::Duration, Type::Int) => (Type::Filesize, None), - (Type::Int, Type::Duration) => (Type::Filesize, None), + (Type::Filesize, Type::Float) => (Type::Filesize, None), + (Type::Float, Type::Filesize) => (Type::Filesize, None), + (Type::Duration, Type::Int) => (Type::Duration, None), + (Type::Int, Type::Duration) => (Type::Duration, None), + (Type::Duration, Type::Float) => (Type::Duration, None), + (Type::Float, Type::Duration) => (Type::Duration, None), (Type::Custom(a), Type::Custom(b)) if a == b => (Type::Custom(a.to_string()), None), (Type::Custom(a), _) => (Type::Custom(a.to_string()), None), @@ -157,10 +160,11 @@ pub fn math_result_type( (Type::Int, Type::Float) => (Type::Float, None), (Type::Float, Type::Float) => (Type::Float, None), (Type::Filesize, Type::Filesize) => (Type::Float, None), - (Type::Duration, Type::Duration) => (Type::Float, None), - (Type::Filesize, Type::Int) => (Type::Filesize, None), + (Type::Filesize, Type::Float) => (Type::Filesize, None), + (Type::Duration, Type::Duration) => (Type::Float, None), (Type::Duration, Type::Int) => (Type::Duration, None), + (Type::Duration, Type::Float) => (Type::Duration, None), (Type::Custom(a), Type::Custom(b)) if a == b => (Type::Custom(a.to_string()), None), (Type::Custom(a), _) => (Type::Custom(a.to_string()), None), @@ -187,10 +191,11 @@ pub fn math_result_type( (Type::Int, Type::Float) => (Type::Int, None), (Type::Float, Type::Float) => (Type::Int, None), (Type::Filesize, Type::Filesize) => (Type::Int, None), - (Type::Duration, Type::Duration) => (Type::Int, None), - (Type::Filesize, Type::Int) => (Type::Filesize, None), + (Type::Filesize, Type::Float) => (Type::Filesize, None), + (Type::Duration, Type::Duration) => (Type::Int, None), (Type::Duration, Type::Int) => (Type::Duration, None), + (Type::Duration, Type::Float) => (Type::Duration, None), (Type::Any, _) => (Type::Any, None), (_, Type::Any) => (Type::Any, None), diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 4d9762ba9f..145a88a0df 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -1676,6 +1676,7 @@ impl Value { }), } } + pub fn sub(&self, op: Span, rhs: &Value, span: Span) -> Result { match (self, rhs) { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { @@ -1754,6 +1755,7 @@ impl Value { }), } } + pub fn mul(&self, op: Span, rhs: &Value, span: Span) -> Result { match (self, rhs) { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { @@ -1790,6 +1792,18 @@ impl Value { span, }) } + (Value::Float { val: lhs, .. }, Value::Filesize { val: rhs, .. }) => { + Ok(Value::Filesize { + val: (*lhs * *rhs as f64) as i64, + span, + }) + } + (Value::Filesize { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + Ok(Value::Filesize { + val: (*lhs as f64 * *rhs) as i64, + span, + }) + } (Value::Int { val: lhs, .. }, Value::Duration { val: rhs, .. }) => { Ok(Value::Duration { val: *lhs * *rhs, @@ -1802,6 +1816,18 @@ impl Value { span, }) } + (Value::Duration { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + Ok(Value::Duration { + val: (*lhs as f64 * *rhs) as i64, + span, + }) + } + (Value::Float { val: lhs, .. }, Value::Duration { val: rhs, .. }) => { + Ok(Value::Duration { + val: (*lhs * *rhs as f64) as i64, + span, + }) + } (Value::CustomValue { val: lhs, span }, rhs) => { lhs.operation(*span, Operator::Multiply, op, rhs) } @@ -1815,6 +1841,7 @@ impl Value { }), } } + pub fn div(&self, op: Span, rhs: &Value, span: Span) -> Result { match (self, rhs) { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { @@ -1881,6 +1908,26 @@ impl Value { Err(ShellError::DivisionByZero(op)) } } + (Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + if *rhs != 0 { + Ok(Value::Filesize { + val: ((*lhs as f64) / (*rhs as f64)) as i64, + span, + }) + } else { + Err(ShellError::DivisionByZero(op)) + } + } + (Value::Filesize { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + if *rhs != 0.0 { + Ok(Value::Filesize { + val: (*lhs as f64 / rhs) as i64, + span, + }) + } else { + Err(ShellError::DivisionByZero(op)) + } + } (Value::Duration { val: lhs, .. }, Value::Duration { val: rhs, .. }) => { if *rhs != 0 { if lhs % rhs == 0 { @@ -1898,20 +1945,20 @@ impl Value { Err(ShellError::DivisionByZero(op)) } } - (Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + (Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => { if *rhs != 0 { - Ok(Value::Filesize { - val: lhs / rhs, + Ok(Value::Duration { + val: ((*lhs as f64) / (*rhs as f64)) as i64, span, }) } else { Err(ShellError::DivisionByZero(op)) } } - (Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - if *rhs != 0 { + (Value::Duration { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + if *rhs != 0.0 { Ok(Value::Duration { - val: lhs / rhs, + val: ((*lhs as f64) / rhs) as i64, span, }) } else { @@ -1931,6 +1978,7 @@ impl Value { }), } } + pub fn floor_div(&self, op: Span, rhs: &Value, span: Span) -> Result { match (self, rhs) { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { @@ -1998,6 +2046,32 @@ impl Value { Err(ShellError::DivisionByZero(op)) } } + (Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + if *rhs != 0 { + Ok(Value::Filesize { + val: ((*lhs as f64) / (*rhs as f64)) + .max(std::i64::MIN as f64) + .min(std::i64::MAX as f64) + .floor() as i64, + span, + }) + } else { + Err(ShellError::DivisionByZero(op)) + } + } + (Value::Filesize { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + if *rhs != 0.0 { + Ok(Value::Filesize { + val: (*lhs as f64 / *rhs) + .max(std::i64::MIN as f64) + .min(std::i64::MAX as f64) + .floor() as i64, + span, + }) + } else { + Err(ShellError::DivisionByZero(op)) + } + } (Value::Duration { val: lhs, .. }, Value::Duration { val: rhs, .. }) => { if *rhs != 0 { Ok(Value::Int { @@ -2011,20 +2085,26 @@ impl Value { Err(ShellError::DivisionByZero(op)) } } - (Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + (Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => { if *rhs != 0 { - Ok(Value::Filesize { - val: lhs / rhs, + Ok(Value::Duration { + val: (*lhs as f64 / *rhs as f64) + .max(std::i64::MIN as f64) + .min(std::i64::MAX as f64) + .floor() as i64, span, }) } else { Err(ShellError::DivisionByZero(op)) } } - (Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - if *rhs != 0 { + (Value::Duration { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + if *rhs != 0.0 { Ok(Value::Duration { - val: lhs / rhs, + val: (*lhs as f64 / *rhs) + .max(std::i64::MIN as f64) + .min(std::i64::MAX as f64) + .floor() as i64, span, }) } else { @@ -2044,6 +2124,7 @@ impl Value { }), } } + pub fn lt(&self, op: Span, rhs: &Value, span: Span) -> Result { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { return lhs.operation(*span, Operator::LessThan, op, rhs); @@ -2070,6 +2151,7 @@ impl Value { }), } } + pub fn lte(&self, op: Span, rhs: &Value, span: Span) -> Result { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { return lhs.operation(*span, Operator::LessThanOrEqual, op, rhs); @@ -2096,6 +2178,7 @@ impl Value { }), } } + pub fn gt(&self, op: Span, rhs: &Value, span: Span) -> Result { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { return lhs.operation(*span, Operator::GreaterThan, op, rhs); @@ -2122,6 +2205,7 @@ impl Value { }), } } + pub fn gte(&self, op: Span, rhs: &Value, span: Span) -> Result { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { return lhs.operation(*span, Operator::GreaterThanOrEqual, op, rhs); @@ -2148,6 +2232,7 @@ impl Value { }), } } + pub fn eq(&self, op: Span, rhs: &Value, span: Span) -> Result { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { return lhs.operation(*span, Operator::Equal, op, rhs); @@ -2172,6 +2257,7 @@ impl Value { }, } } + pub fn ne(&self, op: Span, rhs: &Value, span: Span) -> Result { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { return lhs.operation(*span, Operator::NotEqual, op, rhs);