Skip to main content

icu_capi/
provider.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5#[diplomat::bridge]
6#[diplomat::abi_rename = "icu4x_{0}_mv1"]
7#[cfg(feature = "buffer_provider")]
8pub mod ffi {
9    use alloc::boxed::Box;
10    use diplomat_runtime::DiplomatByte;
11    use icu_provider::buf::BufferProvider;
12
13    use crate::unstable::errors::ffi::DataError;
14
15    #[diplomat::opaque]
16    /// An ICU4X data provider, capable of loading ICU4X data keys from some source.
17    ///
18    /// Currently the only source supported is loading from "blob" formatted data from a bytes buffer or the file system.
19    ///
20    /// If you wish to use ICU4X's builtin "compiled data", use the version of the constructors that do not have `_with_provider`
21    /// in their names.
22    #[diplomat::rust_link(icu_provider, Mod)]
23    pub struct DataProvider(Option<Box<dyn BufferProvider + 'static>>);
24
25    impl DataProvider {
26        // These will be unused if almost *all* components are turned off, which is tedious and unproductive to gate for
27        #[allow(unused)]
28        pub(crate) fn get(
29            &self,
30        ) -> Result<&(dyn icu_provider::buf::BufferProvider + 'static), icu_provider::DataError>
31        {
32            match &self.0 {
33                None => Err(icu_provider::DataError::custom(
34                    "This provider has been destroyed",
35                ))?,
36                Some(ref buffer_provider) => Ok(buffer_provider),
37            }
38        }
39
40        // These will be unused if almost *all* components are turned off, which is tedious and unproductive to gate for
41        #[allow(unused)]
42        pub(crate) fn get_unstable(
43            &self,
44        ) -> Result<
45            icu_provider::buf::DeserializingBufferProvider<
46                '_,
47                (dyn icu_provider::buf::BufferProvider + 'static),
48            >,
49            icu_provider::DataError,
50        > {
51            self.get()
52                .map(icu_provider::buf::AsDeserializingBufferProvider::as_deserializing)
53        }
54
55        /// Constructs an `FsDataProvider` and returns it as an [`DataProvider`].
56        /// Requires the `provider_fs` Cargo feature.
57        /// Not supported in WASM.
58        #[diplomat::rust_link(icu_provider_fs::FsDataProvider, Struct)]
59        #[cfg(all(
60            feature = "provider_fs",
61            not(any(target_arch = "wasm32", target_os = "none"))
62        ))]
63        #[diplomat::attr(any(dart, js), disable)]
64        #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)]
65        pub fn from_fs(path: &DiplomatStr) -> Result<Box<DataProvider>, DataError> {
66            Ok(Box::new(DataProvider(Some(Box::new(
67                icu_provider_fs::FsDataProvider::try_new(
68                    // In the future we can start using OsString APIs to support non-utf8 paths
69                    core::str::from_utf8(path)
70                        .map_err(|_| DataError::Io)?
71                        .into(),
72                )?,
73            )))))
74        }
75
76        /// Constructs a `BlobDataProvider` and returns it as an [`DataProvider`].
77        #[diplomat::rust_link(
78            icu_provider_blob::BlobDataProvider::try_new_from_static_blob,
79            FnInStruct
80        )]
81        #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)]
82        #[diplomat::attr(not(supports = static_slices), disable)]
83        pub fn from_byte_slice(
84            blob: &'static [DiplomatByte],
85        ) -> Result<Box<DataProvider>, DataError> {
86            Ok(Box::new(DataProvider(Some(Box::new(
87                icu_provider_blob::BlobDataProvider::try_new_from_static_blob(blob)?,
88            )))))
89        }
90
91        #[diplomat::rust_link(icu_provider_blob::BlobDataProvider::try_new_from_blob, FnInStruct)]
92        #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)]
93        #[diplomat::attr(supports = static_slices, disable)]
94        #[diplomat::attr(*, rename = "from_byte_slice")]
95        pub fn from_owned_byte_slice(
96            blob: Box<[DiplomatByte]>,
97        ) -> Result<Box<DataProvider>, DataError> {
98            Ok(Box::new(DataProvider(Some(Box::new(
99                icu_provider_blob::BlobDataProvider::try_new_from_blob(blob)?,
100            )))))
101        }
102
103        /// Creates a provider that tries the current provider and then, if the current provider
104        /// doesn't support the data key, another provider `other`.
105        ///
106        /// This takes ownership of the `other` provider, leaving an empty provider in its place.
107        #[diplomat::rust_link(icu_provider_adapters::fork::ForkByMarkerProvider, Typedef)]
108        #[diplomat::rust_link(
109            icu_provider_adapters::fork::ForkByMarkerProvider::new,
110            FnInTypedef,
111            hidden
112        )]
113        #[diplomat::rust_link(
114            icu_provider_adapters::fork::ForkByMarkerProvider::new_with_predicate,
115            FnInTypedef,
116            hidden
117        )]
118        #[diplomat::rust_link(
119            icu_provider_adapters::fork::predicates::MarkerNotFoundPredicate,
120            Struct,
121            hidden
122        )]
123        pub fn fork_by_marker(&mut self, other: &mut DataProvider) -> Result<(), DataError> {
124            *self = match (core::mem::take(&mut self.0), core::mem::take(&mut other.0)) {
125                (None, _) | (_, None) => Err(icu_provider::DataError::custom(
126                    "This provider has been destroyed",
127                ))?,
128                (Some(a), Some(b)) => DataProvider(Some(Box::new(
129                    icu_provider_adapters::fork::ForkByMarkerProvider::new(a, b),
130                ))),
131            };
132            Ok(())
133        }
134
135        /// Same as `fork_by_key` but forks by locale instead of key.
136        #[diplomat::rust_link(
137            icu_provider_adapters::fork::predicates::IdentifierNotFoundPredicate,
138            Struct
139        )]
140        pub fn fork_by_locale(&mut self, other: &mut DataProvider) -> Result<(), DataError> {
141            *self = match (core::mem::take(&mut self.0), core::mem::take(&mut other.0)) {
142                (None, _) | (_, None) => Err(icu_provider::DataError::custom(
143                    "This provider has been destroyed",
144                ))?,
145                (Some(a), Some(b)) => DataProvider(Some(Box::new(
146                    icu_provider_adapters::fork::ForkByErrorProvider::new_with_predicate(
147                        a,
148                        b,
149                        icu_provider_adapters::fork::predicates::IdentifierNotFoundPredicate,
150                    ),
151                ))),
152            };
153            Ok(())
154        }
155
156        #[diplomat::rust_link(
157            icu_provider_adapters::fallback::LocaleFallbackProvider::new,
158            FnInStruct
159        )]
160        #[diplomat::rust_link(
161            icu_provider_adapters::fallback::LocaleFallbackProvider,
162            Struct,
163            compact
164        )]
165        #[allow(unused_variables)] // feature-gated
166        #[cfg(feature = "locale")]
167        pub fn enable_locale_fallback_with(
168            &mut self,
169            fallbacker: &crate::unstable::fallbacker::ffi::LocaleFallbacker,
170        ) -> Result<(), DataError> {
171            *self = match core::mem::take(&mut self.0) {
172                None => Err(icu_provider::DataError::custom(
173                    "This provider has been destroyed",
174                ))?,
175                Some(inner) => DataProvider(Some(Box::new(
176                    icu_provider_adapters::fallback::LocaleFallbackProvider::new(
177                        inner,
178                        fallbacker.0.clone(),
179                    ),
180                ))),
181            };
182            Ok(())
183        }
184    }
185}