1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

#[diplomat::bridge]
pub mod ffi {
    use alloc::boxed::Box;
    use icu_decimal::{
        options::{FixedDecimalFormatterOptions, GroupingStrategy},
        provider::DecimalSymbolsV1Marker,
        FixedDecimalFormatter,
    };
    use icu_provider_adapters::any_payload::AnyPayloadProvider;
    use writeable::Writeable;

    use crate::{
        data_struct::ffi::ICU4XDataStruct, errors::ffi::ICU4XError,
        fixed_decimal::ffi::ICU4XFixedDecimal, locale::ffi::ICU4XLocale,
        provider::ffi::ICU4XDataProvider,
    };

    #[diplomat::opaque]
    /// An ICU4X Fixed Decimal Format object, capable of formatting a [`ICU4XFixedDecimal`] as a string.
    #[diplomat::rust_link(icu::decimal::FixedDecimalFormatter, Struct)]
    #[diplomat::rust_link(icu::datetime::FormattedFixedDecimal, Struct, hidden)]
    pub struct ICU4XFixedDecimalFormatter(pub FixedDecimalFormatter);

    #[diplomat::rust_link(icu::decimal::options::GroupingStrategy, Enum)]
    pub enum ICU4XFixedDecimalGroupingStrategy {
        Auto,
        Never,
        Always,
        Min2,
    }

    impl ICU4XFixedDecimalFormatter {
        /// Creates a new [`ICU4XFixedDecimalFormatter`] from locale data.
        #[diplomat::rust_link(icu::decimal::FixedDecimalFormatter::try_new, FnInStruct)]
        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "with_grouping_strategy")]
        pub fn create_with_grouping_strategy(
            provider: &ICU4XDataProvider,
            locale: &ICU4XLocale,
            grouping_strategy: ICU4XFixedDecimalGroupingStrategy,
        ) -> Result<Box<ICU4XFixedDecimalFormatter>, ICU4XError> {
            let locale = locale.to_datalocale();

            let grouping_strategy = match grouping_strategy {
                ICU4XFixedDecimalGroupingStrategy::Auto => GroupingStrategy::Auto,
                ICU4XFixedDecimalGroupingStrategy::Never => GroupingStrategy::Never,
                ICU4XFixedDecimalGroupingStrategy::Always => GroupingStrategy::Always,
                ICU4XFixedDecimalGroupingStrategy::Min2 => GroupingStrategy::Min2,
            };
            let mut options = FixedDecimalFormatterOptions::default();
            options.grouping_strategy = grouping_strategy;
            Ok(Box::new(ICU4XFixedDecimalFormatter(call_constructor!(
                FixedDecimalFormatter::try_new,
                FixedDecimalFormatter::try_new_with_any_provider,
                FixedDecimalFormatter::try_new_with_buffer_provider,
                provider,
                &locale,
                options,
            )?)))
        }

        /// Creates a new [`ICU4XFixedDecimalFormatter`] from preconstructed locale data in the form of an [`ICU4XDataStruct`]
        /// constructed from `ICU4XDataStruct::create_decimal_symbols()`.
        ///
        /// The contents of the data struct will be consumed: if you wish to use the struct again it will have to be reconstructed.
        /// Passing a consumed struct to this method will return an error.
        #[diplomat::attr(*, disable)]
        pub fn create_with_decimal_symbols_v1(
            data_struct: &ICU4XDataStruct,
            grouping_strategy: ICU4XFixedDecimalGroupingStrategy,
        ) -> Result<Box<ICU4XFixedDecimalFormatter>, ICU4XError> {
            let grouping_strategy = match grouping_strategy {
                ICU4XFixedDecimalGroupingStrategy::Auto => GroupingStrategy::Auto,
                ICU4XFixedDecimalGroupingStrategy::Never => GroupingStrategy::Never,
                ICU4XFixedDecimalGroupingStrategy::Always => GroupingStrategy::Always,
                ICU4XFixedDecimalGroupingStrategy::Min2 => GroupingStrategy::Min2,
            };
            let mut options = FixedDecimalFormatterOptions::default();
            options.grouping_strategy = grouping_strategy;
            Ok(Box::new(ICU4XFixedDecimalFormatter(
                FixedDecimalFormatter::try_new_with_any_provider(
                    &AnyPayloadProvider::from_any_payload::<DecimalSymbolsV1Marker>(
                        // Note: This clone is free, since cloning AnyPayload is free.
                        data_struct.0.clone(),
                    ),
                    &Default::default(),
                    options,
                )?,
            )))
        }

        /// Formats a [`ICU4XFixedDecimal`] to a string.
        #[diplomat::rust_link(icu::decimal::FixedDecimalFormatter::format, FnInStruct)]
        #[diplomat::rust_link(
            icu::decimal::FixedDecimalFormatter::format_to_string,
            FnInStruct,
            hidden
        )]
        #[diplomat::rust_link(icu::decimal::FormattedFixedDecimal, Struct, hidden)]
        #[diplomat::rust_link(icu::decimal::FormattedFixedDecimal::write_to, FnInStruct, hidden)]
        pub fn format(
            &self,
            value: &ICU4XFixedDecimal,
            write: &mut diplomat_runtime::DiplomatWriteable,
        ) -> Result<(), ICU4XError> {
            self.0.format(&value.0).write_to(write)?;
            Ok(())
        }
    }
}