use crate::data::Value;
pub use crate::locale::{CurrencyPosition, Locale};
pub use crate::scale::format::{
label_bytes, label_comma, label_comma_locale, label_comma_marks, label_currency,
label_currency_locale, label_currency_marks, label_dollar, label_number, label_number_locale,
label_number_marks, label_ordinal, label_percent, label_percent_locale, label_percent_marks,
label_scientific, label_si, LabelFormatter,
};
pub fn format_value(v: &Value) -> String {
match v {
Value::Str(s) => s.clone(),
Value::Bool(b) => b.to_string(),
Value::Na => String::new(),
Value::DateTime(secs) => crate::data::format_epoch_secs(*secs),
_ => v
.as_f64()
.map(|f| format!("{}", (f * 1000.0).round() / 1000.0))
.unwrap_or_default(),
}
}
pub fn format_value_locale(v: &Value, locale: &Locale) -> String {
match v {
Value::DateTime(secs) => locale.format_datetime(*secs),
Value::Str(_) | Value::Bool(_) | Value::Na => format_value(v),
_ => locale.localize_number(&format_value(v)),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn formats_each_variant() {
assert_eq!(format_value(&Value::Str("a<b".into())), "a<b");
assert_eq!(format_value(&Value::Bool(true)), "true");
assert_eq!(format_value(&Value::Integer(-42)), "-42");
assert_eq!(format_value(&Value::Float(2.0)), "2");
assert_eq!(format_value(&Value::Float(0.12345)), "0.123");
assert_eq!(format_value(&Value::DateTime(3_661)), "1970-01-01 01:01:01");
assert_eq!(format_value(&Value::Na), "");
}
#[test]
fn formats_each_variant_with_locale() {
let de = Locale::de_de();
assert_eq!(format_value_locale(&Value::Str("1.5".into()), &de), "1.5");
assert_eq!(format_value_locale(&Value::Integer(-4200), &de), "-4.200");
assert_eq!(format_value_locale(&Value::Float(0.5), &de), "0,5");
assert_eq!(format_value_locale(&Value::Na, &de), "");
assert_eq!(
format_value_locale(&Value::DateTime(1_792_022_400), &Locale::en_us()),
"Oct 15, 2026"
);
assert_eq!(
format_value_locale(&Value::Float(1234.5), &Locale::en_us()),
"1,234.5"
);
}
}