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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// 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]
#[diplomat::abi_rename = "icu4x_{0}_mv1"]
#[diplomat::attr(auto, namespace = "icu4x")]
pub mod ffi {
    use alloc::boxed::Box;
    use alloc::sync::Arc;
    use core::fmt::Write;

    #[cfg(any(feature = "compiled_data", feature = "buffer_provider"))]
    use crate::errors::ffi::DataError;
    use crate::locale_core::ffi::Locale;
    #[cfg(feature = "buffer_provider")]
    use crate::provider::ffi::DataProvider;

    /// The various calendar types currently supported by [`Calendar`]
    #[diplomat::enum_convert(icu_calendar::AnyCalendarKind, needs_wildcard)]
    #[diplomat::rust_link(icu::calendar::AnyCalendarKind, Enum)]
    pub enum AnyCalendarKind {
        /// The kind of an Iso calendar
        Iso = 0,
        /// The kind of a Gregorian calendar
        Gregorian = 1,
        /// The kind of a Buddhist calendar
        Buddhist = 2,
        /// The kind of a Japanese calendar with modern eras
        Japanese = 3,
        /// The kind of a Japanese calendar with modern and historic eras
        JapaneseExtended = 4,
        /// The kind of an Ethiopian calendar, with Amete Mihret era
        Ethiopian = 5,
        /// The kind of an Ethiopian calendar, with Amete Alem era
        EthiopianAmeteAlem = 6,
        /// The kind of a Indian calendar
        Indian = 7,
        /// The kind of a Coptic calendar
        Coptic = 8,
        /// The kind of a Dangi calendar
        Dangi = 9,
        /// The kind of a Chinese calendar
        Chinese = 10,
        /// The kind of a Hebrew calendar
        Hebrew = 11,
        /// The kind of a Islamic civil calendar
        IslamicCivil = 12,
        /// The kind of a Islamic observational calendar
        IslamicObservational = 13,
        /// The kind of a Islamic tabular calendar
        IslamicTabular = 14,
        /// The kind of a Islamic Umm al-Qura calendar
        IslamicUmmAlQura = 15,
        /// The kind of a Persian calendar
        Persian = 16,
        /// The kind of a Roc calendar
        Roc = 17,
    }

    impl AnyCalendarKind {
        /// Read the calendar type off of the -u-ca- extension on a locale.
        ///
        /// Returns nothing if there is no calendar on the locale or if the locale's calendar
        /// is not known or supported.
        #[diplomat::rust_link(icu::calendar::AnyCalendarKind::get_for_locale, FnInEnum)]
        pub fn get_for_locale(locale: &Locale) -> Option<AnyCalendarKind> {
            icu_calendar::AnyCalendarKind::get_for_locale(&locale.0).map(Into::into)
        }

        /// Obtain the calendar type given a BCP-47 -u-ca- extension string.
        ///
        /// Returns nothing if the calendar is not known or supported.
        #[diplomat::rust_link(icu::calendar::AnyCalendarKind::get_for_bcp47_value, FnInEnum)]
        #[diplomat::rust_link(
            icu::calendar::AnyCalendarKind::get_for_bcp47_string,
            FnInEnum,
            hidden
        )]
        #[diplomat::rust_link(
            icu::calendar::AnyCalendarKind::get_for_bcp47_bytes,
            FnInEnum,
            hidden
        )]
        pub fn get_for_bcp47(s: &DiplomatStr) -> Option<AnyCalendarKind> {
            icu_calendar::AnyCalendarKind::get_for_bcp47_bytes(s).map(Into::into)
        }

        /// Obtain the string suitable for use in the -u-ca- extension in a BCP47 locale.
        #[diplomat::rust_link(icu::calendar::AnyCalendarKind::as_bcp47_string, FnInEnum)]
        #[diplomat::rust_link(icu::calendar::AnyCalendarKind::as_bcp47_value, FnInEnum, hidden)]
        #[diplomat::attr(auto, getter)]
        pub fn bcp47(self, write: &mut diplomat_runtime::DiplomatWrite) {
            let kind = icu_calendar::AnyCalendarKind::from(self);
            let _infallible = write.write_str(kind.as_bcp47_string());
        }
    }

    #[diplomat::opaque]
    #[diplomat::transparent_convert]
    #[diplomat::rust_link(icu::calendar::AnyCalendar, Enum)]
    pub struct Calendar(pub Arc<icu_calendar::AnyCalendar>);

    impl Calendar {
        /// Creates a new [`Calendar`] from the specified date and time, using compiled data.
        #[diplomat::rust_link(icu::calendar::AnyCalendar::try_new, FnInEnum)]
        #[diplomat::attr(supports = fallible_constructors, named_constructor = "for_locale")]
        #[diplomat::demo(default_constructor)]
        #[cfg(feature = "compiled_data")]
        pub fn create_for_locale(locale: &Locale) -> Result<Box<Calendar>, DataError> {
            let prefs = (&locale.0).into();
            Ok(Box::new(Calendar(Arc::new(
                icu_calendar::AnyCalendar::try_new(prefs)?,
            ))))
        }

        /// Creates a new [`Calendar`] from the specified date and time, using compiled data.
        #[diplomat::rust_link(icu::calendar::AnyCalendar::new_for_kind, FnInEnum)]
        #[diplomat::attr(supports = fallible_constructors, named_constructor = "for_kind")]
        #[cfg(feature = "compiled_data")]
        pub fn create_for_kind(kind: AnyCalendarKind) -> Result<Box<Calendar>, DataError> {
            Ok(Box::new(Calendar(Arc::new(
                icu_calendar::AnyCalendar::new_for_kind(kind.into()),
            ))))
        }

        /// Creates a new [`Calendar`] from the specified date and time, using a particular data source.
        #[diplomat::rust_link(icu::calendar::AnyCalendar::try_new, FnInEnum)]
        #[diplomat::attr(supports = fallible_constructors, named_constructor = "for_locale_with_provider")]
        #[diplomat::demo(default_constructor)]
        #[cfg(feature = "buffer_provider")]
        pub fn create_for_locale_with_provider(
            provider: &DataProvider,
            locale: &Locale,
        ) -> Result<Box<Calendar>, DataError> {
            let prefs = (&locale.0).into();

            Ok(Box::new(Calendar(Arc::new(provider.call_constructor(
                |provider| icu_calendar::AnyCalendar::try_new_with_buffer_provider(provider, prefs),
            )?))))
        }

        /// Creates a new [`Calendar`] from the specified date and time, using a particular data source.
        #[diplomat::rust_link(icu::calendar::AnyCalendar::new_for_kind, FnInEnum)]
        #[diplomat::attr(supports = fallible_constructors, named_constructor = "for_kind_with_provider")]
        #[cfg(feature = "buffer_provider")]
        pub fn create_for_kind_with_provider(
            provider: &DataProvider,
            kind: AnyCalendarKind,
        ) -> Result<Box<Calendar>, DataError> {
            Ok(Box::new(Calendar(Arc::new(provider.call_constructor(
                |provider| {
                    icu_calendar::AnyCalendar::try_new_for_kind_with_buffer_provider(
                        provider,
                        kind.into(),
                    )
                },
            )?))))
        }

        /// Returns the kind of this calendar
        #[diplomat::rust_link(icu::calendar::AnyCalendar::kind, FnInEnum)]
        #[diplomat::attr(auto, getter)]
        pub fn kind(&self) -> AnyCalendarKind {
            self.0.kind().into()
        }
    }
}