Replace `duplicate` macro with `macro_rules!`

finchie
Jun 30, 2025, 7:56 AM
QM64L3XOUB74M2D7TXDJWXGJNQN46IMF22Y24VNFQ5FEWODLVBLAC

Dependencies

  • [2] NEBSVXIA Apply Clippy fixes
  • [3] WWDZWJTR Implement `Localize` for string types
  • [4] GJMBIJOE Migrate to latest env_preferences version
  • [5] LYZBTYIW Replace `proc-macro-error` with `proc-macro-error2`
  • [6] JUV7C6ET Create initial prototype of `fluent_embed_interaction`
  • [7] FDFI4WMO Do not expand macro by default when using `fluent_embed`
  • [8] XGRU7WZE Add `expand` feature for proc-macro debugging
  • [9] 7M4UI3TW Update dependencies to latest versions
  • [10] LU6IFZFG Remove `std::io::Write` trait bound from `Localize`
  • [11] TIPBMFLW Migrate to edition 2024
  • [12] QJC4IQIT Refactor `Localize` functions to infallibly return `String`
  • [13] BFL2Y7GN Add relative timestamps using `jiff` and `icu_relativetime`
  • [14] C6W7N6N5 Implement `Localize` for `FixedDecimal` and primitive number types
  • [15] HHJDRLLN Create `fluent_embed_runtime` crate
  • [16] 3NMKD6I5 Refactor `Localize` trait to use `std::io::Write`
  • [17] 7X4MEZJU Use Fluent AST when reporting error spans
  • [18] VQBJBFEX Improve error handling for missing Fluent messages
  • [19] VZYZRAO4 Move `output-macros` crate into workspace
  • [*] UKFEFT6L Create basic `Output` proc-macro

