use crate::types::{Rate, Real, Size, Volatility};
use crate::utilities::null::Null;
pub fn check_null<T: Null + std::fmt::Display>(value: T) -> String {
if value.is_null() {
"null".to_string()
} else {
value.to_string()
}
}
pub fn ordinal(n: Size) -> String {
let suffix = match (n % 10, n % 100) {
(1, 11) | (2, 12) | (3, 13) => "th",
(1, _) => "st",
(2, _) => "nd",
(3, _) => "rd",
_ => "th",
};
format!("{n}{suffix}")
}
pub fn percent(value: Real) -> String {
format!("{:.6} %", value * 100.0)
}
pub fn rate(r: Rate) -> String {
percent(r)
}
pub fn volatility(v: Volatility) -> String {
percent(v)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::Integer;
#[test]
fn check_null_emits_null_for_sentinel() {
assert_eq!(check_null(Integer::MAX), "null");
assert_eq!(check_null(7_i32), "7");
}
#[test]
fn ordinals() {
assert_eq!(ordinal(1), "1st");
assert_eq!(ordinal(2), "2nd");
assert_eq!(ordinal(3), "3rd");
assert_eq!(ordinal(4), "4th");
assert_eq!(ordinal(11), "11th");
assert_eq!(ordinal(12), "12th");
assert_eq!(ordinal(13), "13th");
assert_eq!(ordinal(21), "21st");
assert_eq!(ordinal(112), "112th");
}
#[test]
fn percentages() {
assert_eq!(percent(0.05), "5.000000 %");
assert_eq!(rate(0.05), "5.000000 %");
assert_eq!(volatility(0.2), "20.000000 %");
}
}