Framework for embedding localizations into Rust types
//! Implementations of `Localize` for all primitive number types
//! These just convert to a `Decimal` and then use its implementation

use crate::Localize;

use fixed_decimal::{Decimal, FloatPrecision};
use icu_decimal::{DecimalFormatter, options::DecimalFormatterOptions};
use icu_locale::Locale;

macro_rules! impl_integer {
    ($numeric_type:ty) => {
        impl Localize for $numeric_type {
            fn localize_for(&self, locale: &Locale) -> String {
                let fixed_decimal = Decimal::from(*self);
                fixed_decimal.localize_for(locale)
            }
        }
    };
}

macro_rules! impl_float {
    ($numeric_type:ty) => {
        impl Localize for $numeric_type {
            fn localize_for(&self, locale: &Locale) -> String {
                let fixed_decimal =
                    Decimal::try_from_f64(f64::from(*self), FloatPrecision::RoundTrip).unwrap();
                fixed_decimal.localize_for(locale)
            }
        }
    };
}

impl_integer!(u8);
impl_integer!(u16);
impl_integer!(u32);
impl_integer!(u64);
impl_integer!(u128);
impl_integer!(usize);
impl_integer!(i8);
impl_integer!(i16);
impl_integer!(i32);
impl_integer!(i64);
impl_integer!(i128);
impl_integer!(isize);

impl_float!(f32);
impl_float!(f64);

impl Localize for Decimal {
    fn localize_for(&self, locale: &Locale) -> String {
        let formatter =
            DecimalFormatter::try_new(locale.into(), DecimalFormatterOptions::default()).unwrap();

        let formatted_decimal = formatter.format(self);
        formatted_decimal.to_string()
    }
}