Change contents

  • edit in fluent_embed/src/string.rs at line 6
    [3.139][3.139:170]()
    use duplicate::duplicate_item;
  • replacement in fluent_embed/src/string.rs at line 8
    [3.216][3.216:314](),[3.314][3.593:623](),[3.623][3.366:433](),[3.366][3.366:433]()
    #[duplicate_item(
    type_name;
    [String];
    [&str];
    [Box<str>];
    [Cow<'_, str>];
    )]
    impl Localize for type_name {
    const CANONICAL_LOCALE: LanguageIdentifier = langid!("en-US");
    [3.216]
    [3.433]
    macro_rules! impl_string {
    ($string_type:ty) => {
    impl Localize for $string_type {
    const CANONICAL_LOCALE: LanguageIdentifier = langid!("en-US");
  • replacement in fluent_embed/src/string.rs at line 13
    [3.434][3.434:578](),[3.578][3.624:661](),[3.661][3.632:638](),[3.632][3.632:638]()
    fn available_locales(&self) -> Vec<LanguageIdentifier> {
    // TODO: keep track of all locales with Fluent data, and return only those
    vec![Self::CANONICAL_LOCALE]
    }
    [3.434]
    [3.638]
    fn available_locales(&self) -> Vec<LanguageIdentifier> {
    // TODO: keep track of all locales with Fluent data, and return only those
    vec![Self::CANONICAL_LOCALE]
    }
  • replacement in fluent_embed/src/string.rs at line 18
    [3.639][3.1980:2055](),[3.2055][2.2489:2517](),[3.2080][3.850:856](),[2.2517][3.850:856](),[3.850][3.850:856]()
    fn message_for_locale(&self, _locale: &LanguageIdentifier) -> String {
    (*self).to_string()
    }
    [3.639]
    [3.856]
    fn message_for_locale(&self, _locale: &LanguageIdentifier) -> String {
    (*self).to_string()
    }
    }
    };
  • edit in fluent_embed/src/string.rs at line 24
    [3.858]
    impl_string!(String);
    impl_string!(&str);
    impl_string!(Box<str>);
    impl_string!(Cow<'_, str>);
  • edit in fluent_embed/src/decimal.rs at line 1
    [3.2537]
    [3.2538]
    //! Implementations of `Localize` for all primitive number types
    //! These just convert to a `Decimal` and then use its implementation
  • edit in fluent_embed/src/decimal.rs at line 6
    [3.2560][3.2560:2591]()
    use duplicate::duplicate_item;
  • replacement in fluent_embed/src/decimal.rs at line 7
    [3.4120][3.4120:4237]()
    use icu_decimal::{options::DecimalFormatterOptions, DecimalFormatter};
    use icu_locale::{langid, LanguageIdentifier};
    [3.4120]
    [3.2824]
    use icu_decimal::{DecimalFormatter, options::DecimalFormatterOptions};
    use icu_locale::{LanguageIdentifier, langid};
    macro_rules! impl_integer {
    ($numeric_type:ty) => {
    impl Localize for $numeric_type {
    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::CANONICAL_LOCALE]
    }
  • replacement in fluent_embed/src/decimal.rs at line 20
    [3.2825][3.2825:2889](),[3.2889][3.4238:4307](),[3.4307][3.2963:3007](),[3.2963][3.2963:3007](),[3.3007][3.4308:4536](),[3.4536][3.3265:3270](),[3.3265][3.3265:3270](),[3.3270][3.4537:4765]()
    // 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)];
    [3.2825]
    [3.3528]
    fn message_for_locale(&self, locale: &LanguageIdentifier) -> String {
    let fixed_decimal = Decimal::from(*self);
    fixed_decimal.message_for_locale(locale)
    }
    }
    };
    }
  • replacement in fluent_embed/src/decimal.rs at line 28
    [3.3529][2.2518:2611](),[2.2611][3.4855:4937](),[3.4855][3.4855:4937](),[3.4937][3.3708:3711](),[3.3708][3.3708:3711](),[3.3711][3.872:902](),[3.902][3.3763:3830](),[3.3763][3.3763:3830]()
    [f32] [Decimal::try_from_f64(f64::from(*self), FloatPrecision::RoundTrip).unwrap()];
    [f64] [Decimal::try_from_f64(*self, FloatPrecision::RoundTrip).unwrap()];
    )]
    impl Localize for type_name {
    const CANONICAL_LOCALE: LanguageIdentifier = langid!("en-US");
    [3.3529]
    [3.3830]
    macro_rules! impl_float {
    ($numeric_type:ty) => {
    impl Localize for $numeric_type {
    const CANONICAL_LOCALE: LanguageIdentifier = langid!("en-US");
  • replacement in fluent_embed/src/decimal.rs at line 33
    [3.3831][3.3831:3975](),[3.3975][3.903:940](),[3.940][3.4029:4035](),[3.4029][3.4029:4035]()
    fn available_locales(&self) -> Vec<LanguageIdentifier> {
    // TODO: keep track of all locales with Fluent data, and return only those
    vec![Self::CANONICAL_LOCALE]
    }
    [3.3831]
    [3.4035]
    fn available_locales(&self) -> Vec<LanguageIdentifier> {
    // TODO: keep track of all locales with Fluent data, and return only those
    vec![Self::CANONICAL_LOCALE]
    }
  • replacement in fluent_embed/src/decimal.rs at line 38
    [3.4036][3.2328:2355](),[3.987][3.4063:4078](),[3.2355][3.4063:4078](),[3.4063][3.4063:4078](),[3.4102][3.4102:4139](),[3.4139][3.2356:2374](),[3.2374][3.4187:4227](),[3.4187][3.4187:4227](),[3.4227][3.2375:2424](),[3.2424][3.4284:4290](),[3.4284][3.4284:4290]()
    fn message_for_locale(
    &self,
    locale: &LanguageIdentifier,
    ) -> String {
    let fixed_decimal = conversion;
    fixed_decimal.message_for_locale(locale)
    }
    [3.4036]
    [3.4290]
    fn message_for_locale(&self, locale: &LanguageIdentifier) -> String {
    let fixed_decimal =
    Decimal::try_from_f64(f64::from(*self), FloatPrecision::RoundTrip).unwrap();
    fixed_decimal.message_for_locale(locale)
    }
    }
    };
  • edit in fluent_embed/src/decimal.rs at line 46
    [3.4292]
    [3.4292]
    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);
  • replacement in fluent_embed/src/decimal.rs at line 71
    [3.4621][3.2425:2452](),[3.1101][3.4648:4663](),[3.2452][3.4648:4663](),[3.4648][3.4648:4663](),[3.4687][3.4687:4724](),[3.4724][3.2453:2471]()
    fn message_for_locale(
    &self,
    locale: &LanguageIdentifier,
    ) -> String {
    [3.4621]
    [3.4824]
    fn message_for_locale(&self, locale: &LanguageIdentifier) -> String {
  • replacement in fluent_embed/src/decimal.rs at line 73
    [3.4848][3.4989:5078](),[3.5078][3.4946:4973](),[3.4946][3.4946:4973]()
    DecimalFormatter::try_new(locale.into(), DecimalFormatterOptions::default())
    .unwrap();
    [3.4848]
    [3.4973]
    DecimalFormatter::try_new(locale.into(), DecimalFormatterOptions::default()).unwrap();
  • edit in fluent_embed/Cargo.toml at line 10
    [3.1196][3.5149:5176]()
    duplicate.workspace = true
  • edit in Cargo.toml at line 11
    [3.11820][3.5579:5599](),[3.5579][3.5579:5599]()
    duplicate = "2.0.0"
  • edit in Cargo.lock at line 212
    [3.7155][3.7155:7420]()
    name = "duplicate"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "97af9b5f014e228b33e77d75ee0e6e87960124f0f4b16337b586a6bec91867b1"
    dependencies = [
    "heck",
    "proc-macro2",
    "proc-macro2-diagnostics",
    ]
    [[package]]
  • edit in Cargo.lock at line 316
    [3.9112][3.9112:9126]()
    "duplicate",
  • edit in Cargo.lock at line 1185
    [3.29587][3.29587:29825](),[3.29825][3.556:564](),[3.564][3.29840:29883](),[3.29840][3.29840:29883]()
    name = "proc-macro2-diagnostics"
    version = "0.10.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    "version_check",
    "yansi",
    ]
    [[package]]