use std::time::Duration;
pub fn to_string(d: Duration) -> String {
let mut buf = vec![0u8; 32];
let mut w = buf.len();
let secs = d.as_secs();
let nanos = d.subsec_nanos();
if secs == 0 {
let mut prec = 0;
w -= 1;
buf[w] = b's';
w -= 1;
if nanos == 0 {
return "0s".to_owned();
} else if nanos < 1_000 {
prec = 0;
buf[w] = b'n';
} else if nanos < 1_000_000 {
prec = 3;
buf[w] = 0xb5;
w -= 1;
buf[w] = 0xc2;
} else {
prec = 6;
buf[w] = b'm';
}
let (mut w, u) = fmt_frac(&mut buf[..w], nanos as u64, prec);
w = fmt_int(&mut buf[..w], u);
return String::from_utf8_lossy(&buf[w..]).into_owned();
}
let mut u = secs;
w -= 1;
buf[w] = b's';
let (mut w, _) = fmt_frac(&mut buf[..w], nanos as u64, 9);
w = fmt_int(&mut buf[..w], u % 60);
u /= 60;
if u > 0 {
w -= 1;
buf[w] = b'm';
w = fmt_int(&mut buf[..w], u % 60);
u /= 60;
if u > 0 {
w -= 1;
buf[w] = b'h';
w = fmt_int(&mut buf[..w], u);
}
}
return String::from_utf8_lossy(&buf[w..]).into_owned();
}
fn fmt_frac(buf: &mut [u8], v: u64, prec: u8) -> (usize, u64) {
let mut w = buf.len();
let mut v = v;
let mut print = false;
for _ in 0..prec {
let digit = v % 10;
print = print || digit != 0;
if print {
w -= 1;
buf[w] = digit as u8 + b'0';
}
v /= 10;
}
if print {
w -= 1;
buf[w] = b'.';
}
(w, v)
}
fn fmt_int(buf: &mut [u8], v: u64) -> usize {
let mut w = buf.len();
let mut v = v;
if v == 0 {
w -= 1;
buf[w] = b'0';
} else {
while v > 0 {
w -= 1;
buf[w] = ((v % 10) as u8) + b'0';
v /= 10;
}
}
w
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_string() {
assert_eq!("0s", to_string(Duration::new(0, 0)));
assert_eq!("1ns", to_string(Duration::new(0, 1)));
assert_eq!("1.1µs", to_string(Duration::new(0, 1100)));
assert_eq!("2.2ms", to_string(Duration::new(0, 2200_000)));
assert_eq!("100.567123ms", to_string(Duration::new(0, 100_567_123)));
assert_eq!("3.3s", to_string(Duration::new(3, 300_000_000)));
assert_eq!(
"9m13.123456789s",
to_string(Duration::new(553, 123_456_789))
);
assert_eq!("4m5s", to_string(Duration::new(4 * 60 + 5, 0)));
assert_eq!("4m5.001s", to_string(Duration::new(4 * 60 + 5, 1_000_000)));
assert_eq!(
"5h6m7.001s",
to_string(Duration::new((5 * 60 * 60) + (6 * 60) + 7, 1_000_000))
);
assert_eq!("8m0.000000001s", to_string(Duration::new(8 * 60, 1)));
assert_eq!(
"2562047h47m16.854775807s",
to_string(Duration::new(
(2562047 * 60 * 60) + (47 * 60) + 16,
854_775_807
))
);
assert_eq!(
"5124095576030431h0m15s",
to_string(Duration::new(std::u64::MAX, 0))
);
assert_eq!(
"5124095576030431h0m15.999999999s",
to_string(Duration::new(std::u64::MAX, 999_999_999))
);
assert_eq!(
"5124095576030431h0m15.000001s",
to_string(Duration::new(std::u64::MAX, 1_000))
);
assert_eq!(
"5124095576030431h0m15.001s",
to_string(Duration::new(std::u64::MAX, 1_000_000))
);
}
}