other: add additional clamping functions on numeric types (#1324)

* other: add additional clamping functions on numeric types

* add tests and replace one usage
This commit is contained in:
Clement Tsang 2023-11-19 03:15:19 -05:00 committed by GitHub
parent 7c14aa2666
commit 5a17212f89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 7 deletions

View File

@ -21,6 +21,8 @@ pub use data_type::*;
pub mod sortable;
pub use sortable::*;
use crate::utils::gen_util::ClampExt;
/// A [`DataTable`] is a component that displays data in a tabular form.
///
/// Note that [`DataTable`] takes a generic type `S`, bounded by [`SortType`]. This controls whether this table
@ -120,7 +122,7 @@ impl<DataType: DataToCell<H>, H: ColumnHeader, S: SortType, C: DataTableColumn<H
/// Updates the scroll position to a selected index.
#[allow(clippy::comparison_chain)]
pub fn set_position(&mut self, new_index: usize) {
let new_index = new_index.clamp(0, self.data.len().saturating_sub(1));
let new_index = new_index.clamp_upper(self.data.len().saturating_sub(1));
if self.state.current_index < new_index {
self.state.scroll_direction = ScrollDirection::Down;
} else if self.state.current_index > new_index {

View File

@ -186,6 +186,43 @@ macro_rules! multi_eq_ignore_ascii_case {
};
}
/// A trait for additional clamping functions on numeric types.
pub trait ClampExt {
/// Restrict a value by a lower bound. If the current value is _lower_ than `lower_bound`,
/// it will be set to `_lower_bound`.
fn clamp_lower(&self, lower_bound: Self) -> Self;
/// Restrict a value by an upper bound. If the current value is _greater_ than `upper_bound`,
/// it will be set to `upper_bound`.
fn clamp_upper(&self, upper_bound: Self) -> Self;
}
macro_rules! clamp_num_impl {
( $($NumType:ty),+ $(,)? ) => {
$(
impl ClampExt for $NumType {
fn clamp_lower(&self, lower_bound: Self) -> Self {
if *self < lower_bound {
lower_bound
} else {
*self
}
}
fn clamp_upper(&self, upper_bound: Self) -> Self {
if *self > upper_bound {
upper_bound
} else {
*self
}
}
}
)*
};
}
clamp_num_impl!(u8, u16, u32, u64, usize);
#[cfg(test)]
mod test {
use super::*;
@ -209,7 +246,7 @@ mod test {
}
#[test]
fn test_truncate() {
fn test_truncate_str() {
let cpu_header = "CPU(c)▲";
assert_eq!(
@ -232,7 +269,7 @@ mod test {
}
#[test]
fn test_truncate_cjk() {
fn truncate_cjk() {
let cjk = "施氏食獅史";
assert_eq!(
@ -255,7 +292,7 @@ mod test {
}
#[test]
fn test_truncate_mixed() {
fn truncate_mixed() {
let test = "Test (施氏食獅史) Test";
assert_eq!(
@ -288,7 +325,7 @@ mod test {
}
#[test]
fn test_truncate_flags() {
fn truncate_flags() {
let flag = "🇨🇦";
assert_eq!(truncate_str(flag, 3_usize), flag);
assert_eq!(truncate_str(flag, 2_usize), flag);
@ -331,7 +368,7 @@ mod test {
/// This might not be the best way to handle it, but this at least tests that it doesn't crash...
#[test]
fn test_truncate_hindi() {
fn truncate_hindi() {
// cSpell:disable
let test = "हिन्दी";
assert_eq!(truncate_str(test, 10_usize), test);
@ -346,7 +383,7 @@ mod test {
}
#[test]
fn test_truncate_emoji() {
fn truncate_emoji() {
let heart = "❤️";
assert_eq!(truncate_str(heart, 2_usize), heart);
assert_eq!(truncate_str(heart, 1_usize), heart);
@ -396,4 +433,28 @@ mod test {
"multi non-matching should fail"
);
}
#[test]
fn test_clamp_upper() {
let val: usize = 100;
assert_eq!(val.clamp_upper(150), 100);
let val: usize = 100;
assert_eq!(val.clamp_upper(100), 100);
let val: usize = 100;
assert_eq!(val.clamp_upper(50), 50);
}
#[test]
fn test_clamp_lower() {
let val: usize = 100;
assert_eq!(val.clamp_lower(150), 150);
let val: usize = 100;
assert_eq!(val.clamp_lower(100), 100);
let val: usize = 100;
assert_eq!(val.clamp_lower(50), 100);
}
}