Move filesize to use bigint (#2984)

* Move filesize to be bigint-sized

* Add tests and fix filesize display

* clippy
This commit is contained in:
Jonathan Turner 2021-01-30 11:35:18 +13:00 committed by GitHub
parent 7b4cbd7ce9
commit 44e088c6fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 227 additions and 148 deletions

View file

@ -173,6 +173,13 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
let output = format_leaf(&x).plain_string(100_000); let output = format_leaf(&x).plain_string(100_000);
out!("{}", output); out!("{}", output);
} }
Value {
value: UntaggedValue::Primitive(Primitive::Filesize(_)),
..
} => {
let output = format_leaf(&x).plain_string(100_000);
out!("{}", output);
}
Value { Value {
value: UntaggedValue::Primitive(Primitive::Date(d)), value: UntaggedValue::Primitive(Primitive::Date(d)),
.. ..

View file

@ -108,60 +108,70 @@ fn convert_bytes_to_string_using_format(
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
match bytes.value { match bytes.value {
Primitive(Filesize(b)) => { Primitive(Filesize(b)) => {
let byte = byte_unit::Byte::from_bytes(b as u128); if let Some(value) = b.to_u128() {
let value = match format.item().to_lowercase().as_str() { let byte = byte_unit::Byte::from_bytes(value);
"b" => Ok(UntaggedValue::string(b.to_formatted_string(&Locale::en))), let value = match format.item().to_lowercase().as_str() {
"kb" => Ok(UntaggedValue::string( "b" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::KB).to_string(), value.to_formatted_string(&Locale::en),
)), )),
"kib" => Ok(UntaggedValue::string( "kb" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::KiB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::KB).to_string(),
)), )),
"mb" => Ok(UntaggedValue::string( "kib" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::MB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::KiB).to_string(),
)), )),
"mib" => Ok(UntaggedValue::string( "mb" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::MiB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::MB).to_string(),
)), )),
"gb" => Ok(UntaggedValue::string( "mib" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::GB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::MiB).to_string(),
)), )),
"gib" => Ok(UntaggedValue::string( "gb" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::GiB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::GB).to_string(),
)), )),
"tb" => Ok(UntaggedValue::string( "gib" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::TB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::GiB).to_string(),
)), )),
"tib" => Ok(UntaggedValue::string( "tb" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::TiB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::TB).to_string(),
)), )),
"pb" => Ok(UntaggedValue::string( "tib" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::PB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::TiB).to_string(),
)), )),
"pib" => Ok(UntaggedValue::string( "pb" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::PiB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::PB).to_string(),
)), )),
"eb" => Ok(UntaggedValue::string( "pib" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::EB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::PiB).to_string(),
)), )),
"eib" => Ok(UntaggedValue::string( "eb" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::EiB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::EB).to_string(),
)), )),
"zb" => Ok(UntaggedValue::string( "eib" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::ZB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::EiB).to_string(),
)), )),
"zib" => Ok(UntaggedValue::string( "zb" => Ok(UntaggedValue::string(
byte.get_adjusted_unit(byte_unit::ByteUnit::ZiB).to_string(), byte.get_adjusted_unit(byte_unit::ByteUnit::ZB).to_string(),
)), )),
_ => Err(ShellError::labeled_error( "zib" => Ok(UntaggedValue::string(
format!("Invalid format code: {:}", format.item()), byte.get_adjusted_unit(byte_unit::ByteUnit::ZiB).to_string(),
"invalid format", )),
format.tag(), _ => Err(ShellError::labeled_error(
)), format!("Invalid format code: {:}", format.item()),
}; "invalid format",
match value { format.tag(),
Ok(b) => Ok(Value { value: b, ..bytes }), )),
Err(e) => Err(e), };
match value {
Ok(b) => Ok(Value { value: b, ..bytes }),
Err(e) => Err(e),
}
} else {
Err(ShellError::labeled_error(
"Value too large to fit in 128 bits",
"value too large to fit in format",
format.span(),
))
} }
} }
_ => Err(ShellError::labeled_error( _ => Err(ShellError::labeled_error(

View file

@ -59,12 +59,9 @@ impl WholeStreamCommand for SubCommand {
fn to_byte(value: &Value) -> Option<Value> { fn to_byte(value: &Value) -> Option<Value> {
match &value.value { match &value.value {
UntaggedValue::Primitive(Primitive::Int(num)) => Some( UntaggedValue::Primitive(Primitive::Int(num)) => {
UntaggedValue::Primitive(Primitive::Filesize(convert_number_to_u64(&Number::Int( Some(UntaggedValue::Primitive(Primitive::Filesize(num.clone())).into_untagged_value())
num.clone(), }
))))
.into_untagged_value(),
),
_ => None, _ => None,
} }
} }
@ -95,7 +92,7 @@ pub fn average(values: &[Value], name: &Tag) -> Result<Value, ShellError> {
Value { Value {
value: UntaggedValue::Primitive(Primitive::Filesize(num)), value: UntaggedValue::Primitive(Primitive::Filesize(num)),
.. ..
} => UntaggedValue::int(*num as usize).into_untagged_value(), } => UntaggedValue::int(num.clone()).into_untagged_value(),
other => other.clone(), other => other.clone(),
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
@ -116,7 +113,7 @@ pub fn average(values: &[Value], name: &Tag) -> Result<Value, ShellError> {
value: UntaggedValue::Primitive(Primitive::Filesize(num)), value: UntaggedValue::Primitive(Primitive::Filesize(num)),
.. ..
} => { } => {
let left = UntaggedValue::from(Primitive::Int(num.into())); let left = UntaggedValue::from(Primitive::Int(num));
let result = nu_data::value::compute_values(Operator::Divide, &left, &total_rows); let result = nu_data::value::compute_values(Operator::Divide, &left, &total_rows);
match result { match result {

View file

@ -137,7 +137,7 @@ fn compute_average(values: &[Value], name: impl Into<Tag>) -> Result<Value, Shel
value: UntaggedValue::Primitive(Primitive::Filesize(num)), value: UntaggedValue::Primitive(Primitive::Filesize(num)),
.. ..
} => { } => {
let left = UntaggedValue::from(Primitive::Int(num.into())); let left = UntaggedValue::from(Primitive::Int(num));
let result = nu_data::value::compute_values(Operator::Divide, &left, &total_rows); let result = nu_data::value::compute_values(Operator::Divide, &left, &total_rows);
match result { match result {

View file

@ -3,10 +3,7 @@ use crate::commands::math::utils::run_with_function;
use crate::prelude::*; use crate::prelude::*;
use nu_engine::WholeStreamCommand; use nu_engine::WholeStreamCommand;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ use nu_protocol::{Primitive, Signature, UntaggedValue, Value};
hir::{convert_number_to_u64, Number},
Primitive, Signature, UntaggedValue, Value,
};
pub struct SubCommand; pub struct SubCommand;
@ -51,12 +48,9 @@ impl WholeStreamCommand for SubCommand {
fn to_byte(value: &Value) -> Option<Value> { fn to_byte(value: &Value) -> Option<Value> {
match &value.value { match &value.value {
UntaggedValue::Primitive(Primitive::Int(num)) => Some( UntaggedValue::Primitive(Primitive::Int(num)) => {
UntaggedValue::Primitive(Primitive::Filesize(convert_number_to_u64(&Number::Int( Some(UntaggedValue::Primitive(Primitive::Filesize(num.clone())).into_untagged_value())
num.clone(), }
))))
.into_untagged_value(),
),
_ => None, _ => None,
} }
} }
@ -78,7 +72,7 @@ pub fn product(values: &[Value], name: &Tag) -> Result<Value, ShellError> {
Value { Value {
value: UntaggedValue::Primitive(Primitive::Filesize(num)), value: UntaggedValue::Primitive(Primitive::Filesize(num)),
.. ..
} => UntaggedValue::int(*num as usize).into_untagged_value(), } => UntaggedValue::int(num.clone()).into_untagged_value(),
other => other.clone(), other => other.clone(),
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),

View file

@ -4,10 +4,7 @@ use crate::prelude::*;
use nu_engine::WholeStreamCommand; use nu_engine::WholeStreamCommand;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ use nu_protocol::{Primitive, Signature, UntaggedValue, Value};
hir::{convert_number_to_u64, Number},
Primitive, Signature, UntaggedValue, Value,
};
pub struct SubCommand; pub struct SubCommand;
@ -59,12 +56,9 @@ impl WholeStreamCommand for SubCommand {
fn to_byte(value: &Value) -> Option<Value> { fn to_byte(value: &Value) -> Option<Value> {
match &value.value { match &value.value {
UntaggedValue::Primitive(Primitive::Int(num)) => Some( UntaggedValue::Primitive(Primitive::Int(num)) => {
UntaggedValue::Primitive(Primitive::Filesize(convert_number_to_u64(&Number::Int( Some(UntaggedValue::Primitive(Primitive::Filesize(num.clone())).into_untagged_value())
num.clone(), }
))))
.into_untagged_value(),
),
_ => None, _ => None,
} }
} }
@ -90,7 +84,7 @@ pub fn summation(values: &[Value], name: &Tag) -> Result<Value, ShellError> {
Value { Value {
value: UntaggedValue::Primitive(Primitive::Filesize(num)), value: UntaggedValue::Primitive(Primitive::Filesize(num)),
.. ..
} => UntaggedValue::int(*num as usize).into_untagged_value(), } => UntaggedValue::int(num.clone()).into_untagged_value(),
other => other.clone(), other => other.clone(),
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),

View file

@ -130,7 +130,7 @@ fn sum_of_squares(values: &[Value], name: &Tag) -> Result<Value, ShellError> {
value: UntaggedValue::Primitive(Primitive::Filesize(num)), value: UntaggedValue::Primitive(Primitive::Filesize(num)),
.. ..
} => { } => {
UntaggedValue::from(Primitive::Int(num.clone().into())) UntaggedValue::from(Primitive::Int(num.clone()))
}, },
Value { Value {
value: UntaggedValue::Primitive(num), value: UntaggedValue::Primitive(num),

View file

@ -116,7 +116,7 @@ pub fn clone_tagged_value(v: &Value) -> Value {
UntaggedValue::Primitive(Primitive::FilePath(x.clone())) UntaggedValue::Primitive(Primitive::FilePath(x.clone()))
} }
UntaggedValue::Primitive(Primitive::Filesize(b)) => { UntaggedValue::Primitive(Primitive::Filesize(b)) => {
UntaggedValue::Primitive(Primitive::Filesize(*b)) UntaggedValue::Primitive(Primitive::Filesize(b.clone()))
} }
UntaggedValue::Primitive(Primitive::Date(d)) => { UntaggedValue::Primitive(Primitive::Date(d)) => {
UntaggedValue::Primitive(Primitive::Date(*d)) UntaggedValue::Primitive(Primitive::Date(*d))

View file

@ -40,7 +40,17 @@ impl WholeStreamCommand for ToTOML {
fn helper(v: &Value) -> Result<toml::Value, ShellError> { fn helper(v: &Value) -> Result<toml::Value, ShellError> {
Ok(match &v.value { Ok(match &v.value {
UntaggedValue::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b), UntaggedValue::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b),
UntaggedValue::Primitive(Primitive::Filesize(b)) => toml::Value::Integer(*b as i64), UntaggedValue::Primitive(Primitive::Filesize(b)) => {
if let Some(value) = b.to_i64() {
toml::Value::Integer(value)
} else {
return Err(ShellError::labeled_error(
"Value too large to write to toml",
"value too large for toml",
v.tag.span,
));
}
}
UntaggedValue::Primitive(Primitive::Duration(i)) => toml::Value::String(i.to_string()), UntaggedValue::Primitive(Primitive::Duration(i)) => toml::Value::String(i.to_string()),
UntaggedValue::Primitive(Primitive::Date(d)) => toml::Value::String(d.to_string()), UntaggedValue::Primitive(Primitive::Date(d)) => toml::Value::String(d.to_string()),
UntaggedValue::Primitive(Primitive::EndOfStream) => { UntaggedValue::Primitive(Primitive::EndOfStream) => {

View file

@ -129,20 +129,18 @@ pub fn coerce_compare_primitive(
(Int(left), Decimal(right)) => { (Int(left), Decimal(right)) => {
CompareValues::Decimals(BigDecimal::zero() + left, right.clone()) CompareValues::Decimals(BigDecimal::zero() + left, right.clone())
} }
(Int(left), Filesize(right)) => CompareValues::Ints(left.clone(), BigInt::from(*right)), (Int(left), Filesize(right)) => CompareValues::Ints(left.clone(), right.clone()),
(Decimal(left), Decimal(right)) => CompareValues::Decimals(left.clone(), right.clone()), (Decimal(left), Decimal(right)) => CompareValues::Decimals(left.clone(), right.clone()),
(Decimal(left), Int(right)) => { (Decimal(left), Int(right)) => {
CompareValues::Decimals(left.clone(), BigDecimal::zero() + right) CompareValues::Decimals(left.clone(), BigDecimal::zero() + right)
} }
(Decimal(left), Filesize(right)) => { (Decimal(left), Filesize(right)) => {
CompareValues::Decimals(left.clone(), BigDecimal::from(*right)) CompareValues::Decimals(left.clone(), BigDecimal::from(right.clone()))
} }
(Filesize(left), Filesize(right)) => { (Filesize(left), Filesize(right)) => CompareValues::Ints(left.clone(), right.clone()),
CompareValues::Ints(BigInt::from(*left), BigInt::from(*right)) (Filesize(left), Int(right)) => CompareValues::Ints(left.clone(), right.clone()),
}
(Filesize(left), Int(right)) => CompareValues::Ints(BigInt::from(*left), right.clone()),
(Filesize(left), Decimal(right)) => { (Filesize(left), Decimal(right)) => {
CompareValues::Decimals(BigDecimal::from(*left), right.clone()) CompareValues::Decimals(BigDecimal::from(left.clone()), right.clone())
} }
(Nothing, Nothing) => CompareValues::Booleans(true, true), (Nothing, Nothing) => CompareValues::Booleans(true, true),
(String(left), String(right)) => CompareValues::String(left.clone(), right.clone()), (String(left), String(right)) => CompareValues::String(left.clone(), right.clone()),

View file

@ -24,7 +24,7 @@ pub enum InlineShape {
Int(BigInt), Int(BigInt),
Decimal(BigDecimal), Decimal(BigDecimal),
Range(Box<InlineRange>), Range(Box<InlineRange>),
Bytesize(u64), Bytesize(BigInt),
String(String), String(String),
Line(String), Line(String),
ColumnPath(ColumnPath), ColumnPath(ColumnPath),
@ -68,7 +68,7 @@ impl InlineShape {
})) }))
} }
Primitive::Decimal(decimal) => InlineShape::Decimal(decimal.clone()), Primitive::Decimal(decimal) => InlineShape::Decimal(decimal.clone()),
Primitive::Filesize(bytesize) => InlineShape::Bytesize(*bytesize), Primitive::Filesize(bytesize) => InlineShape::Bytesize(bytesize.clone()),
Primitive::String(string) => InlineShape::String(string.clone()), Primitive::String(string) => InlineShape::String(string.clone()),
Primitive::ColumnPath(path) => InlineShape::ColumnPath(path.clone()), Primitive::ColumnPath(path) => InlineShape::ColumnPath(path.clone()),
Primitive::GlobPattern(pattern) => InlineShape::GlobPattern(pattern.clone()), Primitive::GlobPattern(pattern) => InlineShape::GlobPattern(pattern.clone()),
@ -128,7 +128,9 @@ impl InlineShape {
} }
} }
pub fn format_bytes(bytesize: &u64) -> (DbgDocBldr, String) { pub fn format_bytes(bytesize: &BigInt) -> (DbgDocBldr, String) {
use bigdecimal::ToPrimitive;
// get the config value, if it doesn't exist make it 'auto' so it works how it originally did // get the config value, if it doesn't exist make it 'auto' so it works how it originally did
let filesize_format_var = crate::config::config(Tag::unknown()) let filesize_format_var = crate::config::config(Tag::unknown())
.expect("unable to get the config.toml file") .expect("unable to get the config.toml file")
@ -155,32 +157,41 @@ impl InlineShape {
_ => (byte_unit::ByteUnit::B, "auto"), _ => (byte_unit::ByteUnit::B, "auto"),
}; };
let byte = byte_unit::Byte::from_bytes(*bytesize as u128); if let Some(value) = bytesize.to_u128() {
let byte = if filesize_format.0 == byte_unit::ByteUnit::B && filesize_format.1 == "auto" { let byte = byte_unit::Byte::from_bytes(value);
byte.get_appropriate_unit(false) let byte = if filesize_format.0 == byte_unit::ByteUnit::B && filesize_format.1 == "auto"
} else { {
byte.get_adjusted_unit(filesize_format.0) byte.get_appropriate_unit(false)
}; } else {
byte.get_adjusted_unit(filesize_format.0)
};
match byte.get_unit() { match byte.get_unit() {
byte_unit::ByteUnit::B => { byte_unit::ByteUnit::B => {
let locale_byte = byte.get_value() as u64; let locale_byte = byte.get_value() as u64;
let locale_byte_string = locale_byte.to_formatted_string(&Locale::en); let locale_byte_string = locale_byte.to_formatted_string(&Locale::en);
if filesize_format.1 == "auto" { if filesize_format.1 == "auto" {
let doc = (DbgDocBldr::primitive(locale_byte_string) let doc = (DbgDocBldr::primitive(locale_byte_string)
+ DbgDocBldr::space() + DbgDocBldr::space()
+ DbgDocBldr::kind("B")) + DbgDocBldr::kind("B"))
.group(); .group();
(doc.clone(), InlineShape::render_doc(&doc)) (doc.clone(), InlineShape::render_doc(&doc))
} else { } else {
let doc = (DbgDocBldr::primitive(locale_byte_string)).group(); let doc = (DbgDocBldr::primitive(locale_byte_string)).group();
(doc.clone(), InlineShape::render_doc(&doc))
}
}
_ => {
let doc = DbgDocBldr::primitive(byte.format(1));
(doc.clone(), InlineShape::render_doc(&doc)) (doc.clone(), InlineShape::render_doc(&doc))
} }
} }
_ => { } else {
let doc = DbgDocBldr::primitive(byte.format(1)); let doc = (DbgDocBldr::primitive(format!("{}", bytesize))
(doc.clone(), InlineShape::render_doc(&doc)) + DbgDocBldr::space()
} + DbgDocBldr::kind("B"))
.group();
(doc.clone(), InlineShape::render_doc(&doc))
} }
} }

View file

@ -61,9 +61,21 @@ fn collect_values(input: &[Value]) -> Result<Vec<toml::Value>, ShellError> {
// Helper method to recursively convert nu_protocol::Value -> toml::Value // Helper method to recursively convert nu_protocol::Value -> toml::Value
// This shouldn't be called at the top-level // This shouldn't be called at the top-level
fn helper(v: &Value) -> Result<toml::Value, ShellError> { fn helper(v: &Value) -> Result<toml::Value, ShellError> {
use bigdecimal::ToPrimitive;
Ok(match &v.value { Ok(match &v.value {
UntaggedValue::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b), UntaggedValue::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b),
UntaggedValue::Primitive(Primitive::Filesize(b)) => toml::Value::Integer(*b as i64), UntaggedValue::Primitive(Primitive::Filesize(b)) => {
if let Some(value) = b.to_i64() {
toml::Value::Integer(value)
} else {
return Err(ShellError::labeled_error(
"Value too large to convert to toml value",
"value too large",
v.tag.span,
));
}
}
UntaggedValue::Primitive(Primitive::Duration(i)) => toml::Value::String(i.to_string()), UntaggedValue::Primitive(Primitive::Duration(i)) => toml::Value::String(i.to_string()),
UntaggedValue::Primitive(Primitive::Date(d)) => toml::Value::String(d.to_string()), UntaggedValue::Primitive(Primitive::Date(d)) => toml::Value::String(d.to_string()),
UntaggedValue::Primitive(Primitive::EndOfStream) => { UntaggedValue::Primitive(Primitive::EndOfStream) => {

View file

@ -81,21 +81,12 @@ pub fn unsafe_compute_values(
match (left, right) { match (left, right) {
(UntaggedValue::Primitive(lhs), UntaggedValue::Primitive(rhs)) => match (lhs, rhs) { (UntaggedValue::Primitive(lhs), UntaggedValue::Primitive(rhs)) => match (lhs, rhs) {
(Primitive::Filesize(x), Primitive::Int(y)) => match operator { (Primitive::Filesize(x), Primitive::Int(y)) => match operator {
Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::Int(x + y))), Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Filesize(x * y))),
Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::Int(x - y))), Operator::Divide => Ok(UntaggedValue::Primitive(Primitive::Filesize(x / y))),
Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Int(x * y))),
Operator::Divide => Ok(UntaggedValue::Primitive(Primitive::Decimal(
bigdecimal::BigDecimal::from(*x) / bigdecimal::BigDecimal::from(y.clone()),
))),
_ => Err((left.type_name(), right.type_name())), _ => Err((left.type_name(), right.type_name())),
}, },
(Primitive::Int(x), Primitive::Filesize(y)) => match operator { (Primitive::Int(x), Primitive::Filesize(y)) => match operator {
Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::Int(x + y))), Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Filesize(x * y))),
Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::Int(x - y))),
Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Int(x * y))),
Operator::Divide => Ok(UntaggedValue::Primitive(Primitive::Decimal(
bigdecimal::BigDecimal::from(x.clone()) / bigdecimal::BigDecimal::from(*y),
))),
_ => Err((left.type_name(), right.type_name())), _ => Err((left.type_name(), right.type_name())),
}, },
_ => Err((left.type_name(), right.type_name())), _ => Err((left.type_name(), right.type_name())),
@ -120,8 +111,12 @@ pub fn compute_values(
Ok(UntaggedValue::Primitive(Primitive::Filesize(result))) Ok(UntaggedValue::Primitive(Primitive::Filesize(result)))
} }
(Primitive::Filesize(x), Primitive::Int(y)) => match operator { (Primitive::Filesize(x), Primitive::Int(y)) => match operator {
Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Int(x * y))), Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Filesize(x * y))),
Operator::Divide => Ok(UntaggedValue::Primitive(Primitive::Int(x / y))), Operator::Divide => Ok(UntaggedValue::Primitive(Primitive::Filesize(x / y))),
_ => Err((left.type_name(), right.type_name())),
},
(Primitive::Int(x), Primitive::Filesize(y)) => match operator {
Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Filesize(x * y))),
_ => Err((left.type_name(), right.type_name())), _ => Err((left.type_name(), right.type_name())),
}, },
(Primitive::Int(x), Primitive::Int(y)) => match operator { (Primitive::Int(x), Primitive::Int(y)) => match operator {

View file

@ -631,8 +631,8 @@ impl Unit {
} }
} }
pub fn filesize(size_in_bytes: u64) -> UntaggedValue { pub fn filesize(size_in_bytes: impl Into<BigInt>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Filesize(size_in_bytes)) UntaggedValue::Primitive(Primitive::Filesize(size_in_bytes.into()))
} }
pub fn duration(nanos: BigInt) -> UntaggedValue { pub fn duration(nanos: BigInt) -> UntaggedValue {

View file

@ -186,7 +186,7 @@ impl UntaggedValue {
} }
/// Helper for creating filesize values /// Helper for creating filesize values
pub fn filesize(s: impl Into<u64>) -> UntaggedValue { pub fn filesize(s: impl Into<BigInt>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Filesize(s.into())) UntaggedValue::Primitive(Primitive::Filesize(s.into()))
} }
@ -713,7 +713,7 @@ impl U64Ext for u64 {
fn to_filesize_value(&self, the_tag: Tag) -> Value { fn to_filesize_value(&self, the_tag: Tag) -> Value {
Value { Value {
value: UntaggedValue::Primitive(Primitive::Filesize(*self)), value: UntaggedValue::Primitive(Primitive::Filesize(BigInt::from(*self))),
tag: the_tag, tag: the_tag,
} }
} }

View file

@ -31,7 +31,7 @@ pub enum Primitive {
#[serde(with = "serde_bigdecimal")] #[serde(with = "serde_bigdecimal")]
Decimal(BigDecimal), Decimal(BigDecimal),
/// A count in the number of bytes, used as a filesize /// A count in the number of bytes, used as a filesize
Filesize(u64), Filesize(BigInt),
/// A string value /// A string value
String(String), String(String),
/// A path to travel to reach a value in a table /// A path to travel to reach a value in a table
@ -254,17 +254,21 @@ pub fn format_primitive(primitive: &Primitive, field_name: Option<&String>) -> S
Primitive::EndOfStream => String::new(), Primitive::EndOfStream => String::new(),
Primitive::FilePath(p) => format!("{}", p.display()), Primitive::FilePath(p) => format!("{}", p.display()),
Primitive::Filesize(num_bytes) => { Primitive::Filesize(num_bytes) => {
let byte = byte_unit::Byte::from_bytes(*num_bytes as u128); if let Some(value) = num_bytes.to_u128() {
let byte = byte_unit::Byte::from_bytes(value);
if byte.get_bytes() == 0u128 { if byte.get_bytes() == 0u128 {
return "".to_string(); return "".to_string();
} }
let byte = byte.get_appropriate_unit(false); let byte = byte.get_appropriate_unit(false);
match byte.get_unit() { match byte.get_unit() {
byte_unit::ByteUnit::B => format!("{} B ", byte.get_value()), byte_unit::ByteUnit::B => format!("{} B ", byte.get_value()),
_ => byte.format(1), _ => byte.format(1),
}
} else {
format!("{} B", num_bytes)
} }
} }
Primitive::Duration(duration) => format_duration(duration), Primitive::Duration(duration) => format_duration(duration),

View file

@ -750,6 +750,53 @@ fn range_with_mixed_types() {
assert_eq!(actual.out, "55"); assert_eq!(actual.out, "55");
} }
#[test]
fn filesize_math() {
let actual = nu!(
cwd: ".",
r#"
= 100 * 10kb
"#
);
assert_eq!(actual.out, "1.0 MB");
}
#[test]
fn filesize_math2() {
let actual = nu!(
cwd: ".",
r#"
= 100 / 10kb
"#
);
assert!(actual.err.contains("Coercion"));
}
#[test]
fn filesize_math3() {
let actual = nu!(
cwd: ".",
r#"
= 100kb / 10
"#
);
assert_eq!(actual.out, "10.2 KB");
}
#[test]
fn filesize_math4() {
let actual = nu!(
cwd: ".",
r#"
= 100kb * 5
"#
);
assert_eq!(actual.out, "512.0 KB");
}
#[test] #[test]
fn exclusive_range_with_mixed_types() { fn exclusive_range_with_mixed_types() {
let actual = nu!( let actual = nu!(