From 45dfe129dc15855fbe0730a785c499a741a18ea1 Mon Sep 17 00:00:00 2001 From: Matthew Gamble Date: Thu, 8 Jul 2021 00:33:49 +1000 Subject: [PATCH] Add support for data rate units This permits the following calculations: 10 kilobytes per second * 6 seconds = 60 kilobytes 500 megabytes / 100 megabytes per second = 5 seconds 1 gibibit per second * 1 hour = 3600 gibibits --- CHANGELOG.md | 1 + src/lexer.rs | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/units.rs | 120 ++++++++++++++++++++++++++ 3 files changed, 357 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d84439e..5b27d7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## Next - Add support for dividing length units by speed units (like 10 km / 100 kph) +- Add support for data transfer rate units (eg. megabytes per second) ## 1.7.0 - 2021 Jul 14 - Add operator words `plus`, `minus` and `times` diff --git a/src/lexer.rs b/src/lexer.rs index f7c3e98..407a772 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -428,6 +428,16 @@ fn parse_word(word: &str, lexer: &mut Lexer) -> Result<(), String> { "zib" | "zebibyte" | "zebibytes" => Token::Unit(Zebibyte), "yib" | "yobibyte" | "yobibytes" => Token::Unit(Yobibyte), + "bps" => Token::Unit(BitsPerSecond), + "kbps" => Token::Unit(KilobitsPerSecond), + "mbps" => Token::Unit(MegabitsPerSecond), + "gbps" => Token::Unit(GigabitsPerSecond), + "tbps" => Token::Unit(TerabitsPerSecond), + "pbps" => Token::Unit(PetabitsPerSecond), + "ebps" => Token::Unit(ExabitsPerSecond), + "zbps" => Token::Unit(ZettabitsPerSecond), + "ybps" => Token::Unit(YottabitsPerSecond), + "millijoule" | "millijoules" => Token::Unit(Millijoule), "j"| "joule" | "joules" => Token::Unit(Joule), "nm" => Token::Unit(NewtonMeter), @@ -750,6 +760,142 @@ pub fn lex(input: &str, remove_trailing_operator: bool, default_degree: Unit) -> (Token::Unit(Foot), Token::LexerKeyword(Per), Token::Unit(Second)) => { tokens[token_index-2] = Token::Unit(FeetPerSecond); }, + // bits per second + (Token::Unit(Bit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(BitsPerSecond); + }, + // kilobits per second + (Token::Unit(Kilobit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(KilobitsPerSecond); + }, + // megabits per second + (Token::Unit(Megabit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(MegabitsPerSecond); + }, + // gigabits per second + (Token::Unit(Gigabit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(GigabitsPerSecond); + }, + // terabits per second + (Token::Unit(Terabit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(TerabitsPerSecond); + }, + // petabits per second + (Token::Unit(Petabit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(PetabitsPerSecond); + }, + // exabits per second + (Token::Unit(Exabit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(ExabitsPerSecond); + }, + // zettabits per second + (Token::Unit(Zettabit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(ZettabitsPerSecond); + }, + // yottabits per second + (Token::Unit(Yottabit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(YottabitsPerSecond); + }, + // kibibits per second + (Token::Unit(Kibibit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(KibibitsPerSecond); + }, + // mebibits per second + (Token::Unit(Mebibit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(MebibitsPerSecond); + }, + // gibibits per second + (Token::Unit(Gibibit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(GibibitsPerSecond); + }, + // tebibits per second + (Token::Unit(Tebibit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(TebibitsPerSecond); + }, + // pebibits per second + (Token::Unit(Pebibit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(PebibitsPerSecond); + }, + // exbibits per second + (Token::Unit(Exbibit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(ExbibitsPerSecond); + }, + // zebibits per second + (Token::Unit(Zebibit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(ZebibitsPerSecond); + }, + // yobibits per second + (Token::Unit(Yobibit), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(YobibitsPerSecond); + }, + // bytes per second + (Token::Unit(Byte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(BytesPerSecond); + }, + // kilobytes per second + (Token::Unit(Kilobyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(KilobytesPerSecond); + }, + // megabytes per second + (Token::Unit(Megabyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(MegabytesPerSecond); + }, + // gigabytes per second + (Token::Unit(Gigabyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(GigabytesPerSecond); + }, + // terabytes per second + (Token::Unit(Terabyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(TerabytesPerSecond); + }, + // petabytes per second + (Token::Unit(Petabyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(PetabytesPerSecond); + }, + // exabytes per second + (Token::Unit(Exabyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(ExabytesPerSecond); + }, + // zettabytes per second + (Token::Unit(Zettabyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(ZettabytesPerSecond); + }, + // yottabytes per second + (Token::Unit(Yottabyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(YottabytesPerSecond); + }, + // kibibytes per second + (Token::Unit(Kibibyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(KibibytesPerSecond); + }, + // mebibytes per second + (Token::Unit(Mebibyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(MebibytesPerSecond); + }, + // gibibytes per second + (Token::Unit(Gibibyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(GibibytesPerSecond); + }, + // tebibytes per second + (Token::Unit(Tebibyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(TebibytesPerSecond); + }, + // pebibytes per second + (Token::Unit(Pebibyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(PebibytesPerSecond); + }, + // exbibytes per second + (Token::Unit(Exbibyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(ExbibytesPerSecond); + }, + // zebibytes per second + (Token::Unit(Zebibyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(ZebibytesPerSecond); + }, + // yobibytes per second + (Token::Unit(Yobibyte), Token::LexerKeyword(Per), Token::Unit(Second)) => { + tokens[token_index-2] = Token::Unit(YobibytesPerSecond); + }, // btu/min (Token::Unit(BritishThermalUnit), Token::LexerKeyword(Per), Token::Unit(Minute)) => { tokens[token_index-2] = Token::Unit(BritishThermalUnitsPerMinute); @@ -800,6 +946,7 @@ mod tests { fn test_lex() { let strip_operator_spacing = Regex::new(r" ([+\-*/]) ").unwrap(); let strip_afterdigit_spacing = Regex::new(r"(\d) ").unwrap(); + let nonplural_data_units = Regex::new(r"(bit|byte)s").unwrap(); let run_lex = |input: &str, expected_tokens: Vec| { let tokens = match lex(input, false, Unit::Celsius) { @@ -827,6 +974,16 @@ mod tests { assert!(tokens_afterdigit_stripped_spaces == expected_tokens, "{}", info_msg); }; + let run_datarate_lex = |input: &str, expected_tokens: Vec| { + run_lex(input, (*expected_tokens).to_vec()); + + // Prove plural and non-plural data units behave identically + let input_nonplural_units = nonplural_data_units.replace_all(input, "$1"); + let tokens_nonplural_units = lex(&input_nonplural_units, false, Unit::Celsius).unwrap(); + let info_msg = format!("run_datarate_lex input: {}\nexpected: {:?}\nreceived: {:?}", input, expected_tokens, tokens_nonplural_units); + assert!(tokens_nonplural_units == expected_tokens, "{}", info_msg); + }; + run_lex("88 kilometres * 2", vec![numtok!(88), Token::Unit(Kilometer), Token::Operator(Multiply), numtok!(2)]); run_lex("100 nmi", vec![numtok!(100), Token::Unit(NauticalMile)]); run_lex("101 nautical miles", vec![numtok!(101), Token::Unit(NauticalMile)]); @@ -861,6 +1018,85 @@ mod tests { run_lex("3 short tons", vec![numtok!(3), Token::Unit(ShortTon)]); run_lex("4 lt", vec![numtok!(4), Token::Unit(LongTon)]); run_lex("4 long tonnes", vec![numtok!(4), Token::Unit(LongTon)]); + run_datarate_lex("1 bit", vec![numtok!(1), Token::Unit(Bit)]); + run_datarate_lex("8 bits", vec![numtok!(8), Token::Unit(Bit)]); + run_datarate_lex("63 kilobits", vec![numtok!(63), Token::Unit(Kilobit)]); + run_datarate_lex("32 megabits", vec![numtok!(32), Token::Unit(Megabit)]); + run_datarate_lex("3.5 gigabits", vec![numtok!(3.5), Token::Unit(Gigabit)]); + run_datarate_lex("2.1 terabits", vec![numtok!(2.1), Token::Unit(Terabit)]); + run_datarate_lex("1.08 petabits", vec![numtok!(1.08), Token::Unit(Petabit)]); + run_datarate_lex("0.73 exabits", vec![numtok!(0.73), Token::Unit(Exabit)]); + run_datarate_lex("0.49 zettabits", vec![numtok!(0.49), Token::Unit(Zettabit)]); + run_datarate_lex("0.23 yottabits", vec![numtok!(0.23), Token::Unit(Yottabit)]); + run_datarate_lex("63 kibibits", vec![numtok!(63), Token::Unit(Kibibit)]); + run_datarate_lex("32 mebibits", vec![numtok!(32), Token::Unit(Mebibit)]); + run_datarate_lex("3.5 gibibits", vec![numtok!(3.5), Token::Unit(Gibibit)]); + run_datarate_lex("2.1 tebibits", vec![numtok!(2.1), Token::Unit(Tebibit)]); + run_datarate_lex("1.08 pebibits", vec![numtok!(1.08), Token::Unit(Pebibit)]); + run_datarate_lex("0.73 exbibits", vec![numtok!(0.73), Token::Unit(Exbibit)]); + run_datarate_lex("0.49 zebibits", vec![numtok!(0.49), Token::Unit(Zebibit)]); + run_datarate_lex("0.23 yobibits", vec![numtok!(0.23), Token::Unit(Yobibit)]); + run_datarate_lex("1 byte", vec![numtok!(1), Token::Unit(Byte)]); + run_datarate_lex("3 bytes", vec![numtok!(3), Token::Unit(Byte)]); + run_datarate_lex("63 kilobytes", vec![numtok!(63), Token::Unit(Kilobyte)]); + run_datarate_lex("32 megabytes", vec![numtok!(32), Token::Unit(Megabyte)]); + run_datarate_lex("3.5 gigabytes", vec![numtok!(3.5), Token::Unit(Gigabyte)]); + run_datarate_lex("2.1 terabytes", vec![numtok!(2.1), Token::Unit(Terabyte)]); + run_datarate_lex("1.08 petabytes", vec![numtok!(1.08), Token::Unit(Petabyte)]); + run_datarate_lex("0.73 exabytes", vec![numtok!(0.73), Token::Unit(Exabyte)]); + run_datarate_lex("0.49 zettabytes", vec![numtok!(0.49), Token::Unit(Zettabyte)]); + run_datarate_lex("0.23 yottabytes", vec![numtok!(0.23), Token::Unit(Yottabyte)]); + run_datarate_lex("63 kibibytes", vec![numtok!(63), Token::Unit(Kibibyte)]); + run_datarate_lex("32 mebibytes", vec![numtok!(32), Token::Unit(Mebibyte)]); + run_datarate_lex("3.5 gibibytes", vec![numtok!(3.5), Token::Unit(Gibibyte)]); + run_datarate_lex("2.1 tebibytes", vec![numtok!(2.1), Token::Unit(Tebibyte)]); + run_datarate_lex("1.08 pebibytes", vec![numtok!(1.08), Token::Unit(Pebibyte)]); + run_datarate_lex("0.73 exbibytes", vec![numtok!(0.73), Token::Unit(Exbibyte)]); + run_datarate_lex("0.49 zebibytes", vec![numtok!(0.49), Token::Unit(Zebibyte)]); + run_datarate_lex("0.23 yobibytes", vec![numtok!(0.23), Token::Unit(Yobibyte)]); + run_lex("432 bps", vec![numtok!(432), Token::Unit(BitsPerSecond)]); + run_lex("56 kbps", vec![numtok!(56), Token::Unit(KilobitsPerSecond)]); + run_lex("12 mbps", vec![numtok!(12), Token::Unit(MegabitsPerSecond)]); + run_lex("4.2 gbps", vec![numtok!(4.2), Token::Unit(GigabitsPerSecond)]); + run_lex("2.2 tbps", vec![numtok!(2.2), Token::Unit(TerabitsPerSecond)]); + run_lex("1.7 pbps", vec![numtok!(1.7), Token::Unit(PetabitsPerSecond)]); + run_lex("0.99 ebps", vec![numtok!(0.99), Token::Unit(ExabitsPerSecond)]); + run_lex("0.64 zbps", vec![numtok!(0.64), Token::Unit(ZettabitsPerSecond)]); + run_lex("0.278 ybps", vec![numtok!(0.278), Token::Unit(YottabitsPerSecond)]); + run_datarate_lex("4 bits per second", vec![numtok!(4), Token::Unit(BitsPerSecond)]); + run_datarate_lex("5 kilobits per second", vec![numtok!(5), Token::Unit(KilobitsPerSecond)]); + run_datarate_lex("6 megabits per second", vec![numtok!(6), Token::Unit(MegabitsPerSecond)]); + run_datarate_lex("7 gigabits per second", vec![numtok!(7), Token::Unit(GigabitsPerSecond)]); + run_datarate_lex("8 terabits per second", vec![numtok!(8), Token::Unit(TerabitsPerSecond)]); + run_datarate_lex("9 petabits per second", vec![numtok!(9), Token::Unit(PetabitsPerSecond)]); + run_datarate_lex("10 exabits per second", vec![numtok!(10), Token::Unit(ExabitsPerSecond)]); + run_datarate_lex("11 zettabits per second", vec![numtok!(11), Token::Unit(ZettabitsPerSecond)]); + run_datarate_lex("12 yottabits per second", vec![numtok!(12), Token::Unit(YottabitsPerSecond)]); + run_datarate_lex("13 kibibits per second", vec![numtok!(13), Token::Unit(KibibitsPerSecond)]); + run_datarate_lex("14 mebibits per second", vec![numtok!(14), Token::Unit(MebibitsPerSecond)]); + run_datarate_lex("15 gibibits per second", vec![numtok!(15), Token::Unit(GibibitsPerSecond)]); + run_datarate_lex("16 tebibits per second", vec![numtok!(16), Token::Unit(TebibitsPerSecond)]); + run_datarate_lex("17 pebibits per second", vec![numtok!(17), Token::Unit(PebibitsPerSecond)]); + run_datarate_lex("18 exbibits per second", vec![numtok!(18), Token::Unit(ExbibitsPerSecond)]); + run_datarate_lex("19 zebibits per second", vec![numtok!(19), Token::Unit(ZebibitsPerSecond)]); + run_datarate_lex("20 yobibits per second", vec![numtok!(20), Token::Unit(YobibitsPerSecond)]); + run_datarate_lex("4 bytes per second", vec![numtok!(4), Token::Unit(BytesPerSecond)]); + run_datarate_lex("5 kilobytes per second", vec![numtok!(5), Token::Unit(KilobytesPerSecond)]); + run_datarate_lex("6 megabytes per second", vec![numtok!(6), Token::Unit(MegabytesPerSecond)]); + run_datarate_lex("7 gigabytes per second", vec![numtok!(7), Token::Unit(GigabytesPerSecond)]); + run_datarate_lex("8 terabytes per second", vec![numtok!(8), Token::Unit(TerabytesPerSecond)]); + run_datarate_lex("9 petabytes per second", vec![numtok!(9), Token::Unit(PetabytesPerSecond)]); + run_datarate_lex("10 exabytes per second", vec![numtok!(10), Token::Unit(ExabytesPerSecond)]); + run_datarate_lex("11 zettabytes per second", vec![numtok!(11), Token::Unit(ZettabytesPerSecond)]); + run_datarate_lex("12 yottabytes per second", vec![numtok!(12), Token::Unit(YottabytesPerSecond)]); + run_datarate_lex("13 kibibytes per second", vec![numtok!(13), Token::Unit(KibibytesPerSecond)]); + run_datarate_lex("14 mebibytes per second", vec![numtok!(14), Token::Unit(MebibytesPerSecond)]); + run_datarate_lex("15 gibibytes per second", vec![numtok!(15), Token::Unit(GibibytesPerSecond)]); + run_datarate_lex("16 tebibytes per second", vec![numtok!(16), Token::Unit(TebibytesPerSecond)]); + run_datarate_lex("17 pebibytes per second", vec![numtok!(17), Token::Unit(PebibytesPerSecond)]); + run_datarate_lex("18 exbibytes per second", vec![numtok!(18), Token::Unit(ExbibytesPerSecond)]); + run_datarate_lex("19 zebibytes per second", vec![numtok!(19), Token::Unit(ZebibytesPerSecond)]); + run_datarate_lex("20 yobibytes per second", vec![numtok!(20), Token::Unit(YobibytesPerSecond)]); run_lex("234 wh", vec![numtok!(234), Token::Unit(WattHour)]); run_lex("1 w", vec![numtok!(1), Token::Unit(Watt)]); run_lex("1 watt", vec![numtok!(1), Token::Unit(Watt)]); diff --git a/src/units.rs b/src/units.rs index 49cf191..fdc9894 100644 --- a/src/units.rs +++ b/src/units.rs @@ -19,6 +19,8 @@ pub enum UnitType { Mass, /// A unit of digital storage, for example [`Kilobyte`] DigitalStorage, + /// A unit of data rate transfer, for example [`KilobytesPerSecond`] + DataTransferRate, /// A unit of energy, for example [`Joule`] or [`KilowattHour`] Energy, /// A unit of power, for example [`Watt`] @@ -187,6 +189,41 @@ create_units!( Zebibyte: (DigitalStorage, d128!(9444732965739290427392)), Yobibyte: (DigitalStorage, d128!(9671406556917033397649408)), + BitsPerSecond: (DataTransferRate, d128!(1)), + KilobitsPerSecond: (DataTransferRate, d128!(1000)), + MegabitsPerSecond: (DataTransferRate, d128!(1000000)), + GigabitsPerSecond: (DataTransferRate, d128!(1000000000)), + TerabitsPerSecond: (DataTransferRate, d128!(1000000000000)), + PetabitsPerSecond: (DataTransferRate, d128!(1000000000000000)), + ExabitsPerSecond: (DataTransferRate, d128!(1000000000000000000)), + ZettabitsPerSecond: (DataTransferRate, d128!(1000000000000000000000)), + YottabitsPerSecond: (DataTransferRate, d128!(1000000000000000000000000)), + KibibitsPerSecond: (DataTransferRate, d128!(1024)), + MebibitsPerSecond: (DataTransferRate, d128!(1048576)), + GibibitsPerSecond: (DataTransferRate, d128!(1073741824)), + TebibitsPerSecond: (DataTransferRate, d128!(1099511627776)), + PebibitsPerSecond: (DataTransferRate, d128!(1125899906842624)), + ExbibitsPerSecond: (DataTransferRate, d128!(1152921504606846976)), + ZebibitsPerSecond: (DataTransferRate, d128!(1180591620717411303424)), + YobibitsPerSecond: (DataTransferRate, d128!(1208925819614629174706176)), + BytesPerSecond: (DataTransferRate, d128!(8)), + KilobytesPerSecond: (DataTransferRate, d128!(8000)), + MegabytesPerSecond: (DataTransferRate, d128!(8000000)), + GigabytesPerSecond: (DataTransferRate, d128!(8000000000)), + TerabytesPerSecond: (DataTransferRate, d128!(8000000000000)), + PetabytesPerSecond: (DataTransferRate, d128!(8000000000000000)), + ExabytesPerSecond: (DataTransferRate, d128!(8000000000000000000)), + ZettabytesPerSecond: (DataTransferRate, d128!(8000000000000000000000)), + YottabytesPerSecond: (DataTransferRate, d128!(8000000000000000000000000)), + KibibytesPerSecond: (DataTransferRate, d128!(8192)), + MebibytesPerSecond: (DataTransferRate, d128!(8388608)), + GibibytesPerSecond: (DataTransferRate, d128!(8589934592)), + TebibytesPerSecond: (DataTransferRate, d128!(8796093022208)), + PebibytesPerSecond: (DataTransferRate, d128!(9007199254740992)), + ExbibytesPerSecond: (DataTransferRate, d128!(9223372036854775808)), + ZebibytesPerSecond: (DataTransferRate, d128!(9444732965739290427392)), + YobibytesPerSecond: (DataTransferRate, d128!(9671406556917033397649408)), + // ! If updating Millijoule, also update get_inverted_millijoule_weight() Millijoule: (Energy, d128!(0.001)), Joule: (Energy, d128!(1)), @@ -551,6 +588,50 @@ fn actual_multiply(left: Number, right: Number, swapped: bool) -> Result Bit, + KilobitsPerSecond => Kilobit, + MegabitsPerSecond => Megabit, + GigabitsPerSecond => Gigabit, + TerabitsPerSecond => Terabit, + PetabitsPerSecond => Petabit, + ExabitsPerSecond => Exabit, + ZettabitsPerSecond => Zettabit, + YottabitsPerSecond => Yottabit, + KibibitsPerSecond => Kibibit, + MebibitsPerSecond => Mebibit, + GibibitsPerSecond => Gibibit, + TebibitsPerSecond => Tebibit, + PebibitsPerSecond => Pebibit, + ExbibitsPerSecond => Exbibit, + ZebibitsPerSecond => Zebibit, + YobibitsPerSecond => Yobibit, + BytesPerSecond => Byte, + KilobytesPerSecond => Kilobyte, + MegabytesPerSecond => Megabyte, + GigabytesPerSecond => Gigabyte, + TerabytesPerSecond => Terabyte, + PetabytesPerSecond => Petabyte, + ExabytesPerSecond => Exabyte, + ZettabytesPerSecond => Zettabyte, + YottabytesPerSecond => Yottabyte, + KibibytesPerSecond => Kibibyte, + MebibytesPerSecond => Mebibyte, + GibibytesPerSecond => Gibibyte, + TebibytesPerSecond => Tebibyte, + PebibytesPerSecond => Pebibyte, + ExbibytesPerSecond => Exbibyte, + ZebibytesPerSecond => Zebibyte, + YobibytesPerSecond => Yobibyte, + _ => Bit, + }; + let data_storage = Number::new(result, Bit); + Ok(convert(data_storage, final_unit)?) } else if lcat == Voltage && rcat == ElectricCurrent { // 1 volt * 1 ampere = 1 watt let result = (left.value * left.unit.weight()) * (right.value * right.unit.weight()); @@ -631,6 +712,12 @@ pub fn divide(left: Number, right: Number) -> Result { let kilometers_per_hour = convert(right, KilometersPerHour)?; let hour = Number::new(kilometers.value / kilometers_per_hour.value, Hour); Ok(to_ideal_unit(hour)) + } else if lcat == DigitalStorage && rcat == DataTransferRate { + // 1 kilobit / 1 bit per second + let bits = convert(left, Bit)?; + let bits_per_second = convert(right, BitsPerSecond)?; + let seconds = Number::new(bits.value / bits_per_second.value, Second); + Ok(to_ideal_unit(seconds)) } else if lcat == Power && rcat == ElectricCurrent { // 1 watt / 1 ampere = 1 volt let result = (left.value * left.unit.weight()) / (right.value * right.unit.weight()); @@ -840,6 +927,39 @@ mod tests { assert_float_eq!(convert_test(1024.0, Exbibyte, Zebibyte), 1.0); assert_float_eq!(convert_test(1024.0, Zebibyte, Yobibyte), 1.0); + assert_float_eq!(convert_test(1000.0, BitsPerSecond, KilobitsPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, KilobitsPerSecond, MegabitsPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, MegabitsPerSecond, GigabitsPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, GigabitsPerSecond, TerabitsPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, TerabitsPerSecond, PetabitsPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, PetabitsPerSecond, ExabitsPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, ExabitsPerSecond, ZettabitsPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, ZettabitsPerSecond, YottabitsPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, BitsPerSecond, KibibitsPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, KibibitsPerSecond, MebibitsPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, MebibitsPerSecond, GibibitsPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, GibibitsPerSecond, TebibitsPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, TebibitsPerSecond, PebibitsPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, PebibitsPerSecond, ExbibitsPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, ExbibitsPerSecond, ZebibitsPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, ZebibitsPerSecond, YobibitsPerSecond), 1.0); + assert_float_eq!(convert_test(8.0, BitsPerSecond, BytesPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, BytesPerSecond, KilobytesPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, KilobytesPerSecond, MegabytesPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, MegabytesPerSecond, GigabytesPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, GigabytesPerSecond, TerabytesPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, TerabytesPerSecond, PetabytesPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, PetabytesPerSecond, ExabytesPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, ExabytesPerSecond, ZettabytesPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, ZettabytesPerSecond, YottabytesPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, KibibytesPerSecond, MebibytesPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, MebibytesPerSecond, GibibytesPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, GibibytesPerSecond, TebibytesPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, TebibytesPerSecond, PebibytesPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, PebibytesPerSecond, ExbibytesPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, ExbibytesPerSecond, ZebibytesPerSecond), 1.0); + assert_float_eq!(convert_test(1024.0, ZebibytesPerSecond, YobibytesPerSecond), 1.0); + assert_float_eq!(convert_test(1000.0, Millijoule, Joule), 1.0); assert_float_eq!(convert_test(1000.0, Joule, Kilojoule), 1.0); assert_float_eq!(convert_test(1.0, NewtonMeter, Joule), 1.0);