execution_time/traits.rs
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
/// Trait for rounding floating-point numbers to a specified number of decimal places.
pub trait RoundFloat<T> {
/// Rounds the floating-point number to the given number of decimal places.
///
/// # Arguments
///
/// * `decimal_places` - The number of decimal places to round to.
///
/// # Returns
///
/// The rounded floating-point number.
fn round_float(self, decimal_places: T) -> Self
where
Self: std::marker::Sized; // This trait is object safe
}
impl<T> RoundFloat<T> for f64
where
i32: TryFrom<T>,
<i32 as TryFrom<T>>::Error: std::fmt::Display,
{
fn round_float(self, decimal_places: T) -> f64 {
match i32::try_from(decimal_places) {
Ok(dec) => {
if dec <= 0 || self == 0.0 {
self.round()
} else {
let multiplier: f64 = 10.0_f64.powi(dec);
(self * multiplier).round() / multiplier
}
}
Err(why) => {
let t = std::any::type_name::<T>();
eprintln!("fn round_float() for f64: {self}");
eprintln!("Error converting decimal places from type {t} to i32.");
panic!("Invalid Decimal Places: {why}")
}
}
}
}
/// Trait for formatting floating-point values with their units.
pub trait FormatFloatValue {
/// Formats a value with its unit (singular or plural).
///
/// # Arguments
///
/// * `decimal` - The number of decimal places to display.
/// * `singular` - The singular form of the unit.
/// * `plural` - The plural form of the unit.
///
/// # Returns
///
/// A formatted string.
fn format_unit(&self, decimal: usize, singular: &str, plural: &str) -> String;
}
// Implementation of the trait for f64
impl FormatFloatValue for f64 {
fn format_unit(&self, decimal: usize, singular: &str, plural: &str) -> String {
let unit = if *self >= 2.0 { plural } else { singular };
format!("{self:.decimal$} {unit}")
}
}
/// Trait for formatting integer values with their units.
pub trait FormatIntegerValue {
/// Formats a value with its unit (singular or plural).
///
/// # Arguments
///
/// * `singular` - The singular form of the unit.
/// * `plural` - The plural form of the unit.
///
/// # Returns
///
/// A formatted string.
fn format_unit(&self, singular: &str, plural: &str) -> String;
}
// Implementation of the trait for u8
impl FormatIntegerValue for u8 {
fn format_unit(&self, singular: &str, plural: &str) -> String {
let unit = if *self >= 2 { plural } else { singular };
format!("{self} {unit}")
}
}
// Implementation of the trait for u64
impl FormatIntegerValue for u64 {
fn format_unit(&self, singular: &str, plural: &str) -> String {
let unit = if *self >= 2 { plural } else { singular };
format!("{self} {unit}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_integer_formatting() {
assert_eq!(1u64.format_unit("man", "men"), "1 man");
assert_eq!(5u64.format_unit("man", "men"), "5 men");
assert_eq!(1u8.format_unit("apple", "apples"), "1 apple");
assert_eq!(8u8.format_unit("ox", "oxen"), "8 oxen");
}
#[test]
fn test_floating_point_formatting() {
assert_eq!(1.0.format_unit(1, "meter", "meters"), "1.0 meter");
assert_eq!(2.5.format_unit(2, "meter", "meters"), "2.50 meters");
assert_eq!(7.123501.format_unit(3, "foot", "feet"), "7.124 feet");
}
}