diff --git a/crates/re_format/src/lib.rs b/crates/re_format/src/lib.rs index 8f3a8ecb9eaa..795e42ca5fd9 100644 --- a/crates/re_format/src/lib.rs +++ b/crates/re_format/src/lib.rs @@ -134,7 +134,7 @@ fn test_format_large_number() { /// ``` /// # use re_format::format_bytes; /// assert_eq!(format_bytes(123.0), "123 B"); -/// assert_eq!(format_bytes(12_345.0), "12.1 kiB"); +/// assert_eq!(format_bytes(12_345.0), "12.1 KiB"); /// assert_eq!(format_bytes(1_234_567.0), "1.2 MiB"); /// assert_eq!(format_bytes(123_456_789.0), "118 MiB"); /// ``` @@ -147,7 +147,7 @@ pub fn format_bytes(number_of_bytes: f64) -> String { format!("{number_of_bytes:.0} B") } else if number_of_bytes < 20.0_f64.exp2() { let decimals = (10.0 * number_of_bytes < 20.0_f64.exp2()) as usize; - format!("{:.*} kiB", decimals, number_of_bytes / 10.0_f64.exp2()) + format!("{:.*} KiB", decimals, number_of_bytes / 10.0_f64.exp2()) } else if number_of_bytes < 30.0_f64.exp2() { let decimals = (10.0 * number_of_bytes < 30.0_f64.exp2()) as usize; format!("{:.*} MiB", decimals, number_of_bytes / 20.0_f64.exp2()) @@ -164,12 +164,12 @@ fn test_format_bytes() { (1000.0, "1000 B"), (1001.0, "1001 B"), (1023.0, "1023 B"), - (1024.0, "1.0 kiB"), - (1025.0, "1.0 kiB"), - (1024.0 * 1.2345, "1.2 kiB"), - (1024.0 * 12.345, "12.3 kiB"), - (1024.0 * 123.45, "123 kiB"), - (1024f64.powi(2) - 1.0, "1024 kiB"), + (1024.0, "1.0 KiB"), + (1025.0, "1.0 KiB"), + (1024.0 * 1.2345, "1.2 KiB"), + (1024.0 * 12.345, "12.3 KiB"), + (1024.0 * 123.45, "123 KiB"), + (1024f64.powi(2) - 1.0, "1024 KiB"), (1024f64.powi(2) + 0.0, "1.0 MiB"), (1024f64.powi(2) + 1.0, "1.0 MiB"), (1024f64.powi(3) - 1.0, "1024 MiB"), @@ -182,7 +182,7 @@ fn test_format_bytes() { (1024f64.powi(4) + 0.0, "1024 GiB"), (1024f64.powi(4) + 1.0, "1024 GiB"), (123.0, "123 B"), - (12_345.0, "12.1 kiB"), + (12_345.0, "12.1 KiB"), (1_234_567.0, "1.2 MiB"), (123_456_789.0, "118 MiB"), ]; @@ -193,6 +193,7 @@ fn test_format_bytes() { } pub fn parse_bytes_base10(bytes: &str) -> Option { + // Note: intentionally case sensitive so that we don't parse `Mb` (Megabit) as `MB` (Megabyte). if let Some(kb) = bytes.strip_suffix("kB") { Some(kb.parse::().ok()? * 1_000) } else if let Some(mb) = bytes.strip_suffix("MB") { @@ -231,7 +232,8 @@ fn test_parse_bytes_base10() { } pub fn parse_bytes_base2(bytes: &str) -> Option { - if let Some(kb) = bytes.strip_suffix("kiB") { + // Note: intentionally case sensitive so that we don't parse `Mib` (Mebibit) as `MiB` (Mebibyte). + if let Some(kb) = bytes.strip_suffix("KiB") { Some(kb.parse::().ok()? * 1024) } else if let Some(mb) = bytes.strip_suffix("MiB") { Some(mb.parse::().ok()? * 1024 * 1024) @@ -252,8 +254,8 @@ fn test_parse_bytes_base2() { ("999B", 999), ("1023B", 1_023), ("1024B", 1_024), - ("1kiB", 1_024), - ("1000kiB", 1_000 * 1024), + ("1KiB", 1_024), + ("1000KiB", 1_000 * 1024), ("1MiB", 1024 * 1024), ("1000MiB", 1_000 * 1024 * 1024), ("1GiB", 1024 * 1024 * 1024), @@ -261,7 +263,7 @@ fn test_parse_bytes_base2() { ("1TiB", 1024 * 1024 * 1024 * 1024), ("1000TiB", 1_000 * 1024 * 1024 * 1024 * 1024), ("123B", 123), - ("12kiB", 12 * 1024), + ("12KiB", 12 * 1024), ("123MiB", 123 * 1024 * 1024), ]; for (value, expected) in test_cases { @@ -294,8 +296,8 @@ fn test_parse_bytes() { ("999B", 999), ("1023B", 1_023), ("1024B", 1_024), - ("1kiB", 1_024), - ("1000kiB", 1_000 * 1024), + ("1KiB", 1_024), + ("1000KiB", 1_000 * 1024), ("1MiB", 1024 * 1024), ("1000MiB", 1_000 * 1024 * 1024), ("1GiB", 1024 * 1024 * 1024), @@ -303,7 +305,7 @@ fn test_parse_bytes() { ("1TiB", 1024 * 1024 * 1024 * 1024), ("1000TiB", 1_000 * 1024 * 1024 * 1024 * 1024), ("123B", 123), - ("12kiB", 12 * 1024), + ("12KiB", 12 * 1024), ("123MiB", 123 * 1024 * 1024), ]; for (value, expected) in test_cases { diff --git a/crates/re_log_types/src/lib.rs b/crates/re_log_types/src/lib.rs index 36526feac807..a0788451545e 100644 --- a/crates/re_log_types/src/lib.rs +++ b/crates/re_log_types/src/lib.rs @@ -272,7 +272,7 @@ impl StoreInfo { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct PythonVersion { /// e.g. 3 @@ -288,6 +288,12 @@ pub struct PythonVersion { pub suffix: String, } +impl std::fmt::Debug for PythonVersion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} + impl std::fmt::Display for PythonVersion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Self { diff --git a/crates/rerun/src/run.rs b/crates/rerun/src/run.rs index 4001248afcb0..9045d1b10fbc 100644 --- a/crates/rerun/src/run.rs +++ b/crates/rerun/src/run.rs @@ -10,6 +10,7 @@ use re_smart_channel::{ReceiveSet, Receiver, SmartMessagePayload}; #[cfg(feature = "web_viewer")] use re_sdk::web_viewer::host_web_viewer; +use re_types::SizeBytes; #[cfg(feature = "web_viewer")] use re_web_viewer_server::WebViewerServerPort; #[cfg(feature = "server")] @@ -241,7 +242,7 @@ enum Command { }, /// Print the contents of an .rrd file. - Print { rrd_path: String }, + Print(PrintCommand), /// Reset the memory of the Rerun Viewer. /// @@ -253,6 +254,15 @@ enum Command { Reset, } +#[derive(Debug, Clone, clap::Parser)] +struct PrintCommand { + rrd_path: String, + + /// If specified, print out table contents. + #[clap(long, short, default_value_t = false)] + verbose: bool, +} + #[derive(Debug, Clone, Subcommand)] enum AnalyticsCommands { /// Prints extra information about analytics. @@ -368,10 +378,7 @@ where run_compare(&path_to_rrd1, &path_to_rrd2, *full_dump) } - Command::Print { rrd_path } => { - let rrd_path = PathBuf::from(&rrd_path); - print_rrd(&rrd_path).with_context(|| format!("path: {rrd_path:?}")) - } + Command::Print(print_command) => print_command.run(), #[cfg(feature = "native_viewer")] Command::Reset => reset_viewer(), @@ -486,25 +493,56 @@ fn run_compare(path_to_rrd1: &Path, path_to_rrd2: &Path, full_dump: bool) -> any re_log_types::DataTable::similar(&table1, &table2) } -fn print_rrd(rrd_path: &Path) -> anyhow::Result<()> { - let rrd_file = std::fs::File::open(rrd_path)?; - let version_policy = re_log_encoding::decoder::VersionPolicy::Error; - let decoder = re_log_encoding::decoder::Decoder::new(version_policy, rrd_file)?; - for msg in decoder { - let msg = msg.context("decode rrd message")?; - match msg { - LogMsg::SetStoreInfo(msg) => { - let SetStoreInfo { row_id: _, info } = msg; - println!("{info:#?}"); - } - LogMsg::ArrowMsg(_row_id, arrow_msg) => { - let table = - DataTable::from_arrow_msg(&arrow_msg).context("Decode arrow message")?; - println!("{table}"); +impl PrintCommand { + fn run(&self) -> anyhow::Result<()> { + let rrd_path = PathBuf::from(&self.rrd_path); + self.print_rrd(&rrd_path) + .with_context(|| format!("path: {rrd_path:?}")) + } + + fn print_rrd(&self, rrd_path: &Path) -> anyhow::Result<()> { + let Self { + rrd_path: _, + verbose, + } = self; + + let rrd_file = std::fs::File::open(rrd_path)?; + let version_policy = re_log_encoding::decoder::VersionPolicy::Warn; + let decoder = re_log_encoding::decoder::Decoder::new(version_policy, rrd_file)?; + for msg in decoder { + let msg = msg.context("decode rrd message")?; + match msg { + LogMsg::SetStoreInfo(msg) => { + let SetStoreInfo { row_id: _, info } = msg; + println!("{info:#?}"); + } + LogMsg::ArrowMsg(_row_id, arrow_msg) => { + let mut table = + DataTable::from_arrow_msg(&arrow_msg).context("Decode arrow message")?; + + if *verbose { + println!("{table}"); + } else { + table.compute_all_size_bytes(); + + let column_names = table + .columns + .keys() + .map(|name| name.short_name()) + .collect_vec(); + + println!( + "Table with {} rows ({}). Columns: {:?}", + table.num_rows(), + re_format::format_bytes(table.heap_size_bytes() as _), + column_names + ); + } + } } } + Ok(()) } - Ok(()) } #[cfg(feature = "analytics")]