From 3334920d18c946f810527351e8617106dfc48794 Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Wed, 20 Sep 2023 18:16:21 +0200 Subject: [PATCH] bintols work with generic hmnsize --- members/pt-bintols/src/datalayout.rs | 14 +++--- members/pt-bintols/src/display.rs | 47 ++++++++++++++++++- members/pt-bintols/src/lib.rs | 21 +++++++++ members/pt-bintols/tests/datalayout.rs | 7 +++ members/pt-bintols/tests/display.rs | 63 ++++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 7 deletions(-) create mode 100644 members/pt-bintols/tests/datalayout.rs create mode 100644 members/pt-bintols/tests/display.rs diff --git a/members/pt-bintols/src/datalayout.rs b/members/pt-bintols/src/datalayout.rs index 2777aca..2cdeabc 100644 --- a/members/pt-bintols/src/datalayout.rs +++ b/members/pt-bintols/src/datalayout.rs @@ -1,7 +1,9 @@ //* # See what's behind the datatypes of Rust //* //* This Crate shows off how datatypes of rust are stored in memory. -use crate::display::{bytes_to_bin, byte_bit_display}; + +// reexport macros +pub use crate::investigate_memory_layout; /// ## Investigate the internal representation of variables /// @@ -9,9 +11,9 @@ use crate::display::{bytes_to_bin, byte_bit_display}; #[macro_export] macro_rules! investigate_memory_layout { ($t:ty, $v:tt) => { - println!("Type:\t{}", type_name::<$t>()); + println!("Type:\t{}", std::any::type_name::<$t>()); println!("\talign:\t{:?} B", std::mem::align_of::<$t>()); - println!("\tID:\t{:?}\n", TypeId::of::<$t>()); + println!("\tID:\t{:?}\n", std::any::TypeId::of::<$t>()); println!("\tItems:"); unsafe { for (index, item) in $v.iter().enumerate() { @@ -28,10 +30,10 @@ macro_rules! investigate_memory_layout { \t\tnote: \tmemory order reversed\n\ ", pointer, - byte_bit_display(std::mem::align_of_val(item)), - byte_bit_display(memory.len()), + display::byte_bit_display(std::mem::align_of_val(item)), + display::byte_bit_display(memory.len()), memory, - bytes_to_bin(&memory) + display::bytes_to_bin(&memory) ); } } diff --git a/members/pt-bintols/src/display.rs b/members/pt-bintols/src/display.rs index 106564f..e0fffc1 100644 --- a/members/pt-bintols/src/display.rs +++ b/members/pt-bintols/src/display.rs @@ -1,5 +1,8 @@ //* # Tools that help display binary values, data sizes, etc +use super::*; +pub use num_traits::{PrimInt, ToPrimitive}; + /// ## Get the binary representation for a Byte array [`&[u8]`] /// /// ### Arguments @@ -18,5 +21,47 @@ pub fn bytes_to_bin(data: &[u8]) -> String { /// Quickly format a number of Bytes [`usize`] with the corresponding /// number of bits pub fn byte_bit_display(data: usize) -> String { - format!("{:07} B = {:08} bit", data.clone(), data * 8) + format!("{} B = {} bit", data.clone(), data * 8) +} + +/// ## Format total byte sizes to human readable sizes +pub fn humanbytes(total: T) -> String +where + T: PrimInt, + T: ToPrimitive, + T: Ord, + T: std::fmt::Display, + T: std::fmt::Debug, +{ + if total < T::from(KIBI).unwrap() { + return format!("{total} B"); + } else if T::from(KIBI).unwrap() <= total && total < T::from(MEBI).unwrap() { + return format!("{:.2} K", total.to_f64().unwrap() / KIBI as f64); + } else if T::from(MEBI).unwrap() <= total && total < T::from(GIBI).unwrap() { + return format!("{:.2} M", total.to_f64().unwrap() / MEBI as f64); + } else if T::from(GIBI).unwrap() <= total && total < T::from(TEBI).unwrap() { + return format!("{:.2} G", total.to_f64().unwrap() / GIBI as f64); + } else if T::from(TEBI).unwrap() <= total && total < T::from(PEBI).unwrap() { + return format!("{:.2} T", total.to_f64().unwrap() / TEBI as f64); + } else if T::from(PEBI).unwrap() <= total && total < T::from(EXBI).unwrap() { + return format!("{:.2} P", total.to_f64().unwrap() / PEBI as f64); + } + // now we are starting to reach the sizes that are pretty unrealistic + // (as of 2023 that is, hello future) + // + // the later ones overflow `usize` on 64 Bit computers, so we have + // to work with a fixed, larger sized datatype + else { + let total: u128 = total.to_u128().unwrap(); + if EXBI <= total && total < ZEBI { + return format!("{:.2} E", total.to_f64().unwrap() / EXBI as f64); + } else if ZEBI <= total && total < YOBI { + return format!("{:.2} Z", total.to_f64().unwrap() / ZEBI as f64); + } else if YOBI <= total { + return format!("{:.2} Y", total.to_f64().unwrap() / YOBI as f64); + } + else { + unreachable!() + } + } } diff --git a/members/pt-bintols/src/lib.rs b/members/pt-bintols/src/lib.rs index 8ad5bda..7059e78 100644 --- a/members/pt-bintols/src/lib.rs +++ b/members/pt-bintols/src/lib.rs @@ -1,3 +1,24 @@ +//* # Tools to work with binary values, memory, storage + +// official binary prefixes, see [https://en.wikipedia.org/wiki/Binary_prefix] +/// 2^10 +pub const KIBI: usize = 2usize.pow(10); +/// 2^20 +pub const MEBI: usize = 2usize.pow(20); +/// 2^30 +pub const GIBI: usize = 2usize.pow(30); +/// 2^40 +pub const TEBI: usize = 2usize.pow(40); +/// 2^50 +pub const PEBI: usize = 2usize.pow(50); +/// 2^60 +pub const EXBI: u128 = 2u128.pow(60); +// at this point, `usize` would overflow, so we have to switch to a bigger datatype. +/// 2^70 +pub const ZEBI: u128 = 2u128.pow(70); +/// 2^80 +pub const YOBI: u128 = 2u128.pow(80); + // use pt_core; pub mod datalayout; pub mod display; diff --git a/members/pt-bintols/tests/datalayout.rs b/members/pt-bintols/tests/datalayout.rs new file mode 100644 index 0000000..f6582eb --- /dev/null +++ b/members/pt-bintols/tests/datalayout.rs @@ -0,0 +1,7 @@ +use pt_bintols::*; + +#[test] +fn mkdmp() { + let v = vec![true, true, false]; + investigate_memory_layout!(bool, v); +} diff --git a/members/pt-bintols/tests/display.rs b/members/pt-bintols/tests/display.rs new file mode 100644 index 0000000..a6ac00c --- /dev/null +++ b/members/pt-bintols/tests/display.rs @@ -0,0 +1,63 @@ +use pt_bintols::*; +use pt_bintols::display::*; + +#[test] +fn btobin() { + let data = [19, 19]; + let r = bytes_to_bin(&data); + assert_eq!(r, format!("0b00010011_00010011")); +} + +#[test] +fn big_btobin() { + let data = [12,31,82,32,123,32,92,23,12,32,12,1,1,1]; + let r = bytes_to_bin(&data); + assert_eq!(r, format!("0b00001100_00011111_01010010_\ + 00100000_01111011_00100000_01011100_00010111_00001100\n\ + _00100000_00001100_00000001_00000001_00000001")); +} + +#[test] +fn bybit() { + assert_eq!(byte_bit_display(120), format!("120 B = 960 bit")); + assert_eq!(byte_bit_display(12), format!("12 B = 96 bit")); + assert_eq!(byte_bit_display(8), format!("8 B = 64 bit")); +} + +#[test] +fn hmnbytes() { + assert_eq!(humanbytes(0), format!("0 B")); + assert_eq!(humanbytes(1), format!("1 B")); + + assert_eq!(humanbytes(KIBI-1), format!("1023 B")); + assert_eq!(humanbytes(KIBI), format!("1.00 K")); + assert_eq!(humanbytes(KIBI+1), format!("1.00 K")); + + assert_eq!(humanbytes(MEBI-1), format!("1024.00 K")); + assert_eq!(humanbytes(MEBI), format!("1.00 M")); + assert_eq!(humanbytes(MEBI+1), format!("1.00 M")); + + assert_eq!(humanbytes(GIBI-1), format!("1024.00 M")); + assert_eq!(humanbytes(GIBI), format!("1.00 G")); + assert_eq!(humanbytes(GIBI+1), format!("1.00 G")); + + assert_eq!(humanbytes(TEBI-1), format!("1024.00 G")); + assert_eq!(humanbytes(TEBI), format!("1.00 T")); + assert_eq!(humanbytes(TEBI+1), format!("1.00 T")); + + assert_eq!(humanbytes(PEBI-1), format!("1024.00 T")); + assert_eq!(humanbytes(PEBI), format!("1.00 P")); + assert_eq!(humanbytes(PEBI+1), format!("1.00 P")); + + assert_eq!(humanbytes(EXBI-1), format!("1024.00 P")); + assert_eq!(humanbytes(EXBI), format!("1.00 E")); + assert_eq!(humanbytes(EXBI+1), format!("1.00 E")); + + assert_eq!(humanbytes(ZEBI-1), format!("1024.00 E")); + assert_eq!(humanbytes(ZEBI), format!("1.00 Z")); + assert_eq!(humanbytes(ZEBI+1), format!("1.00 Z")); + + assert_eq!(humanbytes(YOBI-1), format!("1024.00 Z")); + assert_eq!(humanbytes(YOBI), format!("1.00 Y")); + assert_eq!(humanbytes(YOBI+1), format!("1.00 Y")); +}