use std::fmt::Write;
const NS_PER_NANOSECOND: u128 = 1;
const NS_PER_MICROSECOND: u128 = 1000 * NS_PER_NANOSECOND;
const NS_PER_MILLISECOND: u128 = 1000 * NS_PER_MICROSECOND;
const NS_PER_SECOND: u128 = 1000 * NS_PER_MILLISECOND;
const NS_PER_MINUTE: u128 = 60 * NS_PER_SECOND;
const NS_PER_HOUR: u128 = 60 * NS_PER_MINUTE;
fn format_nanoseconds_in_seconds(buf: &mut String, value: u128) {
if value < NS_PER_MICROSECOND {
write!(buf, "{}ns", value).unwrap();
} else if value < NS_PER_MILLISECOND {
write!(buf, "{}µs", (value as f64) / (NS_PER_MICROSECOND as f64)).unwrap();
} else {
write!(buf, "{}ms", (value as f64) / (NS_PER_MILLISECOND as f64)).unwrap();
}
}
pub fn format_nanoseconds(nanoseconds: u128) -> String {
if nanoseconds == 0 {
return "0ns".to_string();
}
let mut value = nanoseconds;
let mut buf = String::new();
if value < NS_PER_SECOND {
format_nanoseconds_in_seconds(&mut buf, value);
} else {
if value >= NS_PER_HOUR {
let hours = value / NS_PER_HOUR;
value -= hours * NS_PER_HOUR;
write!(&mut buf, "{}h", hours).unwrap();
}
if value >= NS_PER_MINUTE {
let minutes = value / NS_PER_MINUTE;
value -= minutes * NS_PER_MINUTE;
write!(&mut buf, "{}m", minutes).unwrap();
}
if value > 0 {
if value < NS_PER_SECOND {
format_nanoseconds_in_seconds(&mut buf, value);
} else {
let seconds = (value as f64) / (NS_PER_SECOND as f64);
write!(&mut buf, "{}s", &seconds).unwrap();
}
}
}
buf
}
pub fn format_scientific(num: f64, width: usize, precision: usize) -> String {
const EXP_PAD: usize = 2;
let mut result = format!("{:.precision$e}", num, precision = precision);
let exp = result.split_off(result.find('e').unwrap());
let (sign, exp) = if exp.starts_with("e-") {
('-', &exp[2..])
} else {
('+', &exp[1..])
};
result.push_str(&format!("E{}{:0>pad$}", sign, exp, pad = EXP_PAD));
format!("{:>width$}", result, width = width)
}
pub fn format_fortran(num: f64) -> String {
format_scientific(num, 23, 15)
}
#[cfg(test)]
mod tests {
use super::{format_fortran, format_nanoseconds, format_scientific};
#[test]
fn format_nanoseconds_works() {
let mut res = format_nanoseconds(0);
assert_eq!(res, "0ns");
res = format_nanoseconds(250);
assert_eq!(res, "250ns");
res = format_nanoseconds(2_500);
assert_eq!(res, "2.5µs");
res = format_nanoseconds(25_000);
assert_eq!(res, "25µs");
res = format_nanoseconds(250_000);
assert_eq!(res, "250µs");
res = format_nanoseconds(2_500_000);
assert_eq!(res, "2.5ms");
res = format_nanoseconds(25_000_000);
assert_eq!(res, "25ms");
res = format_nanoseconds(250_000_000);
assert_eq!(res, "250ms");
res = format_nanoseconds(2_500_000_000);
assert_eq!(res, "2.5s");
res = format_nanoseconds(25_000_000_000);
assert_eq!(res, "25s");
res = format_nanoseconds(250_000_000_000);
assert_eq!(res, "4m10s");
res = format_nanoseconds(2_500_000_000_000);
assert_eq!(res, "41m40s");
res = format_nanoseconds(25_000_000_000_000);
assert_eq!(res, "6h56m40s");
res = format_nanoseconds(250_000_000_000_000);
assert_eq!(res, "69h26m40s");
res = format_nanoseconds(60_000_000_000);
assert_eq!(res, "1m");
res = format_nanoseconds(120_000_000_000);
assert_eq!(res, "2m");
res = format_nanoseconds(3_600_000_000_000);
assert_eq!(res, "1h");
res = format_nanoseconds(3_723_000_000_000);
assert_eq!(res, "1h2m3s");
res = format_nanoseconds(3_600_000_000_001);
assert_eq!(res, "1h1ns");
res = format_nanoseconds(3_600_000_001_000);
assert_eq!(res, "1h1µs");
res = format_nanoseconds(3_600_000_100_001);
assert_eq!(res, "1h100.001µs");
res = format_nanoseconds(3_600_001_000_000);
assert_eq!(res, "1h1ms");
res = format_nanoseconds(3_601_000_000_000);
assert_eq!(res, "1h1s");
res = format_nanoseconds(3_601_100_000_000);
assert_eq!(res, "1h1.1s");
}
#[test]
fn format_scientific_works() {
assert_eq!(format_scientific(0.1111, 9, 2), " 1.11E-01");
assert_eq!(format_scientific(0.02222, 11, 4), " 2.2220E-02");
assert_eq!(format_scientific(3333.0, 10, 3), " 3.333E+03");
assert_eq!(format_scientific(-44444.0, 9, 1), " -4.4E+04");
assert_eq!(format_scientific(0.0, 8, 1), " 0.0E+00");
assert_eq!(format_scientific(1.0, 23, 15), " 1.000000000000000E+00");
assert_eq!(format_scientific(42.0, 23, 15), " 4.200000000000000E+01");
assert_eq!(format_scientific(9999999999.00, 8, 1), " 1.0E+10");
assert_eq!(format_scientific(999999999999.00, 23, 15), " 9.999999999990000E+11");
assert_eq!(format_scientific(123456789.1011, 11, 4), " 1.2346E+08");
}
#[test]
fn format_fortran_works() {
assert_eq!(format_fortran(0.1111), " 1.111000000000000E-01");
assert_eq!(format_fortran(0.02222), " 2.222000000000000E-02");
assert_eq!(format_fortran(3333.0), " 3.333000000000000E+03");
assert_eq!(format_fortran(-44444.0), " -4.444400000000000E+04");
assert_eq!(format_fortran(0.0), " 0.000000000000000E+00");
assert_eq!(format_fortran(1.0), " 1.000000000000000E+00");
assert_eq!(format_fortran(42.0), " 4.200000000000000E+01");
assert_eq!(format_fortran(9999999999.00), " 9.999999999000000E+09");
assert_eq!(format_fortran(999999999999.00), " 9.999999999990000E+11");
assert_eq!(format_fortran(123456789.1011), " 1.234567891011000E+08");
}
}