#[derive(Debug)]
pub struct PriceComma<T> {
data: T,
result: String,
}
trait Formatter {
fn fmt_number(&self) -> String;
fn big_num_i64_str(&self) -> String;
fn fmt_num_f64_str(&self) -> String;
fn fmt_num_str(&self) -> String;
}
impl<T> PriceComma<T> {
fn new(data: T, result: String) -> Self {
Self { data, result }
}
fn push(&mut self, data: T) {
self.data = data;
}
}
impl<T: Default> Default for PriceComma<T> {
fn default() -> Self {
Self::new(T::default(), String::new())
}
}
impl<T: ToString> Formatter for PriceComma<T> {
fn fmt_number(&self) -> String {
let mut formatted_number = String::new();
let mut count = 0;
let number_convert = self.data.to_string();
let (num_str, is_negative) = if number_convert.starts_with('-') {
(&number_convert[1..], true)
} else {
(number_convert.as_str(), false)
};
for c in num_str.chars().rev() {
if count == 3 {
formatted_number.push(',');
count = 0;
}
formatted_number.push(c);
count += 1;
}
let mut result = formatted_number.chars().rev().collect::<String>();
if is_negative {
result.insert(0, '-');
}
result
}
fn big_num_i64_str(&self) -> String {
let mut formatted_number = String::new();
let mut count = 0;
let number_convert = self.data.to_string();
let (num_str, is_negative) = if number_convert.starts_with('-') {
(&number_convert[1..], true)
} else {
(number_convert.as_str(), false)
};
for c in num_str.chars().rev() {
if count == 3 {
formatted_number.push(',');
count = 0;
}
formatted_number.push(c);
count += 1;
}
let mut result = formatted_number.chars().rev().collect::<String>();
if is_negative {
result.insert(0, '-');
}
result
}
fn fmt_num_f64_str(&self) -> String {
let mut formatted_number = String::new();
let mut count = 0;
let number_convert = self.data.to_string();
let mut number_point_raw = number_convert.split('.');
let integer_part = number_point_raw.next().unwrap();
let decimal_part = number_point_raw.next().unwrap_or("00");
let (int_str, is_negative) = if integer_part.starts_with('-') {
(&integer_part[1..], true)
} else {
(integer_part, false)
};
for c in int_str.chars().rev() {
if count == 3 {
formatted_number.push(',');
count = 0;
}
formatted_number.push(c);
count += 1;
}
let mut result = formatted_number.chars().rev().collect::<String>();
if is_negative {
result.insert(0, '-');
}
result.push('.');
result.push_str(decimal_part);
result
}
fn fmt_num_str(&self) -> String {
let number = self.data.to_string();
let mut formatted_number = String::new();
let mut count = 0;
let (num_str, is_negative) = if number.starts_with('-') {
(&number[1..], true)
} else {
(number.as_str(), false)
};
for c in num_str.chars().rev() {
if count == 3 {
formatted_number.push(',');
count = 0;
}
formatted_number.push(c);
count += 1;
}
let mut result = formatted_number.chars().rev().collect::<String>();
if is_negative {
result.insert(0, '-');
}
result
}
}
pub fn fprice<T: ToString>(value: T) -> String {
let pc = PriceComma::new(value, String::new());
pc.fmt_number()
}
pub fn fprice_float<T: ToString>(value: T) -> String {
let pc = PriceComma::new(value, String::new());
pc.fmt_num_f64_str()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_positive_numbers() {
assert_eq!(fprice(123), "123");
assert_eq!(fprice(1234), "1,234");
assert_eq!(fprice(1234567), "1,234,567");
assert_eq!(fprice(1234567890), "1,234,567,890");
}
#[test]
fn test_negative_numbers() {
assert_eq!(fprice(-123), "-123");
assert_eq!(fprice(-1234), "-1,234");
assert_eq!(fprice(-1234567), "-1,234,567");
assert_eq!(fprice(-1234567890), "-1,234,567,890");
}
#[test]
fn test_fprice_float() {
assert_eq!(fprice_float(123.45), "123.45");
assert_eq!(fprice_float(1234.56), "1,234.56");
assert_eq!(fprice_float(1234567.89), "1,234,567.89");
}
#[test]
fn test_fprice_float_negative() {
assert_eq!(fprice_float(-123.45), "-123.45");
assert_eq!(fprice_float(-1234.56), "-1,234.56");
assert_eq!(fprice_float(-1234567.89), "-1,234,567.89");
}
}