1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
//! ### Generate beautiful human representations of bytes, durations and even throughputs!
//!
//! Easily generate human-readable descriptions directly on primitive numbers, of several kinds:
//! - counts: which get SI prefixes: "k", "M", "G", "T", "P", "E", "Z", "Y";
//! - durations: with support for nanoseconds, millis, µs, secs, and even HH:MM:SS;
//! - throughputs: which get, in addition to SI prefixes, support for /day, /hour, /month, and /sec!!
//!
//! They work on the following Rust primitive types: `u8, u16, u32, u64, u128, usize, f32, f64, i8, i16, i32, i64, i128, isize`.
//! <br>The entity they refer to is configurable, so you can send "B" for bytes, or "it" for iterations, or "errors", etc.
//! <br>Bytes have dedicated methods for convenience.
//!
//! It is also blazingly fast, taking only ~80 ns to generate, and well-tested.
//!
//! You can, for example:
//!
//! ```rust
//! use human_repr::HumanRepr;
//!
//! // counts (bytes or anything)
//! assert_eq!("43.2 MB", 43214321_u32.human_count_bytes());
//! assert_eq!("123.5 kPackets", 123456_u64.human_count("Packets"));
//!
//! // durations
//! assert_eq!("15.6 µs", 0.0000156.human_duration());
//! assert_eq!("10 ms", 0.01.human_duration());
//! assert_eq!("1:14:48", 4488.395.human_duration());
//!
//! // throughputs (bytes or anything)
//! assert_eq!("1.2 MB/s", (1234567. / 1.).human_throughput_bytes());
//! assert_eq!("6.1 tests/m", (10. / 99.).human_throughput("tests"));
//! assert_eq!("9 errors/d", (125. / 1200000.).human_throughput("errors"));
//!
//! ```
//!
//! ## How to use it
//!
//! Add this dependency to your Cargo.toml file:
//!
//! ```toml
//! human-repr = "0"
//! ```
//!
//! Use the trait:
//!
//! ```rust
//! use human_repr::HumanRepr;
//! ```
//!
//! That's it! You can now call on any number:
//!
//! ```rust
//! fn human_count(self, what: &str) -> String;
//! fn human_count_bytes(self) -> String;
//!
//! fn human_duration(self) -> String;
//!
//! fn human_throughput(self, what: &str) -> String;
//! fn human_throughput_bytes(self) -> String;
//! ```
mod human_count;
mod human_duration;
mod human_throughput;
const BYTES: &str = "B";
/// Human representation trait, already implemented for all Rust primitive number types.
pub trait HumanRepr: sealed::Sealed + Sized {
/// Generate a beautiful human count.
///
/// ```
/// use human_repr::HumanRepr;
/// assert_eq!("43.2 Mcoins", 43214321u32.human_count("coins"));
/// ```
fn human_count(self, what: &str) -> String;
/// Generate a beautiful human count.
///
/// ```
/// use human_repr::HumanRepr;
/// assert_eq!("43.2 MB", 43214321u32.human_count_bytes());
/// ```
fn human_count_bytes(self) -> String {
self.human_count(BYTES)
}
/// Generate a beautiful human duration.
///
/// ```
/// use human_repr::HumanRepr;
/// assert_eq!("160 ms", 0.1599999.human_duration());
/// ```
fn human_duration(self) -> String;
/// Generate a beautiful human throughput.
///
/// ```
/// use human_repr::HumanRepr;
/// assert_eq!("1.2 Mcoins/s", 1234567.8.human_throughput("coins"));
/// ```
fn human_throughput(self, what: &str) -> String;
/// Generate a beautiful human throughput.
///
/// ```
/// use human_repr::HumanRepr;
/// assert_eq!("1.2 MB/s", 1234567.8.human_throughput_bytes());
/// ```
fn human_throughput_bytes(self) -> String {
self.human_throughput(BYTES)
}
}
macro_rules! impl_human {
{$($t:ty),+} => {$(
impl HumanRepr for $t {
fn human_count(self, what: &str) -> String {
human_count::conv(self as f64, what)
}
fn human_duration(self) -> String {
human_duration::conv(self as f64)
}
fn human_throughput(self, what: &str) -> String {
human_throughput::conv(self as f64, what)
}
}
)+}
}
impl_human!(u8, u16, u32, u64, u128, usize, f32, f64, i8, i16, i32, i64, i128, isize);
mod sealed {
pub trait Sealed {}
macro_rules! impl_sealed {
{$($t:ty),+} => {
$(impl Sealed for $t {})+
}
}
impl_sealed!(u8, u16, u32, u64, u128, usize, f32, f64, i8, i16, i32, i64, i128, isize);
}
const SPACE: &str = {
match cfg!(feature = "nospace") {
true => "",
false => " ",
}
};
#[inline]
fn rounded(val: f64, dec: usize) -> f64 {
match dec {
1 => (val * 10.).round() / 10.,
2 => (val * 100.).round() / 100.,
// 0 => val.round(),
_ => unreachable!(),
}
}