Experimenting with more structured ways to handle command-line input/output in Rust
use crate::Localize;

use duplicate::duplicate_item;
use fixed_decimal::{Decimal, FloatPrecision};
use icu_decimal::{options::DecimalFormatterOptions, DecimalFormatter};
use icu_locale::{langid, LanguageIdentifier};

// Implementations of `Localize` for all primitive number types
// These just convert to a `Decimal` and then use its implementation
#[duplicate_item(
    type_name conversion;
    [u8]      [Decimal::from(*self)];
    [u16]     [Decimal::from(*self)];
    [u32]     [Decimal::from(*self)];
    [u64]     [Decimal::from(*self)];
    [u128]    [Decimal::from(*self)];
    [usize]   [Decimal::from(*self)];
    
    [i8]      [Decimal::from(*self)];
    [i16]     [Decimal::from(*self)];
    [i32]     [Decimal::from(*self)];
    [i64]     [Decimal::from(*self)];
    [i128]    [Decimal::from(*self)];
    [isize]   [Decimal::from(*self)];

    [f32]     [Decimal::try_from_f64(*self as f64, FloatPrecision::RoundTrip).unwrap()];
    [f64]     [Decimal::try_from_f64(*self, FloatPrecision::RoundTrip).unwrap()];
)]
impl<W: std::io::Write> Localize<W> for type_name {
    const CANONICAL_LOCALE: LanguageIdentifier = langid!("en-US");

    fn available_locales(&self) -> Vec<LanguageIdentifier> {
        // TODO: keep track of all locales with Fluent data, and return only those
        vec![<Self as Localize<W>>::CANONICAL_LOCALE]
    }

    fn message_for_locale(
        &self,
        writer: &mut W,
        locale: &LanguageIdentifier,
    ) -> Result<(), crate::LocalizationError> {
        let fixed_decimal = conversion;
        fixed_decimal.message_for_locale(writer, locale)
    }
}

impl<W: std::io::Write> Localize<W> for Decimal {
    const CANONICAL_LOCALE: LanguageIdentifier = langid!("en-US");

    fn available_locales(&self) -> Vec<LanguageIdentifier> {
        // TODO: keep track of all locales with Fluent data, and return only those
        vec![<Self as Localize<W>>::CANONICAL_LOCALE]
    }

    fn message_for_locale(
        &self,
        writer: &mut W,
        locale: &LanguageIdentifier,
    ) -> Result<(), crate::LocalizationError> {
        let formatter =
            DecimalFormatter::try_new(locale.into(), DecimalFormatterOptions::default())
                .unwrap();

        let formatted_decimal = formatter.format(self);
        writer.write_all(formatted_decimal.to_string().as_bytes())?;
        Ok(())
    }
}