From de681d44840e694ff7339aabe78032ed0ae66a1e Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 3 Apr 2024 10:18:46 +0200 Subject: [PATCH 1/2] re_format: add general `format_int` function --- crates/re_format/src/lib.rs | 81 +++++++++++++++++++---- crates/re_log_types/src/time_point/mod.rs | 2 +- crates/re_time_panel/src/paint_ticks.rs | 2 +- 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/crates/re_format/src/lib.rs b/crates/re_format/src/lib.rs index 4a0ecc78cc8a..939578539c87 100644 --- a/crates/re_format/src/lib.rs +++ b/crates/re_format/src/lib.rs @@ -7,6 +7,8 @@ pub mod arrow; mod time; +use std::{cmp::PartialOrd, fmt::Display}; + pub use time::next_grid_tick_magnitude_ns; // --- Numbers --- @@ -16,30 +18,85 @@ pub use time::next_grid_tick_magnitude_ns; /// Looks slightly different from the normal hyphen `-`. const MINUS: char = '−'; -/// Pretty format an unsigned integer by using thousands separators for readability. -/// -/// The returned value is for human eyes only, and can not be parsed -/// by the normal `usize::from_str` function. -pub fn format_uint(number: Uint) -> String -where - Uint: Copy + num_traits::Unsigned + std::fmt::Display, -{ - add_thousands_separators(&number.to_string()) +// TODO(rust-num/num-traits#315): waiting for https://github.com/rust-num/num-traits/issues/315 to land +pub trait UnsignedAbs { + /// An unsigned type which is large enough to hold the absolute value of `Self`. + type Unsigned; + + /// Computes the absolute value of `self` without any wrapping or panicking. + fn unsigned_abs(self) -> Self::Unsigned; +} + +impl UnsignedAbs for i8 { + type Unsigned = u8; + fn unsigned_abs(self) -> Self::Unsigned { + self.unsigned_abs() + } +} + +impl UnsignedAbs for i16 { + type Unsigned = u16; + fn unsigned_abs(self) -> Self::Unsigned { + self.unsigned_abs() + } +} + +impl UnsignedAbs for i32 { + type Unsigned = u32; + fn unsigned_abs(self) -> Self::Unsigned { + self.unsigned_abs() + } +} + +impl UnsignedAbs for i64 { + type Unsigned = u64; + fn unsigned_abs(self) -> Self::Unsigned { + self.unsigned_abs() + } +} + +impl UnsignedAbs for i128 { + type Unsigned = u128; + fn unsigned_abs(self) -> Self::Unsigned { + self.unsigned_abs() + } +} + +impl UnsignedAbs for isize { + type Unsigned = usize; + fn unsigned_abs(self) -> Self::Unsigned { + self.unsigned_abs() + } } /// Pretty format a signed number by using thousands separators for readability. /// /// The returned value is for human eyes only, and can not be parsed /// by the normal `usize::from_str` function. -pub fn format_i64(number: i64) -> String { - if number < 0 { - // TODO(rust-num/num-traits#315): generalize this to all signed integers once https://github.com/rust-num/num-traits/issues/315 lands +pub fn format_int(number: Int) -> String +where + Int: Display + PartialOrd + num_traits::Zero + UnsignedAbs, + Int::Unsigned: Display + num_traits::Unsigned, +{ + if number < Int::zero() { format!("{MINUS}{}", format_uint(number.unsigned_abs())) } else { add_thousands_separators(&number.to_string()) } } +/// Pretty format an unsigned integer by using thousands separators for readability. +/// +/// The returned value is for human eyes only, and can not be parsed +/// by the normal `usize::from_str` function. +#[allow(clippy::needless_pass_by_value)] +pub fn format_uint(number: Uint) -> String +where + Uint: Display + num_traits::Unsigned, +{ + add_thousands_separators(&number.to_string()) +} + /// Add thousands separators to a number, every three steps, /// counting from the last character. fn add_thousands_separators(number: &str) -> String { diff --git a/crates/re_log_types/src/time_point/mod.rs b/crates/re_log_types/src/time_point/mod.rs index b6c0ad94eea7..bdd4e8f4081b 100644 --- a/crates/re_log_types/src/time_point/mod.rs +++ b/crates/re_log_types/src/time_point/mod.rs @@ -139,7 +139,7 @@ impl TimeType { } else { match self { Self::Time => Time::from(time_int).format(time_zone_for_timestamps), - Self::Sequence => format!("#{}", re_format::format_i64(time_int.0)), + Self::Sequence => format!("#{}", re_format::format_int(time_int.0)), } } } diff --git a/crates/re_time_panel/src/paint_ticks.rs b/crates/re_time_panel/src/paint_ticks.rs index 1d3e7b778555..a10d4a6702ff 100644 --- a/crates/re_time_panel/src/paint_ticks.rs +++ b/crates/re_time_panel/src/paint_ticks.rs @@ -92,7 +92,7 @@ fn paint_time_range_ticks( &ui.clip_rect(), time_range, next_power_of_10, - |seq| format!("#{}", re_format::format_i64(seq)), + |seq| format!("#{}", re_format::format_int(seq)), ) } } From b55246f04976986ca8ffac7b72963eae454e374b Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 3 Apr 2024 10:24:53 +0200 Subject: [PATCH 2/2] Add `#[inline]` to all `unsigned_abs` implementations --- crates/re_format/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/re_format/src/lib.rs b/crates/re_format/src/lib.rs index 939578539c87..778fb6beac39 100644 --- a/crates/re_format/src/lib.rs +++ b/crates/re_format/src/lib.rs @@ -29,6 +29,8 @@ pub trait UnsignedAbs { impl UnsignedAbs for i8 { type Unsigned = u8; + + #[inline] fn unsigned_abs(self) -> Self::Unsigned { self.unsigned_abs() } @@ -36,6 +38,8 @@ impl UnsignedAbs for i8 { impl UnsignedAbs for i16 { type Unsigned = u16; + + #[inline] fn unsigned_abs(self) -> Self::Unsigned { self.unsigned_abs() } @@ -43,6 +47,8 @@ impl UnsignedAbs for i16 { impl UnsignedAbs for i32 { type Unsigned = u32; + + #[inline] fn unsigned_abs(self) -> Self::Unsigned { self.unsigned_abs() } @@ -50,6 +56,8 @@ impl UnsignedAbs for i32 { impl UnsignedAbs for i64 { type Unsigned = u64; + + #[inline] fn unsigned_abs(self) -> Self::Unsigned { self.unsigned_abs() } @@ -57,6 +65,8 @@ impl UnsignedAbs for i64 { impl UnsignedAbs for i128 { type Unsigned = u128; + + #[inline] fn unsigned_abs(self) -> Self::Unsigned { self.unsigned_abs() } @@ -64,6 +74,8 @@ impl UnsignedAbs for i128 { impl UnsignedAbs for isize { type Unsigned = usize; + + #[inline] fn unsigned_abs(self) -> Self::Unsigned { self.unsigned_abs() }