summaryrefslogtreecommitdiffstats
path: root/vendor/icu_provider/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /vendor/icu_provider/src
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/icu_provider/src')
-rw-r--r--vendor/icu_provider/src/any.rs416
-rw-r--r--vendor/icu_provider/src/buf.rs106
-rw-r--r--vendor/icu_provider/src/constructors.rs101
-rw-r--r--vendor/icu_provider/src/data_provider.rs333
-rw-r--r--vendor/icu_provider/src/datagen/data_conversion.rs48
-rw-r--r--vendor/icu_provider/src/datagen/heap_measure.rs59
-rw-r--r--vendor/icu_provider/src/datagen/iter.rs35
-rw-r--r--vendor/icu_provider/src/datagen/mod.rs120
-rw-r--r--vendor/icu_provider/src/datagen/payload.rs137
-rw-r--r--vendor/icu_provider/src/dynutil.rs263
-rw-r--r--vendor/icu_provider/src/error.rs267
-rw-r--r--vendor/icu_provider/src/hello_world.rs307
-rw-r--r--vendor/icu_provider/src/helpers.rs369
-rw-r--r--vendor/icu_provider/src/key.rs660
-rw-r--r--vendor/icu_provider/src/lib.rs214
-rw-r--r--vendor/icu_provider/src/marker.rs80
-rw-r--r--vendor/icu_provider/src/request.rs513
-rw-r--r--vendor/icu_provider/src/response.rs635
-rw-r--r--vendor/icu_provider/src/serde/borrow_de_utils.rs80
-rw-r--r--vendor/icu_provider/src/serde/mod.rs187
20 files changed, 4930 insertions, 0 deletions
diff --git a/vendor/icu_provider/src/any.rs b/vendor/icu_provider/src/any.rs
new file mode 100644
index 000000000..1c7a60435
--- /dev/null
+++ b/vendor/icu_provider/src/any.rs
@@ -0,0 +1,416 @@
+// 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 ).
+
+//! Traits for data providers that produce `Any` objects.
+
+use crate::prelude::*;
+use core::any::Any;
+use core::convert::TryFrom;
+use core::convert::TryInto;
+use yoke::trait_hack::YokeTraitHack;
+use yoke::Yokeable;
+use zerofrom::ZeroFrom;
+
+#[cfg(not(feature = "sync"))]
+use alloc::rc::Rc as SelectedRc;
+#[cfg(feature = "sync")]
+use alloc::sync::Arc as SelectedRc;
+
+/// A trait that allows to specify `Send + Sync` bounds that are only required when
+/// the `sync` feature is enabled. Without the feature, this is an empty bound.
+#[cfg(feature = "sync")]
+pub trait MaybeSendSync: Send + Sync {}
+#[cfg(feature = "sync")]
+impl<T: Send + Sync> MaybeSendSync for T {}
+
+#[allow(missing_docs)] // docs generated with all features
+#[cfg(not(feature = "sync"))]
+pub trait MaybeSendSync {}
+#[cfg(not(feature = "sync"))]
+impl<T> MaybeSendSync for T {}
+
+/// Representations of the `Any` trait object.
+///
+/// **Important Note:** The types enclosed by `StructRef` and `PayloadRc` are NOT the same!
+/// The first refers to the struct itself, whereas the second refers to a `DataPayload`.
+#[derive(Debug, Clone)]
+enum AnyPayloadInner {
+ /// A reference to `M::Yokeable`
+ StructRef(&'static dyn Any),
+ /// A boxed `DataPayload<M>`.
+ ///
+ /// Note: This needs to be reference counted, not a `Box`, so that `AnyPayload` is cloneable.
+ /// If an `AnyPayload` is cloned, the actual cloning of the data is delayed until
+ /// `downcast()` is invoked (at which point we have the concrete type).
+
+ #[cfg(not(feature = "sync"))]
+ PayloadRc(SelectedRc<dyn Any>),
+
+ #[cfg(feature = "sync")]
+ PayloadRc(SelectedRc<dyn Any + Send + Sync>),
+}
+
+/// A type-erased data payload.
+///
+/// The only useful method on this type is [`AnyPayload::downcast()`], which transforms this into
+/// a normal `DataPayload` which you can subsequently access or mutate.
+///
+/// As with `DataPayload`, cloning is designed to be cheap.
+#[derive(Debug, Clone, Yokeable)]
+pub struct AnyPayload {
+ inner: AnyPayloadInner,
+ type_name: &'static str,
+}
+
+/// The [`DataMarker`] marker type for [`AnyPayload`].
+#[allow(clippy::exhaustive_structs)] // marker type
+pub struct AnyMarker;
+
+impl DataMarker for AnyMarker {
+ type Yokeable = AnyPayload;
+}
+
+impl<M> crate::dynutil::UpcastDataPayload<M> for AnyMarker
+where
+ M: DataMarker + 'static,
+ M::Yokeable: MaybeSendSync,
+{
+ #[inline]
+ fn upcast(other: DataPayload<M>) -> DataPayload<AnyMarker> {
+ DataPayload::from_owned(other.wrap_into_any_payload())
+ }
+}
+
+impl AnyPayload {
+ /// Transforms a type-erased `AnyPayload` into a concrete `DataPayload<M>`.
+ ///
+ /// Because it is expected that the call site knows the identity of the AnyPayload (e.g., from
+ /// the data request), this function returns a `DataError` if the generic type does not match
+ /// the type stored in the `AnyPayload`.
+ pub fn downcast<M>(self) -> Result<DataPayload<M>, DataError>
+ where
+ M: DataMarker + 'static,
+ // For the StructRef case:
+ M::Yokeable: ZeroFrom<'static, M::Yokeable>,
+ // For the PayloadRc case:
+ M::Yokeable: MaybeSendSync,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
+ {
+ use AnyPayloadInner::*;
+ let type_name = self.type_name;
+ match self.inner {
+ StructRef(any_ref) => {
+ let down_ref: &'static M::Yokeable = any_ref
+ .downcast_ref()
+ .ok_or_else(|| DataError::for_type::<M>().with_str_context(type_name))?;
+ Ok(DataPayload::from_owned(M::Yokeable::zero_from(down_ref)))
+ }
+ PayloadRc(any_rc) => {
+ let down_rc = any_rc
+ .downcast::<DataPayload<M>>()
+ .map_err(|_| DataError::for_type::<M>().with_str_context(type_name))?;
+ Ok(SelectedRc::try_unwrap(down_rc).unwrap_or_else(|down_rc| (*down_rc).clone()))
+ }
+ }
+ }
+
+ /// Creates an `AnyPayload` from a static reference to a data struct.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_provider::hello_world::*;
+ /// use icu_provider::prelude::*;
+ /// use std::borrow::Cow;
+ ///
+ /// const HELLO_DATA: HelloWorldV1<'static> = HelloWorldV1 {
+ /// message: Cow::Borrowed("Custom Hello World"),
+ /// };
+ ///
+ /// let any_payload = AnyPayload::from_static_ref(&HELLO_DATA);
+ ///
+ /// let payload: DataPayload<HelloWorldV1Marker> =
+ /// any_payload.downcast().expect("TypeId matches");
+ /// assert_eq!("Custom Hello World", payload.get().message);
+ /// ```
+ pub fn from_static_ref<Y>(static_ref: &'static Y) -> Self
+ where
+ Y: for<'a> Yokeable<'a>,
+ {
+ AnyPayload {
+ inner: AnyPayloadInner::StructRef(static_ref),
+ // Note: This records the Yokeable type rather than the DataMarker type,
+ // but that is okay since this is only for debugging
+ type_name: core::any::type_name::<Y>(),
+ }
+ }
+}
+
+impl<M> DataPayload<M>
+where
+ M: DataMarker + 'static,
+ M::Yokeable: MaybeSendSync,
+{
+ /// Moves this DataPayload to the heap (requiring an allocation) and returns it as an
+ /// erased `AnyPayload`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_provider::hello_world::*;
+ /// use icu_provider::prelude::*;
+ /// use std::borrow::Cow;
+ /// use std::rc::Rc;
+ ///
+ /// let payload: DataPayload<HelloWorldV1Marker> =
+ /// DataPayload::from_owned(HelloWorldV1 {
+ /// message: Cow::Borrowed("Custom Hello World"),
+ /// });
+ ///
+ /// let any_payload = payload.wrap_into_any_payload();
+ ///
+ /// let payload: DataPayload<HelloWorldV1Marker> =
+ /// any_payload.downcast().expect("TypeId matches");
+ /// assert_eq!("Custom Hello World", payload.get().message);
+ /// ```
+ pub fn wrap_into_any_payload(self) -> AnyPayload {
+ AnyPayload {
+ inner: AnyPayloadInner::PayloadRc(SelectedRc::from(self)),
+ type_name: core::any::type_name::<M>(),
+ }
+ }
+}
+
+impl DataPayload<AnyMarker> {
+ /// Transforms a type-erased `DataPayload<AnyMarker>` into a concrete `DataPayload<M>`.
+ #[inline]
+ pub fn downcast<M>(self) -> Result<DataPayload<M>, DataError>
+ where
+ M: DataMarker + 'static,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
+ M::Yokeable: ZeroFrom<'static, M::Yokeable>,
+ M::Yokeable: MaybeSendSync,
+ {
+ self.try_unwrap_owned()?.downcast()
+ }
+}
+
+/// A [`DataResponse`] for type-erased values.
+///
+/// Convertible to and from `DataResponse<AnyMarker>`.
+#[allow(clippy::exhaustive_structs)] // this type is stable (the metadata is allowed to grow)
+pub struct AnyResponse {
+ /// Metadata about the returned object.
+ pub metadata: DataResponseMetadata,
+
+ /// The object itself; None if it was not loaded.
+ pub payload: Option<AnyPayload>,
+}
+
+impl TryFrom<DataResponse<AnyMarker>> for AnyResponse {
+ type Error = DataError;
+ #[inline]
+ fn try_from(other: DataResponse<AnyMarker>) -> Result<Self, Self::Error> {
+ Ok(Self {
+ metadata: other.metadata,
+ payload: other.payload.map(|p| p.try_unwrap_owned()).transpose()?,
+ })
+ }
+}
+
+impl From<AnyResponse> for DataResponse<AnyMarker> {
+ #[inline]
+ fn from(other: AnyResponse) -> Self {
+ Self {
+ metadata: other.metadata,
+ payload: other.payload.map(DataPayload::from_owned),
+ }
+ }
+}
+
+impl AnyResponse {
+ /// Transforms a type-erased `DataResponse<AnyMarker>` into a concrete `DataResponse<M>`.
+ #[inline]
+ pub fn downcast<M>(self) -> Result<DataResponse<M>, DataError>
+ where
+ M: DataMarker + 'static,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
+ M::Yokeable: ZeroFrom<'static, M::Yokeable>,
+ M::Yokeable: MaybeSendSync,
+ {
+ Ok(DataResponse {
+ metadata: self.metadata,
+ payload: self.payload.map(|p| p.downcast()).transpose()?,
+ })
+ }
+}
+
+/// An object-safe data provider that returns data structs cast to `dyn Any` trait objects.
+///
+/// # Examples
+///
+/// ```
+/// use icu_provider::hello_world::*;
+/// use icu_provider::prelude::*;
+/// use std::borrow::Cow;
+///
+/// let any_response = HelloWorldProvider
+/// .as_any_provider()
+/// .load_any(
+/// HelloWorldV1Marker::KEY,
+/// DataRequest {
+/// locale: &icu_locid::locale!("de").into(),
+/// metadata: Default::default(),
+/// },
+/// )
+/// .expect("Load should succeed");
+///
+/// // Downcast to something useful
+/// let response: DataResponse<HelloWorldV1Marker> =
+/// any_response.downcast().expect("Types match");
+///
+/// let payload = response.take_payload().expect("Data should be present");
+///
+/// assert_eq!(payload.get().message, "Hallo Welt");
+/// ```
+pub trait AnyProvider {
+ /// Loads an [`AnyPayload`] according to the key and request.
+ fn load_any(&self, key: DataKey, req: DataRequest) -> Result<AnyResponse, DataError>;
+}
+
+impl<T: AnyProvider + ?Sized> AnyProvider for alloc::boxed::Box<T> {
+ fn load_any(&self, key: DataKey, req: DataRequest) -> Result<AnyResponse, DataError> {
+ (**self).load_any(key, req)
+ }
+}
+
+/// A wrapper over `DynamicDataProvider<AnyMarker>` that implements `AnyProvider`
+#[allow(clippy::exhaustive_structs)] // newtype
+pub struct DynamicDataProviderAnyMarkerWrap<'a, P: ?Sized>(pub &'a P);
+
+/// Blanket-implemented trait adding the [`Self::as_any_provider()`] function.
+pub trait AsDynamicDataProviderAnyMarkerWrap {
+ /// Returns an object implementing `AnyProvider` when called on `DynamicDataProvider<AnyMarker>`
+ fn as_any_provider(&self) -> DynamicDataProviderAnyMarkerWrap<Self>;
+}
+
+impl<P> AsDynamicDataProviderAnyMarkerWrap for P
+where
+ P: DynamicDataProvider<AnyMarker>,
+{
+ #[inline]
+ fn as_any_provider(&self) -> DynamicDataProviderAnyMarkerWrap<P> {
+ DynamicDataProviderAnyMarkerWrap(self)
+ }
+}
+
+impl<P> AnyProvider for DynamicDataProviderAnyMarkerWrap<'_, P>
+where
+ P: DynamicDataProvider<AnyMarker> + ?Sized,
+{
+ #[inline]
+ fn load_any(&self, key: DataKey, req: DataRequest) -> Result<AnyResponse, DataError> {
+ self.0.load_data(key, req)?.try_into()
+ }
+}
+
+/// A wrapper over `AnyProvider` that implements `DynamicDataProvider<M>` via downcasting
+#[allow(clippy::exhaustive_structs)] // newtype
+pub struct DowncastingAnyProvider<'a, P: ?Sized>(pub &'a P);
+
+/// Blanket-implemented trait adding the [`Self::as_downcasting()`] function.
+pub trait AsDowncastingAnyProvider {
+ /// Returns an object implementing `DynamicDataProvider<M>` when called on `AnyProvider`
+ fn as_downcasting(&self) -> DowncastingAnyProvider<Self>;
+}
+
+impl<P> AsDowncastingAnyProvider for P
+where
+ P: AnyProvider + ?Sized,
+{
+ #[inline]
+ fn as_downcasting(&self) -> DowncastingAnyProvider<P> {
+ DowncastingAnyProvider(self)
+ }
+}
+
+impl<M, P> DataProvider<M> for DowncastingAnyProvider<'_, P>
+where
+ P: AnyProvider + ?Sized,
+ M: KeyedDataMarker + 'static,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
+ M::Yokeable: ZeroFrom<'static, M::Yokeable>,
+ M::Yokeable: MaybeSendSync,
+{
+ #[inline]
+ fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
+ self.0.load_any(M::KEY, req)?.downcast()
+ }
+}
+
+impl<M, P> DynamicDataProvider<M> for DowncastingAnyProvider<'_, P>
+where
+ P: AnyProvider + ?Sized,
+ M: DataMarker + 'static,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
+ M::Yokeable: ZeroFrom<'static, M::Yokeable>,
+ M::Yokeable: MaybeSendSync,
+{
+ #[inline]
+ fn load_data(&self, key: DataKey, req: DataRequest) -> Result<DataResponse<M>, DataError> {
+ self.0.load_any(key, req)?.downcast()
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::hello_world::*;
+ use alloc::borrow::Cow;
+
+ const CONST_DATA: HelloWorldV1<'static> = HelloWorldV1 {
+ message: Cow::Borrowed("Custom Hello World"),
+ };
+
+ #[test]
+ fn test_debug() {
+ let payload: DataPayload<HelloWorldV1Marker> = DataPayload::from_owned(HelloWorldV1 {
+ message: Cow::Borrowed("Custom Hello World"),
+ });
+
+ let any_payload = payload.wrap_into_any_payload();
+ assert_eq!(
+ "AnyPayload { inner: PayloadRc(Any { .. }), type_name: \"icu_provider::hello_world::HelloWorldV1Marker\" }",
+ format!("{:?}", any_payload)
+ );
+
+ struct WrongMarker;
+
+ impl DataMarker for WrongMarker {
+ type Yokeable = u8;
+ }
+
+ let err = any_payload.downcast::<WrongMarker>().unwrap_err();
+ assert_eq!(
+ "ICU4X data error: Mismatched types: tried to downcast with icu_provider::any::test::test_debug::WrongMarker, but actual type is different: icu_provider::hello_world::HelloWorldV1Marker",
+ format!("{}", err)
+ );
+ }
+
+ #[test]
+ fn test_non_owned_any_marker() {
+ // This test demonstrates a code path that can trigger the InvalidState error kind.
+ let payload_result: DataPayload<AnyMarker> =
+ DataPayload::from_owned_buffer(Box::new(*b"pretend we're borrowing from here"))
+ .map_project(|_, _| AnyPayload::from_static_ref(&CONST_DATA));
+ let err = payload_result.downcast::<HelloWorldV1Marker>().unwrap_err();
+ assert!(matches!(
+ err,
+ DataError {
+ kind: DataErrorKind::InvalidState,
+ ..
+ }
+ ));
+ }
+}
diff --git a/vendor/icu_provider/src/buf.rs b/vendor/icu_provider/src/buf.rs
new file mode 100644
index 000000000..73bc0f165
--- /dev/null
+++ b/vendor/icu_provider/src/buf.rs
@@ -0,0 +1,106 @@
+// 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 ).
+
+//! Traits for data providers that produce opaque buffers.
+
+use crate::prelude::*;
+
+/// [`DataMarker`] for raw buffers. Returned by [`BufferProvider`].
+///
+/// The data is expected to be deserialized before it can be used; see
+/// [`DataPayload::into_deserialized`].
+#[allow(clippy::exhaustive_structs)] // marker type
+pub struct BufferMarker;
+
+impl DataMarker for BufferMarker {
+ type Yokeable = &'static [u8];
+}
+
+/// A data provider that returns opaque bytes.
+///
+/// Generally, these bytes are expected to be deserializable with Serde. To get an object
+/// implementing [`DataProvider`] via Serde, use [`as_deserializing()`], which requires
+/// enabling at least one of the Serde features.
+///
+/// Along with [`DataProvider`], this is one of the two foundational traits in this crate.
+///
+/// [`BufferProvider`] can be made into a trait object. It is used over FFI.
+///
+/// # Examples
+///
+/// ```
+/// # #[cfg(feature = "deserialize_json")] {
+/// use icu_locid::locale;
+/// use icu_provider::hello_world::*;
+/// use icu_provider::prelude::*;
+///
+/// let buffer_provider = HelloWorldProvider.into_json_provider();
+///
+/// let data_provider = buffer_provider.as_deserializing();
+///
+/// let german_hello_world: DataPayload<HelloWorldV1Marker> = data_provider
+/// .load(DataRequest {
+/// locale: &locale!("de").into(),
+/// metadata: Default::default(),
+/// })
+/// .expect("Loading should succeed")
+/// .take_payload()
+/// .expect("Data should be present");
+///
+/// assert_eq!("Hallo Welt", german_hello_world.get().message);
+/// # }
+/// ```
+///
+/// [`as_deserializing()`]: AsDeserializingBufferProvider::as_deserializing
+pub trait BufferProvider {
+ /// Loads a [`DataPayload`]`<`[`BufferMarker`]`>` according to the key and request.
+ fn load_buffer(
+ &self,
+ key: DataKey,
+ req: DataRequest,
+ ) -> Result<DataResponse<BufferMarker>, DataError>;
+}
+
+impl<T: BufferProvider + ?Sized> BufferProvider for alloc::boxed::Box<T> {
+ fn load_buffer(
+ &self,
+ key: DataKey,
+ req: DataRequest,
+ ) -> Result<DataResponse<BufferMarker>, DataError> {
+ (**self).load_buffer(key, req)
+ }
+}
+
+/// An enum expressing all Serde formats known to ICU4X.
+#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[non_exhaustive]
+pub enum BufferFormat {
+ /// Serialize using JavaScript Object Notation (JSON).
+ Json,
+ /// Serialize using Bincode version 1.
+ Bincode1,
+ /// Serialize using Postcard version 0.7.
+ Postcard1,
+}
+
+impl BufferFormat {
+ /// Returns an error if the buffer format is not enabled.
+ pub fn check_available(&self) -> Result<(), DataError> {
+ match self {
+ #[cfg(feature = "deserialize_json")]
+ BufferFormat::Json => Ok(()),
+
+ #[cfg(feature = "deserialize_bincode_1")]
+ BufferFormat::Bincode1 => Ok(()),
+
+ #[cfg(feature = "deserialize_postcard_1")]
+ BufferFormat::Postcard1 => Ok(()),
+
+ // Allowed for cases in which all features are enabled
+ #[allow(unreachable_patterns)]
+ _ => Err(DataErrorKind::UnavailableBufferFormat(*self).into_error()),
+ }
+ }
+}
diff --git a/vendor/icu_provider/src/constructors.rs b/vendor/icu_provider/src/constructors.rs
new file mode 100644
index 000000000..a9330c3f2
--- /dev/null
+++ b/vendor/icu_provider/src/constructors.rs
@@ -0,0 +1,101 @@
+// 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 ).
+
+//! 📚 *This module documents ICU4X constructor signatures.*
+//!
+//! One of the key differences between ICU4X and its parent projects, ICU4C and ICU4J, is in how
+//! it deals with locale data.
+//!
+//! In ICU4X, the data provider is an *explicit argument* whenever it is required by the library.
+//! This enables ICU4X to achieve the following value propositions:
+//!
+//! 1. Configurable data sources (machine-readable data file, baked into code, JSON, etc).
+//! 2. Dynamic data loading at runtime (load data on demand).
+//! 3. Reduced overhead and code size (data is resolved locally at each call site).
+//! 4. Explicit support for multiple ICU4X instances sharing data.
+//!
+//! In order to achieve these goals, there are 3 versions of all Rust ICU4X functions that
+//! take a data provider argument:
+//!
+//! 1. `*_unstable`
+//! 2. `*_with_any_provider`
+//! 3. `*_with_buffer_provider`
+//!
+//! # Which constructor should I use?
+//!
+//! ## When to use `*_unstable`
+//!
+//! Use this constructor if your data provider implements the [`DataProvider`] trait for all
+//! data structs in *current and future* ICU4X versions. Examples:
+//!
+//! 1. `BakedDataProvider` auto-regenerated on new ICU4X versions
+//! 2. Anything with a _blanket_ [`DataProvider`] impl
+//!
+//! Since the exact set of bounds may change at any time, including in minor SemVer releases,
+//! it is the client's responsibility to guarantee that the requirement is upheld.
+//!
+//! ## When to use `*_with_any_provider`
+//!
+//! Use this constructor if you need to use a provider that implements [`AnyProvider`] but not
+//! [`DataProvider`]. Examples:
+//!
+//! 1. [`AnyPayloadProvider`]
+//! 2. [`ForkByKeyProvider`] between two providers implementing [`AnyProvider`]
+//! 3. Providers that cache or override certain keys but not others and therefore
+//! can't implement [`DataProvider`]
+//!
+//! ## When to use `*_with_buffer_provider`
+//!
+//! Use this constructor if your data originates as byte buffers that need to be deserialized.
+//! All such providers should implement [`BufferProvider`]. Examples:
+//!
+//! 1. [`BlobDataProvider`]
+//! 2. [`FsDataProvider`]
+//! 3. [`ForkByKeyProvider`] between any of the above
+//!
+//! Please note that you must enable the `"serde"` feature on each crate in which you use the
+//! `*_with_buffer_provider` constructor.
+//!
+//! # Data Versioning Policy
+//!
+//! The `*_with_any_provider` and `*_with_buffer_provider` functions will succeed to compile and
+//! run if given a data provider supporting all of the keys required for the object being
+//! constructed, either the current or any previous version within the same SemVer major release.
+//! For example, if a data file is built to support FooFormatter version 1.1, then FooFormatter
+//! version 1.2 will be able to read the same data file. Likewise, backwards-compatible keys can
+//! always be included by `icu_datagen` to support older library versions.
+//!
+//! The `*_unstable` functions are only guaranteed to work on data built for the exact same version
+//! of ICU4X. The advantage of the `*_unstable` functions is that they result in the smallest code
+//! size and allow for automatic data slicing when `BakedDataProvider` is used. However, the type
+//! bounds of this function may change over time, breaking SemVer guarantees. These functions
+//! should therefore only be used when you have full control over your data lifecycle at compile
+//! time.
+//!
+//! # Data Providers Over FFI
+//!
+//! Over FFI, there is only one data provider type: [`ICU4XDataProvider`]. Internally, it is an
+//! `enum` between `dyn `[`AnyProvider`] and `dyn `[`BufferProvider`].
+//!
+//! To control for code size, there are two features, `any_provider` and `buffer_provider`, that
+//! enable the corresponding items in the enum.
+//!
+//! In Rust ICU4X, a similar buffer/any enum approach was not taken because:
+//!
+//! 1. Feature-gating the enum branches gets complex across crates.
+//! 2. Without feature gating, users need to carry Serde code even if they're not using it,
+//! violating one of the core value propositions of ICU4X.
+//! 3. We could reduce the number of constructors from 3 to 2 but not to 1, so the educational
+//! benefit is limited.
+//!
+//!
+//! [`DataProvider`]: crate::DataProvider
+//! [`BufferProvider`]: crate::BufferProvider
+//! [`AnyProvider`]: crate::AnyProvider
+//! [`AnyPayloadProvider`]: ../../icu_provider_adapters/any_payload/struct.AnyPayloadProvider.html
+//! [`ForkByKeyProvider`]: ../../icu_provider_adapters/fork/struct.ForkByKeyProvider.html
+//! [`BlobDataProvider`]: ../../icu_provider_blob/struct.BlobDataProvider.html
+//! [`StaticDataProvider`]: ../../icu_provider_blob/struct.StaticDataProvider.html
+//! [`FsDataProvider`]: ../../icu_provider_blob/struct.FsDataProvider.html
+//! [`ICU4XDataProvider`]: ../../icu_capi/provider/ffi/struct.ICU4XDataProvider.html
diff --git a/vendor/icu_provider/src/data_provider.rs b/vendor/icu_provider/src/data_provider.rs
new file mode 100644
index 000000000..af98a252a
--- /dev/null
+++ b/vendor/icu_provider/src/data_provider.rs
@@ -0,0 +1,333 @@
+// 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 ).
+
+use crate::error::DataError;
+use crate::key::DataKey;
+use crate::marker::{DataMarker, KeyedDataMarker};
+use crate::request::DataRequest;
+use crate::response::DataResponse;
+
+/// A data provider that loads data for a specific data type.
+///
+/// Unlike [`DataProvider`], there may be multiple keys corresponding to the same data type.
+/// This is often the case when returning `dyn` trait objects such as [`AnyMarker`].
+///
+/// [`AnyMarker`]: crate::any::AnyMarker
+pub trait DynamicDataProvider<M>
+where
+ M: DataMarker,
+{
+ /// Query the provider for data, returning the result.
+ ///
+ /// Returns [`Ok`] if the request successfully loaded data. If data failed to load, returns an
+ /// Error with more information.
+ fn load_data(&self, key: DataKey, req: DataRequest) -> Result<DataResponse<M>, DataError>;
+}
+
+/// A data provider that loads data for a specific [`DataKey`].
+pub trait DataProvider<M>
+where
+ M: KeyedDataMarker,
+{
+ /// Query the provider for data, returning the result.
+ ///
+ /// Returns [`Ok`] if the request successfully loaded data. If data failed to load, returns an
+ /// Error with more information.
+ fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError>;
+}
+
+impl<M, P> DynamicDataProvider<M> for alloc::boxed::Box<P>
+where
+ M: DataMarker,
+ P: DynamicDataProvider<M> + ?Sized,
+{
+ fn load_data(&self, key: DataKey, req: DataRequest) -> Result<DataResponse<M>, DataError> {
+ (**self).load_data(key, req)
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use super::*;
+ use crate::hello_world::*;
+ use crate::prelude::*;
+ use crate::yoke::Yokeable;
+ use crate::zerofrom;
+ use alloc::borrow::Cow;
+ use alloc::string::String;
+ use core::fmt::Debug;
+ use serde::{Deserialize, Serialize};
+
+ // This tests DataProvider borrow semantics with a dummy data provider based on a
+ // JSON string. It also exercises most of the data provider code paths.
+
+ /// Key for HelloAlt, used for testing mismatched types
+ const HELLO_ALT_KEY: DataKey = crate::data_key!("core/helloalt@1");
+
+ /// A data struct serialization-compatible with HelloWorldV1 used for testing mismatched types
+ #[derive(
+ Serialize, Deserialize, Debug, Clone, Default, PartialEq, Yokeable, zerofrom::ZeroFrom,
+ )]
+ struct HelloAlt {
+ #[zerofrom(clone)]
+ message: String,
+ }
+
+ /// Marker type for [`HelloAlt`].
+ struct HelloAltMarker {}
+
+ impl DataMarker for HelloAltMarker {
+ type Yokeable = HelloAlt;
+ }
+
+ impl KeyedDataMarker for HelloAltMarker {
+ const KEY: DataKey = HELLO_ALT_KEY;
+ }
+
+ #[derive(Deserialize, Debug, Clone, Default, PartialEq)]
+ struct HelloCombined<'data> {
+ #[serde(borrow)]
+ pub hello_v1: HelloWorldV1<'data>,
+ pub hello_alt: HelloAlt,
+ }
+
+ /// A DataProvider that owns its data, returning an Rc-variant DataPayload.
+ /// Supports only key::HELLO_WORLD_V1. Uses `impl_dynamic_data_provider!()`.
+ #[derive(Debug)]
+ struct DataWarehouse {
+ hello_v1: HelloWorldV1<'static>,
+ hello_alt: HelloAlt,
+ }
+
+ impl DataProvider<HelloWorldV1Marker> for DataWarehouse {
+ fn load(&self, _: DataRequest) -> Result<DataResponse<HelloWorldV1Marker>, DataError> {
+ Ok(DataResponse {
+ metadata: DataResponseMetadata::default(),
+ payload: Some(DataPayload::from_owned(self.hello_v1.clone())),
+ })
+ }
+ }
+
+ crate::impl_dynamic_data_provider!(DataWarehouse, [HelloWorldV1Marker,], AnyMarker);
+
+ /// A DataProvider that supports both key::HELLO_WORLD_V1 and HELLO_ALT.
+ #[derive(Debug)]
+ struct DataProvider2 {
+ data: DataWarehouse,
+ }
+
+ impl From<DataWarehouse> for DataProvider2 {
+ fn from(warehouse: DataWarehouse) -> Self {
+ DataProvider2 { data: warehouse }
+ }
+ }
+
+ impl DataProvider<HelloWorldV1Marker> for DataProvider2 {
+ fn load(&self, _: DataRequest) -> Result<DataResponse<HelloWorldV1Marker>, DataError> {
+ Ok(DataResponse {
+ metadata: DataResponseMetadata::default(),
+ payload: Some(DataPayload::from_owned(self.data.hello_v1.clone())),
+ })
+ }
+ }
+
+ impl DataProvider<HelloAltMarker> for DataProvider2 {
+ fn load(&self, _: DataRequest) -> Result<DataResponse<HelloAltMarker>, DataError> {
+ Ok(DataResponse {
+ metadata: DataResponseMetadata::default(),
+ payload: Some(DataPayload::from_owned(self.data.hello_alt.clone())),
+ })
+ }
+ }
+
+ crate::impl_dynamic_data_provider!(
+ DataProvider2,
+ [HelloWorldV1Marker, HelloAltMarker,],
+ AnyMarker
+ );
+
+ const DATA: &str = r#"{
+ "hello_v1": {
+ "message": "Hello V1"
+ },
+ "hello_alt": {
+ "message": "Hello Alt"
+ }
+ }"#;
+
+ fn get_warehouse(data: &'static str) -> DataWarehouse {
+ let data: HelloCombined = serde_json::from_str(data).expect("Well-formed data");
+ DataWarehouse {
+ hello_v1: data.hello_v1,
+ hello_alt: data.hello_alt,
+ }
+ }
+
+ fn get_payload_v1<P: DataProvider<HelloWorldV1Marker> + ?Sized>(
+ provider: &P,
+ ) -> Result<DataPayload<HelloWorldV1Marker>, DataError> {
+ provider.load(Default::default())?.take_payload()
+ }
+
+ fn get_payload_alt<P: DataProvider<HelloAltMarker> + ?Sized>(
+ provider: &P,
+ ) -> Result<DataPayload<HelloAltMarker>, DataError> {
+ provider.load(Default::default())?.take_payload()
+ }
+
+ #[test]
+ fn test_warehouse_owned() {
+ let warehouse = get_warehouse(DATA);
+ let hello_data = get_payload_v1(&warehouse).unwrap();
+ assert!(matches!(
+ hello_data.get(),
+ HelloWorldV1 {
+ message: Cow::Borrowed(_),
+ }
+ ));
+ }
+
+ #[test]
+ fn test_warehouse_owned_dyn_erased() {
+ let warehouse = get_warehouse(DATA);
+ let hello_data = get_payload_v1(&warehouse.as_any_provider().as_downcasting()).unwrap();
+ assert!(matches!(
+ hello_data.get(),
+ HelloWorldV1 {
+ message: Cow::Borrowed(_),
+ }
+ ));
+ }
+
+ #[test]
+ fn test_warehouse_owned_dyn_generic() {
+ let warehouse = get_warehouse(DATA);
+ let hello_data =
+ get_payload_v1(&warehouse as &dyn DataProvider<HelloWorldV1Marker>).unwrap();
+ assert!(matches!(
+ hello_data.get(),
+ HelloWorldV1 {
+ message: Cow::Borrowed(_),
+ }
+ ));
+ }
+
+ #[test]
+ fn test_warehouse_owned_dyn_erased_alt() {
+ let warehouse = get_warehouse(DATA);
+ let response = get_payload_alt(&warehouse.as_any_provider().as_downcasting());
+ assert!(matches!(
+ response,
+ Err(DataError {
+ kind: DataErrorKind::MissingDataKey,
+ ..
+ })
+ ));
+ }
+
+ #[test]
+ fn test_provider2() {
+ let warehouse = get_warehouse(DATA);
+ let provider = DataProvider2::from(warehouse);
+ let hello_data = get_payload_v1(&provider).unwrap();
+ assert!(matches!(
+ hello_data.get(),
+ HelloWorldV1 {
+ message: Cow::Borrowed(_),
+ }
+ ));
+ }
+
+ #[test]
+ fn test_provider2_dyn_erased() {
+ let warehouse = get_warehouse(DATA);
+ let provider = DataProvider2::from(warehouse);
+ let hello_data = get_payload_v1(&provider.as_any_provider().as_downcasting()).unwrap();
+ assert!(matches!(
+ hello_data.get(),
+ HelloWorldV1 {
+ message: Cow::Borrowed(_),
+ }
+ ));
+ }
+
+ #[test]
+ fn test_provider2_dyn_erased_alt() {
+ let warehouse = get_warehouse(DATA);
+ let provider = DataProvider2::from(warehouse);
+ let hello_data = get_payload_alt(&provider.as_any_provider().as_downcasting()).unwrap();
+ assert!(matches!(hello_data.get(), HelloAlt { .. }));
+ }
+
+ #[test]
+ fn test_provider2_dyn_generic() {
+ let warehouse = get_warehouse(DATA);
+ let provider = DataProvider2::from(warehouse);
+ let hello_data =
+ get_payload_v1(&provider as &dyn DataProvider<HelloWorldV1Marker>).unwrap();
+ assert!(matches!(
+ hello_data.get(),
+ HelloWorldV1 {
+ message: Cow::Borrowed(_),
+ }
+ ));
+ }
+
+ #[test]
+ fn test_provider2_dyn_generic_alt() {
+ let warehouse = get_warehouse(DATA);
+ let provider = DataProvider2::from(warehouse);
+ let hello_data = get_payload_alt(&provider as &dyn DataProvider<HelloAltMarker>).unwrap();
+ assert!(matches!(hello_data.get(), HelloAlt { .. }));
+ }
+
+ #[test]
+ fn test_mismatched_types() {
+ let warehouse = get_warehouse(DATA);
+ let provider = DataProvider2::from(warehouse);
+ // Request is for v2, but type argument is for v1
+ let response: Result<DataResponse<HelloWorldV1Marker>, DataError> = AnyProvider::load_any(
+ &provider.as_any_provider(),
+ HELLO_ALT_KEY,
+ Default::default(),
+ )
+ .unwrap()
+ .downcast();
+ assert!(matches!(
+ response,
+ Err(DataError {
+ kind: DataErrorKind::MismatchedType(_),
+ ..
+ })
+ ));
+ }
+
+ fn check_v1_v2<P>(d: &P)
+ where
+ P: DataProvider<HelloWorldV1Marker> + DataProvider<HelloAltMarker> + ?Sized,
+ {
+ let v1: DataPayload<HelloWorldV1Marker> =
+ d.load(Default::default()).unwrap().take_payload().unwrap();
+ let v2: DataPayload<HelloAltMarker> =
+ d.load(Default::default()).unwrap().take_payload().unwrap();
+ if v1.get().message == v2.get().message {
+ panic!()
+ }
+ }
+
+ #[test]
+ fn test_v1_v2_generic() {
+ let warehouse = get_warehouse(DATA);
+ let provider = DataProvider2::from(warehouse);
+ check_v1_v2(&provider);
+ }
+
+ #[test]
+ fn test_v1_v2_dyn_erased() {
+ let warehouse = get_warehouse(DATA);
+ let provider = DataProvider2::from(warehouse);
+ check_v1_v2(&provider.as_any_provider().as_downcasting());
+ }
+}
diff --git a/vendor/icu_provider/src/datagen/data_conversion.rs b/vendor/icu_provider/src/datagen/data_conversion.rs
new file mode 100644
index 000000000..59146352a
--- /dev/null
+++ b/vendor/icu_provider/src/datagen/data_conversion.rs
@@ -0,0 +1,48 @@
+// 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 ).
+
+use crate::prelude::*;
+use crate::DataKey;
+use alloc::boxed::Box;
+
+/// A trait that allows for converting between data payloads of different types.
+///
+/// These payloads will typically be some kind of erased payload, either with
+/// AnyMarker, BufferMarker, or SerializeMarker, where converting requires reifying the type.
+/// A type implementing [`DataConverter`] will essentially have a "registry" mapping keys to
+/// concrete marker types M, and reifying the input to a `DataPayload<M>`, performing some conversion
+/// or computation, and erasing the result to `DataPayload<MTo>`.
+///
+/// It will typically be implemented on data providers used in datagen.
+///
+/// The [`make_exportable_provider!`] macro is able to automatically implement this trait.
+///
+/// [`make_exportable_provider!`]: crate::make_exportable_provider
+pub trait DataConverter<MFrom: DataMarker, MTo: DataMarker> {
+ /// Attempt to convert a payload corresponding to the given data key
+ /// from one marker type to another marker type.
+ ///
+ /// If this is not possible (for example, if the provider does not know about the key),
+ /// the original payload is returned back to the caller.
+ fn convert(
+ &self,
+ key: DataKey,
+ from: DataPayload<MFrom>,
+ ) -> Result<DataPayload<MTo>, (DataPayload<MFrom>, DataError)>;
+}
+
+impl<MFrom, MTo, P> DataConverter<MFrom, MTo> for Box<P>
+where
+ MFrom: DataMarker,
+ MTo: DataMarker,
+ P: DataConverter<MFrom, MTo> + ?Sized,
+{
+ fn convert(
+ &self,
+ key: DataKey,
+ from: DataPayload<MFrom>,
+ ) -> Result<DataPayload<MTo>, (DataPayload<MFrom>, DataError)> {
+ (**self).convert(key, from)
+ }
+}
diff --git a/vendor/icu_provider/src/datagen/heap_measure.rs b/vendor/icu_provider/src/datagen/heap_measure.rs
new file mode 100644
index 000000000..d451f3ebe
--- /dev/null
+++ b/vendor/icu_provider/src/datagen/heap_measure.rs
@@ -0,0 +1,59 @@
+// 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 ).
+
+use crate::buf::{BufferFormat, BufferMarker};
+use crate::prelude::*;
+use yoke::trait_hack::YokeTraitHack;
+
+/// Stats on the heap size needed when attempting to zero-copy-deserialize
+/// a postcard-formatted data struct.
+#[derive(Debug, Copy, Clone, yoke::Yokeable, Default)]
+#[non_exhaustive]
+pub struct HeapStats {
+ /// Total bytes allocated during deserialization
+ pub total_bytes_allocated: u64,
+ /// Total bytes allocated during deserialization that have not yet been freed
+ pub net_bytes_allocated: usize,
+}
+
+/// The [`DataMarker`] marker type for [`HeapStats`].
+#[allow(clippy::exhaustive_structs)] // marker type
+pub struct HeapStatsMarker;
+
+impl DataMarker for HeapStatsMarker {
+ type Yokeable = HeapStats;
+}
+
+impl DataPayload<BufferMarker> {
+ /// Given a buffer known to be in postcard-0.7 format, attempt to zero-copy
+ /// deserialize it and record the amount of heap allocations that occurred.
+ ///
+ /// Ideally, this number should be zero.
+ ///
+ /// [`dhat`]'s profiler must be initialized before using this.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the buffer is not in postcard-0.7 format.
+ #[allow(clippy::expect_used)] // The function documents when panics may occur.
+ pub fn attempt_zero_copy_heap_size<M>(self) -> HeapStats
+ where
+ M: DataMarker,
+ for<'a> &'a <M::Yokeable as yoke::Yokeable<'a>>::Output: serde::Serialize,
+ for<'de> YokeTraitHack<<M::Yokeable as yoke::Yokeable<'de>>::Output>:
+ serde::Deserialize<'de>,
+ {
+ let stats_before = dhat::HeapStats::get();
+ // reify, but do nothing with the type
+ let _reified_data: DataPayload<M> = self
+ .into_deserialized(BufferFormat::Postcard1)
+ .expect("Failed to deserialize BufferMarker as postcard-0.7");
+ let stats_after = dhat::HeapStats::get();
+
+ HeapStats {
+ total_bytes_allocated: stats_after.total_bytes - stats_before.total_bytes,
+ net_bytes_allocated: stats_after.curr_bytes - stats_before.curr_bytes,
+ }
+ }
+}
diff --git a/vendor/icu_provider/src/datagen/iter.rs b/vendor/icu_provider/src/datagen/iter.rs
new file mode 100644
index 000000000..6175d89c6
--- /dev/null
+++ b/vendor/icu_provider/src/datagen/iter.rs
@@ -0,0 +1,35 @@
+// 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 ).
+
+//! Collection of iteration APIs for data providers.
+
+use crate::prelude::*;
+
+/// A [`DynamicDataProvider`] that can iterate over all supported [`DataLocale`] for a certain key.
+///
+/// Implementing this trait means that a data provider knows all of the data it can successfully
+/// return from a load request.
+pub trait IterableDynamicDataProvider<M: DataMarker>: DynamicDataProvider<M> {
+ /// Given a [`DataKey`], returns a list of [`DataLocale`].
+ fn supported_locales_for_key(&self, key: DataKey) -> Result<Vec<DataLocale>, DataError>;
+}
+
+/// A [`DataProvider`] that can iterate over all supported [`DataLocale`] for a certain key.
+///
+/// Implementing this trait means that a data provider knows all of the data it can successfully
+/// return from a load request.
+pub trait IterableDataProvider<M: KeyedDataMarker>: DataProvider<M> {
+ /// Returns a list of [`DataLocale`].
+ fn supported_locales(&self) -> Result<Vec<DataLocale>, DataError>;
+}
+
+impl<M, P> IterableDynamicDataProvider<M> for Box<P>
+where
+ M: DataMarker,
+ P: IterableDynamicDataProvider<M> + ?Sized,
+{
+ fn supported_locales_for_key(&self, key: DataKey) -> Result<Vec<DataLocale>, DataError> {
+ (**self).supported_locales_for_key(key)
+ }
+}
diff --git a/vendor/icu_provider/src/datagen/mod.rs b/vendor/icu_provider/src/datagen/mod.rs
new file mode 100644
index 000000000..5ede82275
--- /dev/null
+++ b/vendor/icu_provider/src/datagen/mod.rs
@@ -0,0 +1,120 @@
+// 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 ).
+
+//! This module contains various utilities required to generate ICU4X data files, typically
+//! via the `icu_datagen` reference crate. End users should not need to consume anything in
+//! this module as a library unless defining new types that integrate with `icu_datagen`.
+//!
+//! This module can be enabled with the `datagen` feature on `icu_provider`.
+
+mod data_conversion;
+mod heap_measure;
+mod iter;
+mod payload;
+pub use data_conversion::DataConverter;
+pub use heap_measure::{HeapStats, HeapStatsMarker};
+pub use iter::IterableDataProvider;
+
+#[doc(hidden)] // exposed for make_exportable_provider
+pub use iter::IterableDynamicDataProvider;
+#[doc(hidden)] // exposed for make_exportable_provider
+pub use payload::{ExportBox, ExportMarker};
+
+use crate::prelude::*;
+
+/// An object capable of exporting data payloads in some form.
+pub trait DataExporter: Sync {
+ /// Save a `payload` corresponding to the given key and locale.
+ /// Takes non-mut self as it can be called concurrently.
+ fn put_payload(
+ &self,
+ key: DataKey,
+ locale: &DataLocale,
+ payload: &DataPayload<ExportMarker>,
+ ) -> Result<(), DataError>;
+
+ /// Function called after all keys have been fully dumped.
+ /// Takes non-mut self as it can be called concurrently.
+ fn flush(&self, _key: DataKey) -> Result<(), DataError> {
+ Ok(())
+ }
+
+ /// This function has to be called before the object is dropped (after all
+ /// keys have been fully dumped). This conceptually takes ownership, so
+ /// clients *may not* interact with this object after close has been called.
+ fn close(&mut self) -> Result<(), DataError> {
+ Ok(())
+ }
+}
+
+/// A [`DynamicDataProvider`] that can be used for exporting data.
+///
+/// Use [`make_exportable_provider`] to implement this.
+pub trait ExportableProvider: IterableDynamicDataProvider<ExportMarker> + Sync {}
+impl<T> ExportableProvider for T where T: IterableDynamicDataProvider<ExportMarker> + Sync {}
+
+/// This macro can be used on a data provider to allow it to be used for data generation.
+///
+/// Data generation 'compiles' data by using this data provider (which usually translates data from
+/// different sources and doesn't have to be efficient) to generate data structs, and then writing
+/// them to an efficient format like [`BlobDataProvider`] or [`BakedDataProvider`]. The requirements
+/// for `make_exportable_provider` are:
+/// * The data struct has to implement [`serde::Serialize`](::serde::Serialize) and [`databake::Bake`]
+/// * The provider needs to implement [`IterableDataProvider`] for all specified [`KeyedDataMarker`]s.
+/// This allows the generating code to know which [`DataLocale`] to collect.
+///
+/// [`BlobDataProvider`]: ../../icu_provider_blob/struct.BlobDataProvider.html
+/// [`BakedDataProvider`]: ../../icu_datagen/index.html
+#[macro_export]
+macro_rules! make_exportable_provider {
+ ($provider:ty, [ $($struct_m:ident),+, ]) => {
+ $crate::impl_dynamic_data_provider!(
+ $provider,
+ [ $($struct_m),+, ],
+ $crate::datagen::ExportMarker
+ );
+ $crate::impl_dynamic_data_provider!(
+ $provider,
+ [ $($struct_m),+, ],
+ $crate::any::AnyMarker
+ );
+
+ impl $crate::datagen::IterableDynamicDataProvider<$crate::datagen::ExportMarker> for $provider {
+ fn supported_locales_for_key(&self, key: $crate::DataKey) -> Result<Vec<$crate::DataLocale>, $crate::DataError> {
+ #![allow(non_upper_case_globals)]
+ // Reusing the struct names as identifiers
+ $(
+ const $struct_m: $crate::DataKeyHash = <$struct_m as $crate::KeyedDataMarker>::KEY.hashed();
+ )+
+ match key.hashed() {
+ $(
+ $struct_m => {
+ $crate::datagen::IterableDataProvider::<$struct_m>::supported_locales(self)
+ }
+ )+,
+ _ => Err($crate::DataErrorKind::MissingDataKey.with_key(key))
+ }
+ }
+ }
+
+ impl $crate::datagen::DataConverter<$crate::buf::BufferMarker, $crate::datagen::HeapStatsMarker> for $provider {
+ fn convert(&self, key: $crate::DataKey, from: $crate::DataPayload<$crate::buf::BufferMarker>) -> Result<$crate::DataPayload<$crate::datagen::HeapStatsMarker>, ($crate::DataPayload<$crate::buf::BufferMarker>, $crate::DataError)> {
+ #![allow(non_upper_case_globals)]
+ // Reusing the struct names as identifiers
+ $(
+ const $struct_m: $crate::DataKeyHash = <$struct_m as $crate::KeyedDataMarker>::KEY.hashed();
+ )+
+ match key.hashed() {
+ $(
+ $struct_m => {
+ let heap_stats = from.attempt_zero_copy_heap_size::<$struct_m>();
+ return Ok($crate::DataPayload::from_owned(heap_stats));
+ }
+ )+,
+ _ => Err((from, $crate::DataErrorKind::MissingDataKey.with_key(key)))
+ }
+ }
+ }
+ };
+}
diff --git a/vendor/icu_provider/src/datagen/payload.rs b/vendor/icu_provider/src/datagen/payload.rs
new file mode 100644
index 000000000..b6ea8049f
--- /dev/null
+++ b/vendor/icu_provider/src/datagen/payload.rs
@@ -0,0 +1,137 @@
+// 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 ).
+
+use crate::dynutil::UpcastDataPayload;
+use crate::prelude::*;
+use crate::yoke::*;
+use alloc::boxed::Box;
+use databake::{Bake, CrateEnv, TokenStream};
+
+trait ExportableYoke {
+ fn bake_yoke(&self, env: &CrateEnv) -> TokenStream;
+ fn serialize_yoke(
+ &self,
+ serializer: &mut dyn erased_serde::Serializer,
+ ) -> Result<(), DataError>;
+}
+
+impl<Y, C> ExportableYoke for Yoke<Y, C>
+where
+ Y: for<'a> Yokeable<'a>,
+ for<'a> <Y as Yokeable<'a>>::Output: Bake + serde::Serialize,
+{
+ fn bake_yoke(&self, ctx: &CrateEnv) -> TokenStream {
+ self.get().bake(ctx)
+ }
+
+ fn serialize_yoke(
+ &self,
+ serializer: &mut dyn erased_serde::Serializer,
+ ) -> Result<(), DataError> {
+ use erased_serde::Serialize;
+ self.get()
+ .erased_serialize(serializer)
+ .map_err(|e| DataError::custom("Serde export").with_display_context(&e))?;
+ Ok(())
+ }
+}
+
+#[doc(hidden)] // exposed for make_exportable_provider
+#[derive(yoke::Yokeable)]
+pub struct ExportBox {
+ payload: Box<dyn ExportableYoke + Sync>,
+}
+
+impl<M> UpcastDataPayload<M> for ExportMarker
+where
+ M: DataMarker,
+ M::Yokeable: Sync,
+ for<'a> <M::Yokeable as Yokeable<'a>>::Output: Bake + serde::Serialize,
+{
+ fn upcast(other: DataPayload<M>) -> DataPayload<ExportMarker> {
+ DataPayload::from_owned(ExportBox {
+ payload: Box::new(other.yoke),
+ })
+ }
+}
+
+impl DataPayload<ExportMarker> {
+ /// Serializes this [`DataPayload`] into a serializer using Serde.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_provider::datagen::*;
+ /// use icu_provider::dynutil::UpcastDataPayload;
+ /// use icu_provider::hello_world::HelloWorldV1Marker;
+ /// use icu_provider::prelude::*;
+ ///
+ /// // Create an example DataPayload
+ /// let payload: DataPayload<HelloWorldV1Marker> = Default::default();
+ /// let export: DataPayload<ExportMarker> = UpcastDataPayload::upcast(payload);
+ ///
+ /// // Serialize the payload to a JSON string
+ /// let mut buffer: Vec<u8> = vec![];
+ /// export
+ /// .serialize(&mut serde_json::Serializer::new(&mut buffer))
+ /// .expect("Serialization should succeed");
+ /// assert_eq!("{\"message\":\"(und) Hello World\"}".as_bytes(), buffer);
+ /// ```
+ pub fn serialize<S>(&self, serializer: S) -> Result<(), DataError>
+ where
+ S: serde::Serializer,
+ S::Ok: 'static, // erased_serde requirement, cannot return values in `Ok`
+ {
+ self.get()
+ .payload
+ .serialize_yoke(&mut <dyn erased_serde::Serializer>::erase(serializer))
+ }
+
+ /// Serializes this [`DataPayload`]'s value into a [`TokenStream`]
+ /// using its [`Bake`] implementations.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_provider::datagen::*;
+ /// use icu_provider::dynutil::UpcastDataPayload;
+ /// use icu_provider::hello_world::HelloWorldV1Marker;
+ /// use icu_provider::prelude::*;
+ /// # use databake::quote;
+ /// # use std::collections::BTreeSet;
+ ///
+ /// // Create an example DataPayload
+ /// let payload: DataPayload<HelloWorldV1Marker> = Default::default();
+ /// let export: DataPayload<ExportMarker> = UpcastDataPayload::upcast(payload);
+ ///
+ /// let env = databake::CrateEnv::default();
+ /// let tokens = export.tokenize(&env);
+ /// assert_eq!(
+ /// quote! {
+ /// ::icu_provider::hello_world::HelloWorldV1 {
+ /// message: alloc::borrow::Cow::Borrowed("(und) Hello World"),
+ /// }
+ /// }
+ /// .to_string(),
+ /// tokens.to_string()
+ /// );
+ /// assert_eq!(
+ /// env.into_iter().collect::<BTreeSet<_>>(),
+ /// ["icu_provider", "alloc"]
+ /// .into_iter()
+ /// .collect::<BTreeSet<_>>()
+ /// );
+ /// ```
+ pub fn tokenize(&self, env: &CrateEnv) -> TokenStream {
+ self.get().payload.bake_yoke(env)
+ }
+}
+
+/// Marker type for [`ExportBox`].
+#[allow(clippy::exhaustive_structs)] // marker type
+pub struct ExportMarker {}
+
+impl DataMarker for ExportMarker {
+ type Yokeable = ExportBox;
+}
diff --git a/vendor/icu_provider/src/dynutil.rs b/vendor/icu_provider/src/dynutil.rs
new file mode 100644
index 000000000..89d7d7ded
--- /dev/null
+++ b/vendor/icu_provider/src/dynutil.rs
@@ -0,0 +1,263 @@
+// 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 ).
+
+//! Utilities for using trait objects with `DataPayload`.
+
+/// Trait to allow conversion from `DataPayload<T>` to `DataPayload<S>`.
+///
+/// This trait can be manually implemented in order to enable [`impl_dynamic_data_provider`].
+///
+/// [`DataPayload::downcast`]: crate::DataPayload::downcast
+pub trait UpcastDataPayload<M>
+where
+ M: crate::DataMarker,
+ Self: Sized + crate::DataMarker,
+{
+ /// Upcast a `DataPayload<T>` to a `DataPayload<S>` where `T` implements trait `S`.
+ ///
+ /// # Examples
+ ///
+ /// Upcast and then downcast a data struct of type `Cow<str>` (cart type `String`) via
+ /// [`AnyPayload`](crate::any::AnyPayload):
+ ///
+ /// ```
+ /// use icu_provider::dynutil::UpcastDataPayload;
+ /// use icu_provider::hello_world::*;
+ /// use icu_provider::prelude::*;
+ /// use std::borrow::Cow;
+ ///
+ /// let original = DataPayload::<HelloWorldV1Marker>::from_static_str("foo");
+ /// let upcasted = AnyMarker::upcast(original);
+ /// let downcasted = upcasted
+ /// .downcast::<HelloWorldV1Marker>()
+ /// .expect("Type conversion");
+ /// assert_eq!(downcasted.get().message, "foo");
+ /// ```
+ fn upcast(other: crate::DataPayload<M>) -> crate::DataPayload<Self>;
+}
+
+/// Implements [`UpcastDataPayload`] from several data markers to a single data marker
+/// that all share the same [`DataMarker::Yokeable`].
+///
+/// # Examples
+///
+/// ```
+/// use icu_provider::prelude::*;
+/// use std::borrow::Cow;
+///
+/// #[icu_provider::data_struct(
+/// FooV1Marker,
+/// BarV1Marker = "demo/bar@1",
+/// BazV1Marker = "demo/baz@1"
+/// )]
+/// pub struct FooV1<'data> {
+/// message: Cow<'data, str>,
+/// };
+///
+/// icu_provider::impl_casting_upcast!(
+/// FooV1Marker,
+/// [BarV1Marker, BazV1Marker,]
+/// );
+/// ```
+///
+/// [`DataMarker::Yokeable`]: crate::DataMarker::Yokeable
+#[macro_export]
+macro_rules! impl_casting_upcast {
+ ($dyn_m:path, [ $($struct_m:ident),+, ]) => {
+ $(
+ impl $crate::dynutil::UpcastDataPayload<$struct_m> for $dyn_m {
+ fn upcast(other: $crate::DataPayload<$struct_m>) -> $crate::DataPayload<$dyn_m> {
+ other.cast()
+ }
+ }
+ )+
+ }
+}
+
+/// Implements [`DynamicDataProvider`] for a marker type `S` on a type that already implements
+/// [`DynamicDataProvider`] or [`DataProvider`] for one or more `M`, where `M` is a concrete type
+/// that is convertible to `S` via [`UpcastDataPayload`].
+///
+/// Use this macro to add support to your data provider for:
+///
+/// - [`AnyPayload`] if your provider can return typed objects as [`Any`](core::any::Any).
+///
+/// ## Wrapping DataProvider
+///
+/// If your type implements [`DataProvider`], pass a list of markers as the second argument.
+/// This results in a `DynamicDataProvider` that delegates to a specific marker if the key
+/// matches or else returns [`DataErrorKind::MissingDataKey`].
+///
+/// ```
+/// use icu_provider::prelude::*;
+/// use icu_provider::hello_world::*;
+/// #
+/// # // Duplicating HelloWorldProvider because the real one already implements DynamicDataProvider<AnyMarker>
+/// # struct HelloWorldProvider;
+/// # impl DataProvider<HelloWorldV1Marker> for HelloWorldProvider {
+/// # fn load(
+/// # &self,
+/// # req: DataRequest,
+/// # ) -> Result<DataResponse<HelloWorldV1Marker>, DataError> {
+/// # icu_provider::hello_world::HelloWorldProvider.load(req)
+/// # }
+/// # }
+///
+/// // Implement DynamicDataProvider<AnyMarker> on HelloWorldProvider: DataProvider<HelloWorldV1Marker>
+/// icu_provider::impl_dynamic_data_provider!(HelloWorldProvider, [HelloWorldV1Marker,], AnyMarker);
+///
+/// let req = DataRequest {
+/// locale: &icu_locid::locale!("de").into(),
+/// metadata: Default::default(),
+/// };
+///
+/// // Successful because the key matches:
+/// HelloWorldProvider.load_data(HelloWorldV1Marker::KEY, req).unwrap();
+///
+/// // MissingDataKey error as the key does not match:
+/// assert_eq!(
+/// HelloWorldProvider.load_data(icu_provider::data_key!("dummy@1"), req).unwrap_err().kind,
+/// DataErrorKind::MissingDataKey,
+/// );
+/// ```
+///
+/// ## Wrapping DynamicDataProvider
+///
+/// It is also possible to wrap a [`DynamicDataProvider`] to create another [`DynamicDataProvider`]. To do this,
+/// pass a match-like statement for keys as the second argument:
+///
+/// ```
+/// use icu_provider::prelude::*;
+/// use icu_provider::hello_world::*;
+/// #
+/// # struct HelloWorldProvider;
+/// # impl DynamicDataProvider<HelloWorldV1Marker> for HelloWorldProvider {
+/// # fn load_data(&self, key: DataKey, req: DataRequest)
+/// # -> Result<DataResponse<HelloWorldV1Marker>, DataError> {
+/// # icu_provider::hello_world::HelloWorldProvider.load(req)
+/// # }
+/// # }
+///
+/// // Implement DataProvider<AnyMarker> on HelloWorldProvider: DynamicDataProvider<HelloWorldV1Marker>
+/// icu_provider::impl_dynamic_data_provider!(HelloWorldProvider, {
+/// // Match HelloWorldV1Marker::KEY and delegate to DynamicDataProvider<HelloWorldV1Marker>.
+/// HW = HelloWorldV1Marker::KEY => HelloWorldV1Marker,
+/// // Send the wildcard match also to DynamicDataProvider<HelloWorldV1Marker>.
+/// _ => HelloWorldV1Marker,
+/// }, AnyMarker);
+///
+/// let req = DataRequest {
+/// locale: &icu_locid::locale!("de").into(),
+/// metadata: Default::default(),
+/// };
+///
+/// // Successful because the key matches:
+/// HelloWorldProvider.as_any_provider().load_any(HelloWorldV1Marker::KEY, req).unwrap();
+///
+/// // Because of the wildcard, any key actually works:
+/// HelloWorldProvider.as_any_provider().load_any(icu_provider::data_key!("dummy@1"), req).unwrap();
+/// ```
+///
+/// [`DynamicDataProvider`]: crate::DynamicDataProvider
+/// [`DataProvider`]: crate::DataProvider
+/// [`AnyPayload`]: (crate::any::AnyPayload)
+/// [`DataErrorKind::MissingDataKey`]: (crate::DataErrorKind::MissingDataKey)
+/// [`SerializeMarker`]: (crate::serde::SerializeMarker)
+#[macro_export]
+macro_rules! impl_dynamic_data_provider {
+ // allow passing in multiple things to do and get dispatched
+ ($provider:ty, $arms:tt, $one:path, $($rest:path),+) => {
+ $crate::impl_dynamic_data_provider!(
+ $provider,
+ $arms,
+ $one
+ );
+
+ $crate::impl_dynamic_data_provider!(
+ $provider,
+ $arms,
+ $($rest),+
+ );
+ };
+
+ ($provider:ty, { $($ident:ident = $key:path => $struct_m:ty),+, $(_ => $struct_d:ty,)?}, $dyn_m:ty) => {
+ impl $crate::DynamicDataProvider<$dyn_m> for $provider
+ {
+ fn load_data(
+ &self,
+ key: $crate::DataKey,
+ req: $crate::DataRequest,
+ ) -> Result<
+ $crate::DataResponse<$dyn_m>,
+ $crate::DataError,
+ > {
+ $(
+ const $ident: $crate::DataKeyHash = $key.hashed();
+ )+
+ match key.hashed() {
+ $(
+ $ident => {
+ let result: $crate::DataResponse<$struct_m> =
+ $crate::DynamicDataProvider::<$struct_m>::load_data(self, key, req)?;
+ Ok($crate::DataResponse {
+ metadata: result.metadata,
+ payload: result.payload.map(|p| {
+ $crate::dynutil::UpcastDataPayload::<$struct_m>::upcast(p)
+ }),
+ })
+ }
+ )+,
+ $(
+ _ => {
+ let result: $crate::DataResponse<$struct_d> =
+ $crate::DynamicDataProvider::<$struct_d>::load_data(self, key, req)?;
+ Ok($crate::DataResponse {
+ metadata: result.metadata,
+ payload: result.payload.map(|p| {
+ $crate::dynutil::UpcastDataPayload::<$struct_d>::upcast(p)
+ }),
+ })
+ }
+ )?
+ _ => Err($crate::DataErrorKind::MissingDataKey.with_req(key, req))
+ }
+ }
+ }
+
+ };
+ ($provider:ty, [ $($struct_m:ident),+, ], $dyn_m:path) => {
+ impl $crate::DynamicDataProvider<$dyn_m> for $provider
+ {
+ fn load_data(
+ &self,
+ key: $crate::DataKey,
+ req: $crate::DataRequest,
+ ) -> Result<
+ $crate::DataResponse<$dyn_m>,
+ $crate::DataError,
+ > {
+ #![allow(non_upper_case_globals)]
+ // Reusing the struct names as identifiers
+ $(
+ const $struct_m: $crate::DataKeyHash = $struct_m::KEY.hashed();
+ )+
+ match key.hashed() {
+ $(
+ $struct_m => {
+ let result: $crate::DataResponse<$struct_m> =
+ $crate::DataProvider::load(self, req)?;
+ Ok($crate::DataResponse {
+ metadata: result.metadata,
+ payload: result.payload.map(|p| {
+ $crate::dynutil::UpcastDataPayload::<$struct_m>::upcast(p)
+ }),
+ })
+ }
+ )+,
+ _ => Err($crate::DataErrorKind::MissingDataKey.with_req(key, req))
+ }
+ }
+ }
+ };
+}
diff --git a/vendor/icu_provider/src/error.rs b/vendor/icu_provider/src/error.rs
new file mode 100644
index 000000000..39bd1d0bb
--- /dev/null
+++ b/vendor/icu_provider/src/error.rs
@@ -0,0 +1,267 @@
+// 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 ).
+
+use crate::buf::BufferFormat;
+use crate::prelude::*;
+use core::fmt;
+use displaydoc::Display;
+
+/// A list specifying general categories of data provider error.
+///
+/// Errors may be caused either by a malformed request or by the data provider
+/// not being able to fulfill a well-formed request.
+#[derive(Clone, Copy, Eq, PartialEq, Display, Debug)]
+#[non_exhaustive]
+pub enum DataErrorKind {
+ /// No data for the provided resource key.
+ #[displaydoc("Missing data for key")]
+ MissingDataKey,
+
+ /// There is data for the key, but not for this particular locale.
+ #[displaydoc("Missing data for locale")]
+ MissingLocale,
+
+ /// The request should include a locale.
+ #[displaydoc("Request needs a locale")]
+ NeedsLocale,
+
+ /// The request should not contain a locale.
+ #[displaydoc("Request has an extraneous locale")]
+ ExtraneousLocale,
+
+ /// The resource was blocked by a filter. The resource may or may not be available.
+ #[displaydoc("Resource blocked by filter")]
+ FilteredResource,
+
+ /// The generic type parameter does not match the TypeId. The expected type name is stored
+ /// as context when this error is returned.
+ #[displaydoc("Mismatched types: tried to downcast with {0}, but actual type is different")]
+ MismatchedType(&'static str),
+
+ /// The payload is missing. This is usually caused by a previous error.
+ #[displaydoc("Missing payload")]
+ MissingPayload,
+
+ /// A data provider object was given to an operation in an invalid state.
+ #[displaydoc("Invalid state")]
+ InvalidState,
+
+ /// An unspecified error occurred, such as a Serde error.
+ ///
+ /// Check debug logs for potentially more information.
+ #[displaydoc("Custom")]
+ Custom,
+
+ /// An error occurred while accessing a system resource.
+ #[displaydoc("I/O error: {0:?}")]
+ #[cfg(feature = "std")]
+ Io(std::io::ErrorKind),
+
+ /// An unspecified data source containing the required data is unavailable.
+ #[displaydoc("Missing source data")]
+ #[cfg(feature = "datagen")]
+ MissingSourceData,
+
+ /// An error indicating that the desired buffer format is not available. This usually
+ /// means that a required feature was not enabled
+ #[displaydoc("Unavailable buffer format: {0:?} (does icu_provider need to be compiled with an additional feature?)")]
+ UnavailableBufferFormat(BufferFormat),
+}
+
+/// The error type for ICU4X data provider operations.
+///
+/// To create one of these, either start with a [`DataErrorKind`] or use [`DataError::custom()`].
+///
+/// # Example
+///
+/// Create a NeedsLocale error and attach a data request for context:
+///
+/// ```no_run
+/// # use icu_provider::prelude::*;
+/// let key: DataKey = unimplemented!();
+/// let req: DataRequest = unimplemented!();
+/// DataErrorKind::NeedsLocale.with_req(key, req);
+/// ```
+///
+/// Create a named custom error:
+///
+/// ```
+/// # use icu_provider::prelude::*;
+/// DataError::custom("This is an example error");
+/// ```
+#[derive(Clone, Copy, Eq, PartialEq, Debug)]
+#[non_exhaustive]
+pub struct DataError {
+ /// Broad category of the error.
+ pub kind: DataErrorKind,
+
+ /// The data key of the request, if available.
+ pub key: Option<DataKey>,
+
+ /// Additional context, if available.
+ pub str_context: Option<&'static str>,
+}
+
+impl fmt::Display for DataError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ICU4X data error")?;
+ if self.kind != DataErrorKind::Custom {
+ write!(f, ": {}", self.kind)?;
+ }
+ if let Some(key) = self.key {
+ write!(f, " (key: {})", key)?;
+ }
+ if let Some(str_context) = self.str_context {
+ write!(f, ": {}", str_context)?;
+ }
+ Ok(())
+ }
+}
+
+impl DataErrorKind {
+ /// Converts this DataErrorKind into a DataError.
+ ///
+ /// If possible, you should attach context using a `with_` function.
+ #[inline]
+ pub const fn into_error(self) -> DataError {
+ DataError {
+ kind: self,
+ key: None,
+ str_context: None,
+ }
+ }
+
+ /// Creates a DataError with a resource key context.
+ #[inline]
+ pub const fn with_key(self, key: DataKey) -> DataError {
+ self.into_error().with_key(key)
+ }
+
+ /// Creates a DataError with a string context.
+ #[inline]
+ pub const fn with_str_context(self, context: &'static str) -> DataError {
+ self.into_error().with_str_context(context)
+ }
+
+ /// Creates a DataError with a type name context.
+ #[inline]
+ pub fn with_type_context<T>(self) -> DataError {
+ self.into_error().with_type_context::<T>()
+ }
+
+ /// Creates a DataError with a request context.
+ #[inline]
+ pub fn with_req(self, key: DataKey, req: DataRequest) -> DataError {
+ self.into_error().with_req(key, req)
+ }
+}
+
+impl DataError {
+ /// Returns a new, empty DataError with kind Custom and a string error message.
+ #[inline]
+ pub const fn custom(str_context: &'static str) -> Self {
+ Self {
+ kind: DataErrorKind::Custom,
+ key: None,
+ str_context: Some(str_context),
+ }
+ }
+
+ /// Sets the resource key of a DataError, returning a modified error.
+ #[inline]
+ pub const fn with_key(self, key: DataKey) -> Self {
+ Self {
+ kind: self.kind,
+ key: Some(key),
+ str_context: self.str_context,
+ }
+ }
+
+ /// Sets the string context of a DataError, returning a modified error.
+ #[inline]
+ pub const fn with_str_context(self, context: &'static str) -> Self {
+ Self {
+ kind: self.kind,
+ key: self.key,
+ str_context: Some(context),
+ }
+ }
+
+ /// Sets the string context of a DataError to the given type name, returning a modified error.
+ #[inline]
+ pub fn with_type_context<T>(self) -> Self {
+ self.with_str_context(core::any::type_name::<T>())
+ }
+
+ /// Logs the data error with the given request, returning an error containing the resource key.
+ ///
+ /// If the "log_error_context" feature is enabled, this logs the whole request. Either way,
+ /// it returns an error with the resource key portion of the request as context.
+ #[cfg_attr(not(feature = "log_error_context"), allow(unused_variables))]
+ pub fn with_req(self, key: DataKey, req: DataRequest) -> Self {
+ // Don't write out a log for MissingDataKey since there is no context to add
+ #[cfg(feature = "log_error_context")]
+ if self.kind != DataErrorKind::MissingDataKey {
+ log::warn!("{} (key: {}, request: {})", self, key, req);
+ }
+ self.with_key(key)
+ }
+
+ /// Logs the data error with the given context, then return self.
+ ///
+ /// This does not modify the error, but if the "log_error_context" feature is enabled,
+ /// it will print out the context.
+ #[cfg(feature = "std")]
+ #[cfg_attr(not(feature = "log_error_context"), allow(unused_variables))]
+ pub fn with_path_context<P: AsRef<std::path::Path> + ?Sized>(self, path: &P) -> Self {
+ #[cfg(feature = "log_error_context")]
+ log::warn!("{} (path: {:?})", self, path.as_ref());
+ self
+ }
+
+ /// Logs the data error with the given context, then return self.
+ ///
+ /// This does not modify the error, but if the "log_error_context" feature is enabled,
+ /// it will print out the context.
+ #[cfg_attr(not(feature = "log_error_context"), allow(unused_variables))]
+ #[inline]
+ pub fn with_display_context<D: fmt::Display + ?Sized>(self, context: &D) -> Self {
+ #[cfg(feature = "log_error_context")]
+ log::warn!("{}: {}", self, context);
+ self
+ }
+
+ /// Logs the data error with the given context, then return self.
+ ///
+ /// This does not modify the error, but if the "log_error_context" feature is enabled,
+ /// it will print out the context.
+ #[cfg_attr(not(feature = "log_error_context"), allow(unused_variables))]
+ #[inline]
+ pub fn with_debug_context<D: fmt::Debug + ?Sized>(self, context: &D) -> Self {
+ #[cfg(feature = "log_error_context")]
+ log::warn!("{}: {:?}", self, context);
+ self
+ }
+
+ #[inline]
+ pub(crate) fn for_type<T>() -> DataError {
+ DataError {
+ kind: DataErrorKind::MismatchedType(core::any::type_name::<T>()),
+ key: None,
+ str_context: None,
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for DataError {}
+
+#[cfg(feature = "std")]
+impl From<std::io::Error> for DataError {
+ fn from(e: std::io::Error) -> Self {
+ #[cfg(feature = "log_error_context")]
+ log::warn!("I/O error: {}", e);
+ DataErrorKind::Io(e.kind()).into_error()
+ }
+}
diff --git a/vendor/icu_provider/src/hello_world.rs b/vendor/icu_provider/src/hello_world.rs
new file mode 100644
index 000000000..5fa671d84
--- /dev/null
+++ b/vendor/icu_provider/src/hello_world.rs
@@ -0,0 +1,307 @@
+// 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 ).
+
+//! Data provider returning multilingual "Hello World" strings for testing.
+
+#![allow(clippy::exhaustive_structs)] // data struct module
+
+use crate::buf::BufferFormat;
+#[cfg(feature = "datagen")]
+use crate::datagen::IterableDataProvider;
+use crate::helpers;
+use crate::prelude::*;
+use crate::yoke::{self, *};
+use crate::zerofrom::{self, *};
+use alloc::borrow::Cow;
+use alloc::string::String;
+use core::fmt::Debug;
+use writeable::Writeable;
+
+/// A struct containing "Hello World" in the requested language.
+#[derive(Debug, PartialEq, Clone, Yokeable, ZeroFrom)]
+#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
+#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
+#[cfg_attr(feature = "datagen", databake(path = icu_provider::hello_world))]
+pub struct HelloWorldV1<'data> {
+ /// The translation of "Hello World".
+ #[cfg_attr(feature = "serde", serde(borrow))]
+ pub message: Cow<'data, str>,
+}
+
+impl Default for HelloWorldV1<'_> {
+ fn default() -> Self {
+ HelloWorldV1 {
+ message: Cow::Borrowed("(und) Hello World"),
+ }
+ }
+}
+
+/// Marker type for [`HelloWorldV1`].
+#[cfg_attr(feature = "datagen", derive(Default, databake::Bake))]
+#[cfg_attr(feature = "datagen", databake(path = icu_provider::hello_world))]
+pub struct HelloWorldV1Marker;
+
+impl DataMarker for HelloWorldV1Marker {
+ type Yokeable = HelloWorldV1<'static>;
+}
+
+impl KeyedDataMarker for HelloWorldV1Marker {
+ const KEY: DataKey = crate::data_key!("core/helloworld@1");
+}
+
+/// A data provider returning Hello World strings in different languages.
+///
+/// Mostly useful for testing.
+///
+/// # Examples
+///
+/// ```
+/// use icu_locid::locale;
+/// use icu_provider::hello_world::*;
+/// use icu_provider::prelude::*;
+///
+/// let german_hello_world: DataPayload<HelloWorldV1Marker> =
+/// HelloWorldProvider
+/// .load(DataRequest {
+/// locale: &locale!("de").into(),
+/// metadata: Default::default(),
+/// })
+/// .expect("Loading should succeed")
+/// .take_payload()
+/// .expect("Data should be present");
+///
+/// assert_eq!("Hallo Welt", german_hello_world.get().message);
+/// ```
+#[derive(Debug, PartialEq, Default)]
+pub struct HelloWorldProvider;
+
+impl HelloWorldProvider {
+ // Data from https://en.wiktionary.org/wiki/Hello_World#Translations
+ // Keep this sorted!
+ const DATA: &'static [(&'static str, &'static str)] = &[
+ ("bn", "ওহে বিশ্ব"),
+ ("cs", "Ahoj světe"),
+ ("de", "Hallo Welt"),
+ ("el", "Καλημέρα κόσμε"),
+ ("en", "Hello World"),
+ ("eo", "Saluton, Mondo"),
+ ("fa", "سلام دنیا‎"),
+ ("fi", "hei maailma"),
+ ("is", "Halló, heimur"),
+ ("ja", "こんにちは世界"),
+ ("la", "Ave, munde"),
+ ("pt", "Olá, mundo"),
+ ("ro", "Salut, lume"),
+ ("ru", "Привет, мир"),
+ ("vi", "Xin chào thế giới"),
+ ("zh", "你好世界"),
+ ];
+
+ /// Converts this provider into one that serves JSON blobs of the same data.
+ pub fn into_json_provider(self) -> HelloWorldJsonProvider {
+ HelloWorldJsonProvider(self)
+ }
+}
+
+impl DataProvider<HelloWorldV1Marker> for HelloWorldProvider {
+ fn load(&self, req: DataRequest) -> Result<DataResponse<HelloWorldV1Marker>, DataError> {
+ #[allow(clippy::indexing_slicing)] // binary_search
+ let data = Self::DATA
+ .binary_search_by(|(k, _)| req.locale.strict_cmp(k.as_bytes()).reverse())
+ .map(|i| Self::DATA[i].1)
+ .map(|s| HelloWorldV1 {
+ message: Cow::Borrowed(s),
+ })
+ .map_err(|_| DataErrorKind::MissingLocale.with_req(HelloWorldV1Marker::KEY, req))?;
+ Ok(DataResponse {
+ metadata: Default::default(),
+ payload: Some(DataPayload::from_owned(data)),
+ })
+ }
+}
+
+impl DataPayload<HelloWorldV1Marker> {
+ /// Make a [`DataPayload`]`<`[`HelloWorldV1Marker`]`>` from a static string slice.
+ pub fn from_static_str(s: &'static str) -> DataPayload<HelloWorldV1Marker> {
+ DataPayload::from_owned(HelloWorldV1 {
+ message: Cow::Borrowed(s),
+ })
+ }
+}
+
+#[cfg(not(feature = "datagen"))]
+impl_dynamic_data_provider!(HelloWorldProvider, [HelloWorldV1Marker,], AnyMarker);
+
+#[cfg(feature = "datagen")]
+make_exportable_provider!(HelloWorldProvider, [HelloWorldV1Marker,]);
+
+/// A data provider returning Hello World strings in different languages as JSON blobs.
+///
+/// Mostly useful for testing.
+///
+/// # Examples
+///
+/// ```
+/// use icu_locid::locale;
+/// use icu_provider::hello_world::*;
+/// use icu_provider::prelude::*;
+///
+/// let german_hello_world = HelloWorldProvider
+/// .into_json_provider()
+/// .load_buffer(HelloWorldV1Marker::KEY, DataRequest {
+/// locale: &locale!("de").into(),
+/// metadata: Default::default(),
+/// })
+/// .expect("Loading should succeed")
+/// .take_payload()
+/// .expect("Data should be present");
+///
+/// assert_eq!(b"{\"message\":\"Hallo Welt\"}", german_hello_world.get());
+pub struct HelloWorldJsonProvider(HelloWorldProvider);
+
+impl BufferProvider for HelloWorldJsonProvider {
+ fn load_buffer(
+ &self,
+ key: DataKey,
+ req: DataRequest,
+ ) -> Result<DataResponse<BufferMarker>, DataError> {
+ key.match_key(HelloWorldV1Marker::KEY)?;
+ let result = self.0.load(req)?;
+ let (mut metadata, old_payload) =
+ DataResponse::<HelloWorldV1Marker>::take_metadata_and_payload(result)?;
+ metadata.buffer_format = Some(BufferFormat::Json);
+ let mut buffer = String::new();
+ buffer.push_str("{\"message\":\"");
+ helpers::escape_for_json(&old_payload.get().message, &mut buffer);
+ buffer.push_str("\"}");
+ Ok(DataResponse {
+ metadata,
+ payload: Some(DataPayload::from_owned_buffer(
+ buffer.into_bytes().into_boxed_slice(),
+ )),
+ })
+ }
+}
+
+/// A type that formats localized "hello world" strings.
+///
+/// This type is intended to take the shape of a typical ICU4X formatter API.
+///
+/// # Examples
+///
+/// ```
+/// use icu_locid::locale;
+/// use icu_provider::hello_world::{HelloWorldFormatter, HelloWorldProvider};
+/// use writeable::assert_writeable_eq;
+///
+/// let fmt = HelloWorldFormatter::try_new_unstable(
+/// &HelloWorldProvider,
+/// &locale!("eo").into(),
+/// )
+/// .expect("locale exists");
+///
+/// assert_writeable_eq!(fmt.format(), "Saluton, Mondo");
+/// ```
+pub struct HelloWorldFormatter {
+ data: DataPayload<HelloWorldV1Marker>,
+}
+
+/// A formatted hello world message. Implements [`Writeable`].
+///
+/// For an example, see [`HelloWorldFormatter`].
+pub struct FormattedHelloWorld<'l> {
+ data: &'l HelloWorldV1<'l>,
+}
+
+impl HelloWorldFormatter {
+ /// Creates a new [`HelloWorldFormatter`] for the specified locale.
+ ///
+ /// See [`HelloWorldFormatter`] for an example.
+ ///
+ /// [📚 Help choosing a constructor](crate::constructors)
+ /// <div class="stab unstable">
+ /// ⚠️ The bounds on this function may change over time, including in SemVer minor releases.
+ /// </div>
+ pub fn try_new_unstable<P>(provider: &P, locale: &DataLocale) -> Result<Self, DataError>
+ where
+ P: DataProvider<HelloWorldV1Marker>,
+ {
+ let data = provider
+ .load(DataRequest {
+ locale,
+ metadata: Default::default(),
+ })?
+ .take_payload()?;
+ Ok(Self { data })
+ }
+
+ crate::gen_any_buffer_constructors!(locale: include, options: skip, error: DataError);
+
+ /// Formats a hello world message, returning a [`FormattedHelloWorld`].
+ #[allow(clippy::needless_lifetimes)] // documentary example
+ pub fn format<'l>(&'l self) -> FormattedHelloWorld<'l> {
+ FormattedHelloWorld {
+ data: self.data.get(),
+ }
+ }
+
+ /// Formats a hello world message, returning a [`String`].
+ pub fn format_to_string(&self) -> String {
+ self.format().write_to_string().into_owned()
+ }
+}
+
+impl<'l> Writeable for FormattedHelloWorld<'l> {
+ fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
+ self.data.message.write_to(sink)
+ }
+
+ fn write_to_string(&self) -> Cow<str> {
+ self.data.message.clone()
+ }
+
+ fn writeable_length_hint(&self) -> writeable::LengthHint {
+ self.data.message.writeable_length_hint()
+ }
+}
+
+#[cfg(feature = "datagen")]
+impl IterableDataProvider<HelloWorldV1Marker> for HelloWorldProvider {
+ fn supported_locales(&self) -> Result<Vec<DataLocale>, DataError> {
+ #[allow(clippy::unwrap_used)] // datagen
+ Ok(Self::DATA
+ .iter()
+ .map(|(s, _)| s.parse::<icu_locid::LanguageIdentifier>().unwrap())
+ .map(DataLocale::from)
+ .collect())
+ }
+}
+
+#[cfg(feature = "datagen")]
+#[test]
+fn test_iter() {
+ use icu_locid::locale;
+
+ assert_eq!(
+ HelloWorldProvider.supported_locales().unwrap(),
+ vec![
+ locale!("bn").into(),
+ locale!("cs").into(),
+ locale!("de").into(),
+ locale!("el").into(),
+ locale!("en").into(),
+ locale!("eo").into(),
+ locale!("fa").into(),
+ locale!("fi").into(),
+ locale!("is").into(),
+ locale!("ja").into(),
+ locale!("la").into(),
+ locale!("pt").into(),
+ locale!("ro").into(),
+ locale!("ru").into(),
+ locale!("vi").into(),
+ locale!("zh").into()
+ ]
+ );
+}
diff --git a/vendor/icu_provider/src/helpers.rs b/vendor/icu_provider/src/helpers.rs
new file mode 100644
index 000000000..8d499f7ef
--- /dev/null
+++ b/vendor/icu_provider/src/helpers.rs
@@ -0,0 +1,369 @@
+// 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 ).
+
+//! Internal helper functions.
+
+use alloc::string::String;
+
+/// Prints a JSON-safe string to the output.
+pub fn escape_for_json<'o>(input: &str, output: &'o mut String) -> &'o mut String {
+ // From the ECMA-404 specification:
+ // "A string is a sequence of Unicode code points wrapped with quotation marks (U+0022).
+ // All code points may be placed within the quotation marks except for the code points
+ // that must be escaped: quotation mark (U+0022), reverse solidus (U+005C), and the
+ // control characters U+0000 to U+001F. There are two-character escape sequence
+ // representations of some characters."
+ for cp in input.chars() {
+ let str_to_append = match cp {
+ '\u{0000}' => "\\u0000",
+ '\u{0001}' => "\\u0001",
+ '\u{0002}' => "\\u0002",
+ '\u{0003}' => "\\u0003",
+ '\u{0004}' => "\\u0004",
+ '\u{0005}' => "\\u0005",
+ '\u{0006}' => "\\u0006",
+ '\u{0007}' => "\\u0007",
+ '\u{0008}' => "\\b",
+ '\u{0009}' => "\\t",
+ '\u{000A}' => "\\n",
+ '\u{000B}' => "\\u000B",
+ '\u{000C}' => "\\f",
+ '\u{000D}' => "\\r",
+ '\u{000E}' => "\\u000E",
+ '\u{000F}' => "\\u000F",
+ '\u{0010}' => "\\u0010",
+ '\u{0011}' => "\\u0011",
+ '\u{0012}' => "\\u0012",
+ '\u{0013}' => "\\u0013",
+ '\u{0014}' => "\\u0014",
+ '\u{0015}' => "\\u0015",
+ '\u{0016}' => "\\u0016",
+ '\u{0017}' => "\\u0017",
+ '\u{0018}' => "\\u0018",
+ '\u{0019}' => "\\u0019",
+ '\u{001A}' => "\\u001A",
+ '\u{001B}' => "\\u001B",
+ '\u{001C}' => "\\u001C",
+ '\u{001D}' => "\\u001D",
+ '\u{001E}' => "\\u001E",
+ '\u{001F}' => "\\u001F",
+ '\u{0022}' => "\\\"",
+ '\u{005C}' => "\\\\",
+ cp => {
+ output.push(cp);
+ continue;
+ }
+ };
+ output.push_str(str_to_append);
+ }
+ output
+}
+
+#[test]
+fn test_escape_for_json() {
+ assert_eq!("", escape_for_json("", &mut String::new()));
+ assert_eq!("abc", escape_for_json("abc", &mut String::new()));
+ assert_eq!("ab\\nc", escape_for_json("ab\nc", &mut String::new()));
+ assert_eq!("ab\\\\c", escape_for_json("ab\\c", &mut String::new()));
+ assert_eq!("ab\\\"c", escape_for_json("ab\"c", &mut String::new()));
+ assert_eq!(
+ "ab\\u0000c",
+ escape_for_json("ab\u{0000}c", &mut String::new())
+ );
+ assert_eq!(
+ "ab\\u001Fc",
+ escape_for_json("ab\u{001F}c", &mut String::new())
+ );
+}
+
+/// Const function to compute the FxHash of a byte array with little-endian byte order.
+///
+/// FxHash is a speedy hash algorithm used within rustc. The algorithm is satisfactory for our
+/// use case since the strings being hashed originate from a trusted source (the ICU4X
+/// components), and the hashes are computed at compile time, so we can check for collisions.
+///
+/// We could have considered a SHA or other cryptographic hash function. However, we are using
+/// FxHash because:
+///
+/// 1. There is precedent for this algorithm in Rust
+/// 2. The algorithm is easy to implement as a const function
+/// 3. The amount of code is small enough that we can reasonably keep the algorithm in-tree
+/// 4. FxHash is designed to output 32-bit or 64-bit values, whereas SHA outputs more bits,
+/// such that truncation would be required in order to fit into a u32, partially reducing
+/// the benefit of a cryptographically secure algorithm
+// The indexing operations in this function have been reviewed in detail and won't panic.
+#[allow(clippy::indexing_slicing)]
+pub const fn fxhash_32(bytes: &[u8], ignore_leading: usize, ignore_trailing: usize) -> u32 {
+ // This code is adapted from https://github.com/rust-lang/rustc-hash,
+ // whose license text is reproduced below.
+ //
+ // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+ // file at the top-level directory of this distribution and at
+ // http://rust-lang.org/COPYRIGHT.
+ //
+ // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+ // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+ // option. This file may not be copied, modified, or distributed
+ // except according to those terms.
+
+ if ignore_leading + ignore_trailing >= bytes.len() {
+ return 0;
+ }
+
+ #[inline]
+ const fn hash_word_32(mut hash: u32, word: u32) -> u32 {
+ const ROTATE: u32 = 5;
+ const SEED32: u32 = 0x9e_37_79_b9;
+ hash = hash.rotate_left(ROTATE);
+ hash ^= word;
+ hash = hash.wrapping_mul(SEED32);
+ hash
+ }
+
+ let mut cursor = ignore_leading;
+ let end = bytes.len() - ignore_trailing;
+ let mut hash = 0;
+
+ while end - cursor >= 4 {
+ let word = u32::from_le_bytes([
+ bytes[cursor],
+ bytes[cursor + 1],
+ bytes[cursor + 2],
+ bytes[cursor + 3],
+ ]);
+ hash = hash_word_32(hash, word);
+ cursor += 4;
+ }
+
+ if end - cursor >= 2 {
+ let word = u16::from_le_bytes([bytes[cursor], bytes[cursor + 1]]);
+ hash = hash_word_32(hash, word as u32);
+ cursor += 2;
+ }
+
+ if end - cursor >= 1 {
+ hash = hash_word_32(hash, bytes[cursor] as u32);
+ }
+
+ hash
+}
+
+#[test]
+fn test_hash_word_32() {
+ assert_eq!(0, fxhash_32(b"", 0, 0));
+ assert_eq!(0, fxhash_32(b"a", 1, 0));
+ assert_eq!(0, fxhash_32(b"a", 0, 1));
+ assert_eq!(0, fxhash_32(b"a", 0, 10));
+ assert_eq!(0, fxhash_32(b"a", 10, 0));
+ assert_eq!(0, fxhash_32(b"a", 1, 1));
+ assert_eq!(0xF3051F19, fxhash_32(b"a", 0, 0));
+ assert_eq!(0x2F9DF119, fxhash_32(b"ab", 0, 0));
+ assert_eq!(0xCB1D9396, fxhash_32(b"abc", 0, 0));
+ assert_eq!(0x8628F119, fxhash_32(b"abcd", 0, 0));
+ assert_eq!(0xBEBDB56D, fxhash_32(b"abcde", 0, 0));
+ assert_eq!(0x1CE8476D, fxhash_32(b"abcdef", 0, 0));
+ assert_eq!(0xC0F176A4, fxhash_32(b"abcdefg", 0, 0));
+ assert_eq!(0x09AB476D, fxhash_32(b"abcdefgh", 0, 0));
+ assert_eq!(0xB72F5D88, fxhash_32(b"abcdefghi", 0, 0));
+
+ assert_eq!(
+ fxhash_32(crate::tagged!("props/sc=Khmr@1").as_bytes(), 0, 0),
+ fxhash_32(crate::tagged!("props/sc=Samr@1").as_bytes(), 0, 0)
+ );
+
+ assert_ne!(
+ fxhash_32(
+ crate::tagged!("props/sc=Khmr@1").as_bytes(),
+ crate::leading_tag!().len(),
+ crate::trailing_tag!().len()
+ ),
+ fxhash_32(
+ crate::tagged!("props/sc=Samr@1").as_bytes(),
+ crate::leading_tag!().len(),
+ crate::trailing_tag!().len()
+ )
+ );
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! gen_any_buffer_docs {
+ (ANY, $krate:path, $see_also:path) => {
+ concat!(
+ "Creates a new instance using an [`AnyProvider`](",
+ stringify!($krate),
+ "::AnyProvider).\n\n",
+ "For details on the behavior of this function, see: [`",
+ stringify!($see_also),
+ "`]\n\n",
+ "[📚 Help choosing a constructor](",
+ stringify!($krate),
+ "::constructors)",
+ )
+ };
+ (BUFFER, $krate:path, $see_also:path) => {
+ concat!(
+ "✨ **Enabled with the `\"serde\"` feature.**\n\n",
+ "Creates a new instance using a [`BufferProvider`](",
+ stringify!($krate),
+ "::BufferProvider).\n\n",
+ "For details on the behavior of this function, see: [`",
+ stringify!($see_also),
+ "`]\n\n",
+ "[📚 Help choosing a constructor](",
+ stringify!($krate),
+ "::constructors)",
+ )
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! gen_any_buffer_constructors {
+ (locale: skip, options: skip, error: $error_ty:path) => {
+ $crate::gen_any_buffer_constructors!(
+ locale: skip,
+ options: skip,
+ error: $error_ty,
+ functions: [
+ Self::try_new_unstable,
+ try_new_with_any_provider,
+ try_new_with_buffer_provider
+ ]
+ );
+ };
+ (locale: skip, options: skip, error: $error_ty:path, functions: [$f1:path, $f2:ident, $f3:ident]) => {
+ #[doc = $crate::gen_any_buffer_docs!(ANY, $crate, $f1)]
+ pub fn $f2(provider: &(impl $crate::AnyProvider + ?Sized)) -> Result<Self, $error_ty> {
+ use $crate::AsDowncastingAnyProvider;
+ $f1(&provider.as_downcasting())
+ }
+ #[cfg(feature = "serde")]
+ #[doc = $crate::gen_any_buffer_docs!(BUFFER, $crate, $f1)]
+ pub fn $f3(provider: &(impl $crate::BufferProvider + ?Sized)) -> Result<Self, $error_ty> {
+ use $crate::AsDeserializingBufferProvider;
+ $f1(&provider.as_deserializing())
+ }
+ };
+
+ (locale: skip, $options_arg:ident: $options_ty:path, error: $error_ty:path) => {
+ $crate::gen_any_buffer_constructors!(
+ locale: skip,
+ $options_arg: $options_ty,
+ error: $error_ty,
+ functions: [
+ Self::try_new_unstable,
+ try_new_with_any_provider,
+ try_new_with_buffer_provider
+ ]
+ );
+ };
+ (locale: skip, $options_arg:ident: $options_ty:path, error: $error_ty:path, functions: [$f1:path, $f2:ident, $f3:ident]) => {
+ #[doc = $crate::gen_any_buffer_docs!(ANY, $crate, $f1)]
+ pub fn $f2(provider: &(impl $crate::AnyProvider + ?Sized), $options_arg: $options_ty) -> Result<Self, $error_ty> {
+ use $crate::AsDowncastingAnyProvider;
+ $f1(&provider.as_downcasting(), $options_arg)
+ }
+ #[cfg(feature = "serde")]
+ #[doc = $crate::gen_any_buffer_docs!(BUFFER, $crate, $f1)]
+ pub fn $f3(provider: &(impl $crate::BufferProvider + ?Sized), $options_arg: $options_ty) -> Result<Self, $error_ty> {
+ use $crate::AsDeserializingBufferProvider;
+ $f1(&provider.as_deserializing(), $options_arg)
+ }
+ };
+
+ (locale: skip, options: skip, result: $result_ty:path, functions: [$f1:path, $f2:ident, $f3:ident]) => {
+ #[doc = $crate::gen_any_buffer_docs!(ANY, $crate, $f1)]
+ pub fn $f2(provider: &(impl $crate::AnyProvider + ?Sized)) -> $result_ty {
+ use $crate::AsDowncastingAnyProvider;
+ $f1(&provider.as_downcasting())
+ }
+ #[cfg(feature = "serde")]
+ #[doc = $crate::gen_any_buffer_docs!(BUFFER, $crate, $f1)]
+ pub fn $f3(provider: &(impl $crate::BufferProvider + ?Sized)) -> $result_ty {
+ use $crate::AsDeserializingBufferProvider;
+ $f1(&provider.as_deserializing())
+ }
+ };
+
+ (locale: include, options: skip, error: $error_ty:path) => {
+ $crate::gen_any_buffer_constructors!(
+ locale: include,
+ options: skip,
+ error: $error_ty,
+ functions: [
+ Self::try_new_unstable,
+ try_new_with_any_provider,
+ try_new_with_buffer_provider
+ ]
+ );
+ };
+ (locale: include, options: skip, error: $error_ty:path, functions: [$f1:path, $f2:ident, $f3:ident]) => {
+ #[doc = $crate::gen_any_buffer_docs!(ANY, $crate, $f1)]
+ pub fn $f2(provider: &(impl $crate::AnyProvider + ?Sized), locale: &$crate::DataLocale) -> Result<Self, $error_ty> {
+ use $crate::AsDowncastingAnyProvider;
+ $f1(&provider.as_downcasting(), locale)
+ }
+ #[cfg(feature = "serde")]
+ #[doc = $crate::gen_any_buffer_docs!(BUFFER, $crate, $f1)]
+ pub fn $f3(provider: &(impl $crate::BufferProvider + ?Sized), locale: &$crate::DataLocale) -> Result<Self, $error_ty> {
+ use $crate::AsDeserializingBufferProvider;
+ $f1(&provider.as_deserializing(), locale)
+ }
+ };
+
+ (locale: include, $config_arg:ident: $config_ty:path, $options_arg:ident: $options_ty:path, error: $error_ty:path) => {
+ $crate::gen_any_buffer_constructors!(
+ locale: include,
+ $config_arg: $config_ty,
+ $options_arg: $options_ty,
+ error: $error_ty,
+ functions: [
+ Self::try_new_unstable,
+ try_new_with_any_provider,
+ try_new_with_buffer_provider
+ ]
+ );
+ };
+ (locale: include, $config_arg:ident: $config_ty:path, $options_arg:ident: $options_ty:path, error: $error_ty:path, functions: [$f1:path, $f2:ident, $f3:ident]) => {
+ #[doc = $crate::gen_any_buffer_docs!(ANY, $crate, $f1)]
+ pub fn $f2(provider: &(impl $crate::AnyProvider + ?Sized), locale: &$crate::DataLocale, $config_arg: $config_ty, $options_arg: $options_ty) -> Result<Self, $error_ty> {
+ use $crate::AsDowncastingAnyProvider;
+ $f1(&provider.as_downcasting(), locale, $config_arg, $options_arg)
+ }
+ #[cfg(feature = "serde")]
+ #[doc = $crate::gen_any_buffer_docs!(BUFFER, $crate, $f1)]
+ pub fn $f3(provider: &(impl $crate::BufferProvider + ?Sized), locale: &$crate::DataLocale, $config_arg: $config_ty, $options_arg: $options_ty) -> Result<Self, $error_ty> {
+ use $crate::AsDeserializingBufferProvider;
+ $f1(&provider.as_deserializing(), locale, $config_arg, $options_arg)
+ }
+ };
+
+ (locale: include, $options_arg:ident: $options_ty:path, error: $error_ty:path) => {
+ $crate::gen_any_buffer_constructors!(
+ locale: include,
+ $options_arg: $options_ty,
+ error: $error_ty,
+ functions: [
+ Self::try_new_unstable,
+ try_new_with_any_provider,
+ try_new_with_buffer_provider
+ ]
+ );
+ };
+ (locale: include, $options_arg:ident: $options_ty:path, error: $error_ty:path, functions: [$f1:path, $f2:ident, $f3:ident]) => {
+ #[doc = $crate::gen_any_buffer_docs!(ANY, $crate, $f1)]
+ pub fn $f2(provider: &(impl $crate::AnyProvider + ?Sized), locale: &$crate::DataLocale, $options_arg: $options_ty) -> Result<Self, $error_ty> {
+ use $crate::AsDowncastingAnyProvider;
+ $f1(&provider.as_downcasting(), locale, $options_arg)
+ }
+ #[cfg(feature = "serde")]
+ #[doc = $crate::gen_any_buffer_docs!(BUFFER, $crate, $f1)]
+ pub fn $f3(provider: &(impl $crate::BufferProvider + ?Sized), locale: &$crate::DataLocale, $options_arg: $options_ty) -> Result<Self, $error_ty> {
+ use $crate::AsDeserializingBufferProvider;
+ $f1(&provider.as_deserializing(), locale, $options_arg)
+ }
+ };
+}
diff --git a/vendor/icu_provider/src/key.rs b/vendor/icu_provider/src/key.rs
new file mode 100644
index 000000000..2f55e4d46
--- /dev/null
+++ b/vendor/icu_provider/src/key.rs
@@ -0,0 +1,660 @@
+// 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 ).
+
+use crate::error::{DataError, DataErrorKind};
+use crate::helpers;
+
+use alloc::borrow::Cow;
+use core::fmt;
+use core::fmt::Write;
+use core::ops::Deref;
+use writeable::{LengthHint, Writeable};
+use zerovec::ule::*;
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! leading_tag {
+ () => {
+ "\nicu4x_key_tag"
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! trailing_tag {
+ () => {
+ "\n"
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! tagged {
+ ($without_tags:expr) => {
+ concat!(
+ $crate::leading_tag!(),
+ $without_tags,
+ $crate::trailing_tag!()
+ )
+ };
+}
+
+/// A compact hash of a [`DataKey`]. Useful for keys in maps.
+///
+/// The hash will be stable over time within major releases.
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash, ULE)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[repr(transparent)]
+pub struct DataKeyHash([u8; 4]);
+
+impl DataKeyHash {
+ const fn compute_from_path(path: DataKeyPath) -> Self {
+ let hash = helpers::fxhash_32(
+ path.tagged.as_bytes(),
+ leading_tag!().len(),
+ trailing_tag!().len(),
+ );
+ Self(hash.to_le_bytes())
+ }
+
+ /// Gets the hash value as a byte array.
+ pub const fn to_bytes(self) -> [u8; 4] {
+ self.0
+ }
+}
+
+impl<'a> zerovec::maps::ZeroMapKV<'a> for DataKeyHash {
+ type Container = zerovec::ZeroVec<'a, DataKeyHash>;
+ type Slice = zerovec::ZeroSlice<DataKeyHash>;
+ type GetType = <DataKeyHash as AsULE>::ULE;
+ type OwnedType = DataKeyHash;
+}
+
+impl AsULE for DataKeyHash {
+ type ULE = Self;
+ #[inline]
+ fn to_unaligned(self) -> Self::ULE {
+ self
+ }
+ #[inline]
+ fn from_unaligned(unaligned: Self::ULE) -> Self {
+ unaligned
+ }
+}
+
+// Safe since the ULE type is `self`.
+unsafe impl EqULE for DataKeyHash {}
+
+/// Hint for what to prioritize during fallback when data is unavailable.
+///
+/// For example, if `"en-US"` is requested, but we have no data for that specific locale,
+/// fallback may take us to `"en"` or `"und-US"` to check for data.
+#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
+#[non_exhaustive]
+pub enum FallbackPriority {
+ /// Prioritize the language. This is the default behavior.
+ ///
+ /// For example, `"en-US"` should go to `"en"` and then `"und"`.
+ Language,
+ /// Prioritize the region.
+ ///
+ /// For example, `"en-US"` should go to `"und-US"` and then `"und"`.
+ Region,
+ /// Collation-specific fallback rules. Similar to language priority.
+ ///
+ /// For example, `"zh-Hant"` goes to `"zh"` before `"und"`.
+ Collation,
+}
+
+impl FallbackPriority {
+ /// Const-friendly version of [`Default::default`].
+ pub const fn const_default() -> Self {
+ Self::Language
+ }
+}
+
+impl Default for FallbackPriority {
+ fn default() -> Self {
+ Self::const_default()
+ }
+}
+
+/// What additional data to load when performing fallback.
+#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
+#[non_exhaustive]
+pub enum FallbackSupplement {
+ /// Collation supplement; see `CollationFallbackSupplementV1Marker`
+ Collation,
+}
+
+/// The string path of a data key. For example, "foo@1"
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct DataKeyPath {
+ // This string literal is wrapped in leading_tag!() and trailing_tag!() to make it detectable
+ // in a compiled binary.
+ tagged: &'static str,
+}
+
+impl DataKeyPath {
+ /// Gets the path as a static string slice.
+ #[inline]
+ pub const fn get(self) -> &'static str {
+ /// core::slice::from_raw_parts(a, b) = core::mem::transmute((a, b)) hack
+ /// ```compile_fail
+ /// const unsafe fn canary() { core::slice::from_raw_parts(0 as *const u8, 0); }
+ /// ```
+ const _: () = ();
+ unsafe {
+ // Safe due to invariant that self.path is tagged correctly
+ core::str::from_utf8_unchecked(core::mem::transmute((
+ self.tagged.as_ptr().add(leading_tag!().len()),
+ self.tagged.len() - trailing_tag!().len() - leading_tag!().len(),
+ )))
+ }
+ }
+}
+
+impl Deref for DataKeyPath {
+ type Target = str;
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ self.get()
+ }
+}
+
+/// Metadata statically associated with a particular [`DataKey`].
+#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
+#[non_exhaustive]
+pub struct DataKeyMetadata {
+ /// What to prioritize when fallbacking on this [`DataKey`].
+ pub fallback_priority: FallbackPriority,
+ /// A Unicode extension keyword to consider when loading data for this [`DataKey`].
+ pub extension_key: Option<icu_locid::extensions::unicode::Key>,
+ /// Optional choice for additional fallbacking data required for loading this marker.
+ ///
+ /// For more information, see `LocaleFallbackConfig::fallback_supplement`.
+ pub fallback_supplement: Option<FallbackSupplement>,
+}
+
+impl DataKeyMetadata {
+ /// Const-friendly version of [`Default::default`].
+ pub const fn const_default() -> Self {
+ Self {
+ fallback_priority: FallbackPriority::const_default(),
+ extension_key: None,
+ fallback_supplement: None,
+ }
+ }
+
+ #[doc(hidden)]
+ pub const fn construct_internal(
+ fallback_priority: FallbackPriority,
+ extension_key: Option<icu_locid::extensions::unicode::Key>,
+ fallback_supplement: Option<FallbackSupplement>,
+ ) -> Self {
+ Self {
+ fallback_priority,
+ extension_key,
+ fallback_supplement,
+ }
+ }
+}
+
+impl Default for DataKeyMetadata {
+ #[inline]
+ fn default() -> Self {
+ Self::const_default()
+ }
+}
+
+/// Used for loading data from an ICU4X data provider.
+///
+/// A resource key is tightly coupled with the code that uses it to load data at runtime.
+/// Executables can be searched for `DataKey` instances to produce optimized data files.
+/// Therefore, users should not generally create DataKey instances; they should instead use
+/// the ones exported by a component.
+///
+/// `DataKey`s are created with the [`data_key!`] macro:
+///
+/// ```
+/// # use icu_provider::prelude::DataKey;
+/// const K: DataKey = icu_provider::data_key!("foo/bar@1");
+/// ```
+///
+/// The human-readable path string ends with `@` followed by one or more digits (the version
+/// number). Paths do not contain characters other than ASCII letters and digits, `_`, `/`.
+///
+/// Invalid paths are compile-time errors (as [`data_key!`] uses `const`).
+///
+/// ```compile_fail,E0080
+/// # use icu_provider::prelude::DataKey;
+/// const K: DataKey = icu_provider::data_key!("foo/../bar@1");
+/// ```
+#[derive(Copy, Clone)]
+pub struct DataKey {
+ path: DataKeyPath,
+ hash: DataKeyHash,
+ metadata: DataKeyMetadata,
+}
+
+impl PartialEq for DataKey {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.hash == other.hash && self.path == other.path && self.metadata == other.metadata
+ }
+}
+
+impl Eq for DataKey {}
+
+impl Ord for DataKey {
+ fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+ self.path
+ .cmp(&other.path)
+ .then_with(|| self.metadata.cmp(&other.metadata))
+ }
+}
+
+impl PartialOrd for DataKey {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl core::hash::Hash for DataKey {
+ #[inline]
+ fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+ self.hash.hash(state)
+ }
+}
+
+impl DataKey {
+ /// Gets a human-readable representation of a [`DataKey`].
+ ///
+ /// The human-readable path string ends with `@` followed by one or more digits (the version
+ /// number). Paths do not contain characters other than ASCII letters and digits, `_`, `/`.
+ ///
+ /// Useful for reading and writing data to a file system.
+ #[inline]
+ pub const fn path(self) -> DataKeyPath {
+ self.path
+ }
+
+ /// Gets a platform-independent hash of a [`DataKey`].
+ ///
+ /// The hash is 4 bytes and allows for fast key comparison.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use icu_provider::DataKey;
+ /// use icu_provider::DataKeyHash;
+ ///
+ /// const KEY: DataKey = icu_provider::data_key!("foo@1");
+ /// const KEY_HASH: DataKeyHash = KEY.hashed();
+ ///
+ /// assert_eq!(KEY_HASH.to_bytes(), [0xe2, 0xb6, 0x17, 0x71]);
+ /// ```
+ #[inline]
+ pub const fn hashed(self) -> DataKeyHash {
+ self.hash
+ }
+
+ /// Gets the metadata associated with this [`DataKey`].
+ #[inline]
+ pub const fn metadata(self) -> DataKeyMetadata {
+ self.metadata
+ }
+
+ /// Constructs a [`DataKey`] from a path and metadata.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_provider::data_key;
+ /// use icu_provider::DataKey;
+ ///
+ /// const CONST_KEY: DataKey = data_key!("foo@1");
+ ///
+ /// let runtime_key =
+ /// DataKey::from_path_and_metadata(CONST_KEY.path(), CONST_KEY.metadata());
+ ///
+ /// assert_eq!(CONST_KEY, runtime_key);
+ /// ```
+ #[inline]
+ pub const fn from_path_and_metadata(path: DataKeyPath, metadata: DataKeyMetadata) -> Self {
+ Self {
+ path,
+ hash: DataKeyHash::compute_from_path(path),
+ metadata,
+ }
+ }
+
+ #[doc(hidden)]
+ // Error is a str of the expected character class and the index where it wasn't encountered
+ // The indexing operations in this function have been reviewed in detail and won't panic.
+ #[allow(clippy::indexing_slicing)]
+ pub const fn construct_internal(
+ path: &'static str,
+ metadata: DataKeyMetadata,
+ ) -> Result<Self, (&'static str, usize)> {
+ if path.len() < leading_tag!().len() + trailing_tag!().len() {
+ return Err(("tag", 0));
+ }
+ // Start and end of the untagged part
+ let start = leading_tag!().len();
+ let end = path.len() - trailing_tag!().len();
+
+ // Check tags
+ let mut i = 0;
+ while i < leading_tag!().len() {
+ if path.as_bytes()[i] != leading_tag!().as_bytes()[i] {
+ return Err(("tag", 0));
+ }
+ i += 1;
+ }
+ i = 0;
+ while i < trailing_tag!().len() {
+ if path.as_bytes()[end + i] != trailing_tag!().as_bytes()[i] {
+ return Err(("tag", end + 1));
+ }
+ i += 1;
+ }
+
+ match Self::validate_path_manual_slice(path, start, end) {
+ Ok(()) => (),
+ Err(e) => return Err(e),
+ };
+
+ let path = DataKeyPath { tagged: path };
+
+ Ok(Self {
+ path,
+ hash: DataKeyHash::compute_from_path(path),
+ metadata,
+ })
+ }
+
+ const fn validate_path_manual_slice(
+ path: &'static str,
+ start: usize,
+ end: usize,
+ ) -> Result<(), (&'static str, usize)> {
+ debug_assert!(start <= end);
+ debug_assert!(end <= path.len());
+ // Regex: [a-zA-Z0-9_][a-zA-Z0-9_/]*@[0-9]+
+ enum State {
+ Empty,
+ Body,
+ At,
+ Version,
+ }
+ use State::*;
+ let mut i = start;
+ let mut state = Empty;
+ loop {
+ let byte = if i < end {
+ #[allow(clippy::indexing_slicing)] // protected by debug assertion
+ Some(path.as_bytes()[i])
+ } else {
+ None
+ };
+ state = match (state, byte) {
+ (Empty | Body, Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')) => Body,
+ (Body, Some(b'/')) => Body,
+ (Body, Some(b'@')) => At,
+ (At | Version, Some(b'0'..=b'9')) => Version,
+ // One of these cases will be hit at the latest when i == end, so the loop converges.
+ (Version, None) => {
+ return Ok(());
+ }
+
+ (Empty, _) => return Err(("[a-zA-Z0-9_]", i)),
+ (Body, _) => return Err(("[a-zA-z0-9_/@]", i)),
+ (At, _) => return Err(("[0-9]", i)),
+ (Version, _) => return Err(("[0-9]", i)),
+ };
+ i += 1;
+ }
+ }
+
+ /// Returns [`Ok`] if this data key matches the argument, or the appropriate error.
+ ///
+ /// Convenience method for data providers that support a single [`DataKey`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_provider::prelude::*;
+ ///
+ /// const FOO_BAR: DataKey = icu_provider::data_key!("foo/bar@1");
+ /// const FOO_BAZ: DataKey = icu_provider::data_key!("foo/baz@1");
+ /// const BAR_BAZ: DataKey = icu_provider::data_key!("bar/baz@1");
+ ///
+ /// assert!(matches!(FOO_BAR.match_key(FOO_BAR), Ok(())));
+ /// assert!(matches!(
+ /// FOO_BAR.match_key(FOO_BAZ),
+ /// Err(DataError {
+ /// kind: DataErrorKind::MissingDataKey,
+ /// ..
+ /// })
+ /// ));
+ /// assert!(matches!(
+ /// FOO_BAR.match_key(BAR_BAZ),
+ /// Err(DataError {
+ /// kind: DataErrorKind::MissingDataKey,
+ /// ..
+ /// })
+ /// ));
+ ///
+ /// // The error context contains the argument:
+ /// assert_eq!(FOO_BAR.match_key(BAR_BAZ).unwrap_err().key, Some(BAR_BAZ));
+ /// ```
+ pub fn match_key(self, key: Self) -> Result<(), DataError> {
+ if self == key {
+ Ok(())
+ } else {
+ Err(DataErrorKind::MissingDataKey.with_key(key))
+ }
+ }
+}
+
+/// See [`DataKey`].
+#[macro_export]
+macro_rules! data_key {
+ ($path:expr) => {{
+ $crate::data_key!($path, $crate::DataKeyMetadata::const_default())
+ }};
+ ($path:expr, $metadata:expr) => {{
+ // Force the DataKey into a const context
+ const RESOURCE_KEY_MACRO_CONST: $crate::DataKey = {
+ match $crate::DataKey::construct_internal($crate::tagged!($path), $metadata) {
+ Ok(v) => v,
+ #[allow(clippy::panic)] // Const context
+ Err(_) => panic!(concat!("Invalid resource key: ", $path)),
+ // TODO Once formatting is const:
+ // Err((expected, index)) => panic!(
+ // "Invalid resource key {:?}: expected {:?}, found {:?} ",
+ // $path,
+ // expected,
+ // $crate::tagged!($path).get(index..))
+ // );
+ }
+ };
+ RESOURCE_KEY_MACRO_CONST
+ }};
+}
+
+impl fmt::Debug for DataKey {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str("DataKey{")?;
+ fmt::Display::fmt(self, f)?;
+ f.write_char('}')?;
+ Ok(())
+ }
+}
+
+impl Writeable for DataKey {
+ fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
+ self.path().write_to(sink)
+ }
+
+ fn writeable_length_hint(&self) -> LengthHint {
+ self.path().writeable_length_hint()
+ }
+
+ fn write_to_string(&self) -> Cow<str> {
+ Cow::Borrowed(self.path().get())
+ }
+}
+
+writeable::impl_display_with_writeable!(DataKey);
+
+#[test]
+fn test_path_syntax() {
+ // Valid keys:
+ DataKey::construct_internal(tagged!("hello/world@1"), Default::default()).unwrap();
+ DataKey::construct_internal(tagged!("hello/world/foo@1"), Default::default()).unwrap();
+ DataKey::construct_internal(tagged!("hello/world@999"), Default::default()).unwrap();
+ DataKey::construct_internal(tagged!("hello_world/foo@1"), Default::default()).unwrap();
+ DataKey::construct_internal(tagged!("hello_458/world@1"), Default::default()).unwrap();
+ DataKey::construct_internal(tagged!("hello_world@1"), Default::default()).unwrap();
+
+ // No version:
+ assert_eq!(
+ DataKey::construct_internal(tagged!("hello/world"), Default::default()),
+ Err((
+ "[a-zA-z0-9_/@]",
+ concat!(leading_tag!(), "hello/world").len()
+ ))
+ );
+
+ assert_eq!(
+ DataKey::construct_internal(tagged!("hello/world@"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "hello/world@").len()))
+ );
+ assert_eq!(
+ DataKey::construct_internal(tagged!("hello/world@foo"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "hello/world@").len()))
+ );
+ assert_eq!(
+ DataKey::construct_internal(tagged!("hello/world@1foo"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "hello/world@1").len()))
+ );
+
+ // Meta no longer accepted:
+ assert_eq!(
+ DataKey::construct_internal(tagged!("foo@1[R]"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "foo@1").len()))
+ );
+ assert_eq!(
+ DataKey::construct_internal(tagged!("foo@1[u-ca]"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "foo@1").len()))
+ );
+ assert_eq!(
+ DataKey::construct_internal(tagged!("foo@1[R][u-ca]"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "foo@1").len()))
+ );
+
+ // Invalid meta:
+ assert_eq!(
+ DataKey::construct_internal(tagged!("foo@1[U]"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "foo@1").len()))
+ );
+ assert_eq!(
+ DataKey::construct_internal(tagged!("foo@1[uca]"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "foo@1").len()))
+ );
+ assert_eq!(
+ DataKey::construct_internal(tagged!("foo@1[u-"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "foo@1").len()))
+ );
+ assert_eq!(
+ DataKey::construct_internal(tagged!("foo@1[u-caa]"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "foo@1").len()))
+ );
+ assert_eq!(
+ DataKey::construct_internal(tagged!("foo@1[R"), Default::default()),
+ Err(("[0-9]", concat!(leading_tag!(), "foo@1").len()))
+ );
+
+ // Invalid characters:
+ assert_eq!(
+ DataKey::construct_internal(tagged!("你好/世界@1"), Default::default()),
+ Err(("[a-zA-Z0-9_]", leading_tag!().len()))
+ );
+
+ // Invalid tag:
+ assert_eq!(
+ DataKey::construct_internal(
+ concat!("hello/world@1", trailing_tag!()),
+ Default::default()
+ ),
+ Err(("tag", 0))
+ );
+ assert_eq!(
+ DataKey::construct_internal(concat!(leading_tag!(), "hello/world@1"), Default::default()),
+ Err(("tag", concat!(leading_tag!(), "hello/world@1").len()))
+ );
+ assert_eq!(
+ DataKey::construct_internal("hello/world@1", Default::default()),
+ Err(("tag", 0))
+ );
+}
+
+#[test]
+fn test_key_to_string() {
+ struct KeyTestCase {
+ pub key: DataKey,
+ pub expected: &'static str,
+ }
+
+ for cas in [
+ KeyTestCase {
+ key: data_key!("core/cardinal@1"),
+ expected: "core/cardinal@1",
+ },
+ KeyTestCase {
+ key: data_key!("core/maxlengthsubcatg@1"),
+ expected: "core/maxlengthsubcatg@1",
+ },
+ KeyTestCase {
+ key: data_key!("core/cardinal@65535"),
+ expected: "core/cardinal@65535",
+ },
+ ] {
+ assert_eq!(cas.expected, cas.key.to_string());
+ writeable::assert_writeable_eq!(&cas.key, cas.expected);
+ }
+}
+
+#[test]
+fn test_key_hash() {
+ struct KeyTestCase {
+ pub key: DataKey,
+ pub hash: DataKeyHash,
+ pub path: &'static str,
+ }
+
+ for cas in [
+ KeyTestCase {
+ key: data_key!("core/cardinal@1"),
+ hash: DataKeyHash([172, 207, 42, 236]),
+ path: "core/cardinal@1",
+ },
+ KeyTestCase {
+ key: data_key!("core/maxlengthsubcatg@1"),
+ hash: DataKeyHash([193, 6, 79, 61]),
+ path: "core/maxlengthsubcatg@1",
+ },
+ KeyTestCase {
+ key: data_key!("core/cardinal@65535"),
+ hash: DataKeyHash([176, 131, 182, 223]),
+ path: "core/cardinal@65535",
+ },
+ ] {
+ assert_eq!(cas.hash, cas.key.hashed(), "{}", cas.path);
+ assert_eq!(cas.path, &*cas.key.path(), "{}", cas.path);
+ }
+}
diff --git a/vendor/icu_provider/src/lib.rs b/vendor/icu_provider/src/lib.rs
new file mode 100644
index 000000000..594e872f4
--- /dev/null
+++ b/vendor/icu_provider/src/lib.rs
@@ -0,0 +1,214 @@
+// 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 ).
+
+//! `icu_provider` is one of the [`ICU4X`] components.
+//!
+//! Unicode's experience with ICU4X's parent projects, ICU4C and ICU4J, led the team to realize
+//! that data management is the most critical aspect of deploying internationalization, and that it requires
+//! a high level of customization for the needs of the platform it is embedded in. As a result
+//! ICU4X comes with a selection of providers that should allow for ICU4X to naturally fit into
+//! different business and technological needs of customers.
+//!
+//! `icu_provider` defines traits and structs for transmitting data through the ICU4X locale
+//! data pipeline. The primary trait is [`DataProvider`]. It is parameterized by a
+//! [`KeyedDataMarker`], which contains the data type and a [`DataKey`]. It has one method,
+//! [`DataProvider::load`], which transforms a [`DataRequest`]
+//! into a [`DataResponse`].
+//!
+//! - [`DataKey`] is a fixed identifier for the data type, such as `"plurals/cardinal@1"`.
+//! - [`DataRequest`] contains additional annotations to choose a specific variant of the key,
+//! such as a locale.
+//! - [`DataResponse`] contains the data if the request was successful.
+//!
+//! In addition, there are three other traits which are widely implemented:
+//!
+//! - [`AnyProvider`] returns data as `dyn Any` trait objects.
+//! - [`BufferProvider`] returns data as `[u8]` buffers.
+//! - [`DynamicDataProvider`] returns structured data but is not specific to a key.
+//!
+//! The most common types required for this crate are included via the prelude:
+//!
+//! ```
+//! use icu_provider::prelude::*;
+//! ```
+//!
+//! ## Types of Data Providers
+//!
+//! All nontrivial data providers can fit into one of two classes.
+//!
+//! 1. [`AnyProvider`]: Those whose data originates as structured Rust objects
+//! 2. [`BufferProvider`]: Those whose data originates as unstructured `[u8]` buffers
+//!
+//! **✨ Key Insight:** A given data provider is generally *either* an [`AnyProvider`] *or* a
+//! [`BufferProvider`]. Which type depends on the data source, and it is not generally possible
+//! to convert one to the other.
+//!
+//! See also [crate::constructors].
+//!
+//! ### AnyProvider
+//!
+//! These providers are able to return structured data cast into `dyn Any` trait objects. Users
+//! can call [`as_downcasting()`] to get an object implementing [`DataProvider`] by downcasting
+//! the trait objects.
+//!
+//! Examples of AnyProviders:
+//!
+//! - [`CldrJsonDataProvider`] reads structured data from CLDR JSON source files and returns
+//! structured Rust objects.
+//! - [`AnyPayloadProvider`] wraps a specific data struct and returns it.
+//! - The `BakedDataProvider` which encodes structured data directly in Rust source
+//!
+//! ### BufferProvider
+//!
+//! These providers are able to return unstructured data typically represented as
+//! [`serde`]-serialized buffers. Users can call [`as_deserializing()`] to get an object
+//! implementing [`DataProvider`] by invoking Serde Deserialize.
+//!
+//! Examples of BufferProviders:
+//!
+//! - [`FsDataProvider`] reads individual buffers from the filesystem.
+//! - [`BlobDataProvider`] reads buffers from a large in-memory blob.
+//!
+//! ## Provider Adapters
+//!
+//! ICU4X offers several built-in modules to combine providers in interesting ways.
+//! These can be found in the [`icu_provider_adapters`] crate.
+//!
+//! ## Testing Provider
+//!
+//! This crate also contains a concrete provider for testing purposes:
+//!
+//! - [`HelloWorldProvider`] returns "hello world" strings in several languages.
+//!
+//! If you need a testing provider that contains the actual resource keys used by ICU4X features,
+//! see the [`icu_testdata`] crate.
+//!
+//! ## Types and Lifetimes
+//!
+//! Types compatible with [`Yokeable`] can be passed through the data provider, so long as they are
+//! associated with a marker type implementing [`DataMarker`].
+//!
+//! Data structs should generally have one lifetime argument: `'data`. This lifetime allows data
+//! structs to borrow zero-copy data.
+//!
+//! ## Data generation API
+//!
+//! *This functionality is enabled with the "datagen" feature*
+//!
+//! The [`datagen`] module contains several APIs for data generation. See [`icu_datagen`] for the reference
+//! data generation implementation.
+//!
+//! [`ICU4X`]: ../icu/index.html
+//! [`DataProvider`]: data_provider::DataProvider
+//! [`DataKey`]: key::DataKey
+//! [`DataLocale`]: request::DataLocale
+//! [`IterableDynamicDataProvider`]: datagen::IterableDynamicDataProvider
+//! [`IterableDataProvider`]: datagen::IterableDataProvider
+//! [`AnyPayloadProvider`]: ../icu_provider_adapters/any_payload/struct.AnyPayloadProvider.html
+//! [`HelloWorldProvider`]: hello_world::HelloWorldProvider
+//! [`AnyProvider`]: any::AnyProvider
+//! [`Yokeable`]: yoke::Yokeable
+//! [`impl_dynamic_data_provider!`]: impl_dynamic_data_provider
+//! [`icu_provider_adapters`]: ../icu_provider_adapters/index.html
+//! [`as_downcasting()`]: AsDowncastingAnyProvider::as_downcasting
+//! [`as_deserializing()`]: AsDeserializingBufferProvider::as_deserializing
+//! [`CldrJsonDataProvider`]: ../icu_datagen/cldr/struct.CldrJsonDataProvider.html
+//! [`FsDataProvider`]: ../icu_provider_fs/struct.FsDataProvider.html
+//! [`BlobDataProvider`]: ../icu_provider_blob/struct.BlobDataProvider.html
+//! [`icu_testdata`]: ../icu_testdata/index.html
+//! [`icu_datagen`]: ../icu_datagen/index.html
+
+// https://github.com/unicode-org/icu4x/blob/main/docs/process/boilerplate.md#library-annotations
+#![cfg_attr(not(any(test, feature = "std")), no_std)]
+#![cfg_attr(
+ not(test),
+ deny(
+ clippy::indexing_slicing,
+ clippy::unwrap_used,
+ clippy::expect_used,
+ clippy::panic,
+ clippy::exhaustive_structs,
+ clippy::exhaustive_enums,
+ // TODO(#2266): enable missing_debug_implementations,
+ )
+)]
+#![warn(missing_docs)]
+
+extern crate alloc;
+
+pub mod any;
+pub mod buf;
+pub mod constructors;
+mod data_provider;
+#[cfg(feature = "datagen")]
+#[macro_use]
+pub mod datagen;
+#[macro_use]
+pub mod dynutil;
+mod error;
+pub mod hello_world;
+mod helpers;
+#[macro_use]
+mod key;
+pub mod marker;
+mod request;
+mod response;
+#[cfg(feature = "serde")]
+pub mod serde;
+
+#[cfg(feature = "macros")]
+pub use icu_provider_macros::data_struct;
+
+pub mod prelude {
+ //! Core selection of APIs and structures for the ICU4X data provider.
+ pub use crate::any::AnyMarker;
+ pub use crate::any::AnyPayload;
+ pub use crate::any::AnyProvider;
+ pub use crate::any::AnyResponse;
+ pub use crate::buf::BufferMarker;
+ pub use crate::buf::BufferProvider;
+ pub use crate::data_key;
+ pub use crate::data_provider::DataProvider;
+ pub use crate::data_provider::DynamicDataProvider;
+ pub use crate::error::DataError;
+ pub use crate::error::DataErrorKind;
+ pub use crate::key::DataKey;
+ pub use crate::key::DataKeyHash;
+ pub use crate::marker::DataMarker;
+ pub use crate::marker::KeyedDataMarker;
+ pub use crate::request::DataLocale;
+ pub use crate::request::DataRequest;
+ pub use crate::response::DataPayload;
+ pub use crate::response::DataResponse;
+ pub use crate::response::DataResponseMetadata;
+
+ pub use crate::any::AsDowncastingAnyProvider;
+ pub use crate::any::AsDynamicDataProviderAnyMarkerWrap;
+ #[cfg(feature = "serde")]
+ pub use crate::serde::AsDeserializingBufferProvider;
+
+ /// Re-export of the yoke and zerofrom crates for convenience of downstream implementors.
+ #[doc(hidden)]
+ pub use yoke;
+ #[doc(hidden)]
+ pub use zerofrom;
+}
+
+// Also include the same symbols at the top level for selective inclusion
+pub use prelude::*;
+
+// Less important non-prelude items
+pub use crate::any::MaybeSendSync;
+pub use crate::key::DataKeyMetadata;
+pub use crate::key::DataKeyPath;
+pub use crate::key::FallbackPriority;
+pub use crate::key::FallbackSupplement;
+pub use crate::request::DataRequestMetadata;
+pub use crate::response::Cart;
+
+// For macros
+#[doc(hidden)]
+pub mod _internal {
+ pub use icu_locid::extensions_unicode_key;
+}
diff --git a/vendor/icu_provider/src/marker.rs b/vendor/icu_provider/src/marker.rs
new file mode 100644
index 000000000..870885797
--- /dev/null
+++ b/vendor/icu_provider/src/marker.rs
@@ -0,0 +1,80 @@
+// 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 ).
+
+//! Marker types and traits for DataProvider.
+
+use crate::key::DataKey;
+use crate::yoke::Yokeable;
+
+/// Trait marker for data structs. All types delivered by the data provider must be associated with
+/// something implementing this trait.
+///
+/// Structs implementing this trait are normally generated with the [`data_struct`] macro.
+///
+/// By convention, the non-standard `Marker` suffix is used by types implementing DataMarker.
+///
+/// In addition to a marker type implementing DataMarker, the following impls must also be present
+/// for the data struct:
+///
+/// - `impl<'a> Yokeable<'a>` (required)
+/// - `impl ZeroFrom<Self>`
+///
+/// Also see [`KeyedDataMarker`].
+///
+/// # Examples
+///
+/// Manually implementing DataMarker for a custom type:
+///
+/// ```
+/// use icu_provider::prelude::*;
+/// use icu_provider::yoke::*;
+/// use icu_provider::zerofrom::*;
+/// use std::borrow::Cow;
+/// use std::rc::Rc;
+///
+/// #[derive(Yokeable, ZeroFrom)]
+/// struct MyDataStruct<'data> {
+/// message: Cow<'data, str>,
+/// }
+///
+/// struct MyDataStructMarker;
+///
+/// impl DataMarker for MyDataStructMarker {
+/// type Yokeable = MyDataStruct<'static>;
+/// }
+///
+/// // We can now use MyDataStruct with DataProvider:
+/// let s = MyDataStruct {
+/// message: Cow::Owned("Hello World".into()),
+/// };
+/// let payload = DataPayload::<MyDataStructMarker>::from_owned(s);
+/// assert_eq!(payload.get().message, "Hello World");
+/// ```
+///
+/// [`data_struct`]: crate::data_struct
+pub trait DataMarker {
+ /// A type that implements [`Yokeable`]. This should typically be the `'static` version of a
+ /// data struct.
+ type Yokeable: for<'a> Yokeable<'a>;
+}
+
+/// A [`DataMarker`] with a [`DataKey`] attached.
+///
+/// Structs implementing this trait are normally generated with the [`data_struct!`] macro.
+///
+/// Implementing this trait enables this marker to be used with the main [`DataProvider`] trait.
+/// Most markers should be associated with a specific key and should therefore implement this
+/// trait.
+///
+/// [`BufferMarker`] and [`AnyMarker`] are examples of markers that do _not_ implement this trait
+/// because they are not specific to a single key.
+///
+/// [`data_struct!`]: crate::data_struct
+/// [`DataProvider`]: crate::DataProvider
+/// [`BufferMarker`]: crate::BufferMarker
+/// [`AnyMarker`]: crate::AnyMarker
+pub trait KeyedDataMarker: DataMarker {
+ /// The single [`DataKey`] associated with this marker.
+ const KEY: DataKey;
+}
diff --git a/vendor/icu_provider/src/request.rs b/vendor/icu_provider/src/request.rs
new file mode 100644
index 000000000..7f6bb5911
--- /dev/null
+++ b/vendor/icu_provider/src/request.rs
@@ -0,0 +1,513 @@
+// 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 ).
+
+use core::cmp::Ordering;
+use core::default::Default;
+use core::fmt;
+use core::fmt::Debug;
+use icu_locid::extensions::unicode as unicode_ext;
+use icu_locid::subtags::{Language, Region, Script, Variants};
+use icu_locid::{LanguageIdentifier, Locale, SubtagOrderingResult};
+use writeable::{LengthHint, Writeable};
+
+#[cfg(doc)]
+use icu_locid::subtags::Variant;
+
+/// The request type passed into all data provider implementations.
+#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
+#[allow(clippy::exhaustive_structs)] // this type is stable
+pub struct DataRequest<'a> {
+ /// The locale for which to load data.
+ ///
+ /// If locale fallback is enabled, the resulting data may be from a different locale
+ /// than the one requested here.
+ pub locale: &'a DataLocale,
+ /// Metadata that may affect the behavior of the data provider.
+ pub metadata: DataRequestMetadata,
+}
+
+impl fmt::Display for DataRequest<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.locale, f)
+ }
+}
+
+/// Metadata for data requests. This is currently empty, but it may be extended with options
+/// for tuning locale fallback, buffer layout, and so forth.
+#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[non_exhaustive]
+pub struct DataRequestMetadata;
+
+/// The main locale type used by the ICU4X data provider.
+///
+/// [`DataLocale`] contains less functionality than [`Locale`] but more than
+/// [`LanguageIdentifier`] for better size and performance while still meeting
+/// the needs of the ICU4X data pipeline.
+///
+/// # Examples
+///
+/// Convert a [`Locale`] to a [`DataLocale`] and back:
+///
+/// ```
+/// use icu_locid::locale;
+/// use icu_provider::DataLocale;
+///
+/// let locale1 = locale!("en-u-ca-buddhist");
+/// let data_locale = DataLocale::from(locale1);
+/// let locale2 = data_locale.into_locale();
+///
+/// assert_eq!(locale2.to_string(), "en-u-ca-buddhist");
+/// ```
+///
+/// You can alternatively create a [`DataLocale`] from a borrowed [`Locale`], which is more
+/// efficient than cloning the [`Locale`], but less efficient than converting an owned
+/// [`Locale`]:
+///
+/// ```
+/// use icu_locid::locale;
+/// use icu_provider::DataLocale;
+///
+/// let locale1 = locale!("en-u-ca-buddhist");
+/// let data_locale = DataLocale::from(&locale1);
+/// let locale2 = data_locale.into_locale();
+///
+/// assert_eq!(locale1, locale2);
+/// ```
+///
+/// If you are sure that you have no Unicode keywords, start with [`LanguageIdentifier`]:
+///
+/// ```
+/// use icu_locid::langid;
+/// use icu_provider::DataLocale;
+///
+/// let langid1 = langid!("es-CA-valencia");
+/// let data_locale = DataLocale::from(langid1);
+/// let langid2 = data_locale.get_langid();
+///
+/// assert_eq!(langid2.to_string(), "es-CA-valencia");
+/// ```
+///
+/// [`DataLocale`] only supports `-u` keywords, to reflect the current state of CLDR data
+/// lookup and fallback. This may change in the future.
+///
+/// ```
+/// use icu_locid::Locale;
+/// use icu_provider::DataLocale;
+///
+/// let locale = "hi-t-en-h0-hybrid-u-attr-ca-buddhist"
+/// .parse::<Locale>()
+/// .unwrap();
+/// let data_locale = DataLocale::from(locale);
+///
+/// assert_eq!(data_locale.to_string(), "hi-u-ca-buddhist");
+/// ```
+#[derive(PartialEq, Clone, Default, Eq, Hash)]
+pub struct DataLocale {
+ langid: LanguageIdentifier,
+ keywords: unicode_ext::Keywords,
+}
+
+impl<'a> Default for &'a DataLocale {
+ fn default() -> Self {
+ static DEFAULT: DataLocale = DataLocale {
+ langid: LanguageIdentifier::UND,
+ keywords: unicode_ext::Keywords::new(),
+ };
+ &DEFAULT
+ }
+}
+
+impl fmt::Debug for DataLocale {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "DataLocale{{{}}}", self)
+ }
+}
+
+impl Writeable for DataLocale {
+ fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
+ self.langid.write_to(sink)?;
+ if !self.keywords.is_empty() {
+ sink.write_str("-u-")?;
+ self.keywords.write_to(sink)?;
+ }
+ Ok(())
+ }
+
+ fn writeable_length_hint(&self) -> LengthHint {
+ self.langid.writeable_length_hint()
+ + if !self.keywords.is_empty() {
+ self.keywords.writeable_length_hint() + 3
+ } else {
+ LengthHint::exact(0)
+ }
+ }
+
+ fn write_to_string(&self) -> alloc::borrow::Cow<str> {
+ if self.keywords.is_empty() {
+ return self.langid.write_to_string();
+ }
+ let mut string =
+ alloc::string::String::with_capacity(self.writeable_length_hint().capacity());
+ let _ = self.write_to(&mut string);
+ alloc::borrow::Cow::Owned(string)
+ }
+}
+
+writeable::impl_display_with_writeable!(DataLocale);
+
+impl From<LanguageIdentifier> for DataLocale {
+ fn from(langid: LanguageIdentifier) -> Self {
+ Self {
+ langid,
+ keywords: unicode_ext::Keywords::new(),
+ }
+ }
+}
+
+impl From<Locale> for DataLocale {
+ fn from(locale: Locale) -> Self {
+ Self {
+ langid: locale.id,
+ keywords: locale.extensions.unicode.keywords,
+ }
+ }
+}
+
+impl From<&LanguageIdentifier> for DataLocale {
+ fn from(langid: &LanguageIdentifier) -> Self {
+ Self {
+ langid: langid.clone(),
+ keywords: unicode_ext::Keywords::new(),
+ }
+ }
+}
+
+impl From<&Locale> for DataLocale {
+ fn from(locale: &Locale) -> Self {
+ Self {
+ langid: locale.id.clone(),
+ keywords: locale.extensions.unicode.keywords.clone(),
+ }
+ }
+}
+
+impl DataLocale {
+ /// Compare this [`DataLocale`] with BCP-47 bytes.
+ ///
+ /// The return value is equivalent to what would happen if you first converted this
+ /// [`DataLocale`] to a BCP-47 string and then performed a byte comparison.
+ ///
+ /// This function is case-sensitive and results in a *total order*, so it is appropriate for
+ /// binary search. The only argument producing [`Ordering::Equal`] is `self.to_string()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_locid::Locale;
+ /// use icu_provider::DataLocale;
+ /// use std::cmp::Ordering;
+ ///
+ /// let bcp47_strings: &[&str] = &[
+ /// "ca-ES",
+ /// "ca-ES-u-ca-buddhist",
+ /// "ca-ES-valencia",
+ /// "pl-Latn-PL",
+ /// "und",
+ /// "und-fonipa",
+ /// "und-u-ca-hebrew",
+ /// "und-u-ca-japanese",
+ /// "zh",
+ /// ];
+ ///
+ /// for ab in bcp47_strings.windows(2) {
+ /// let a = ab[0];
+ /// let b = ab[1];
+ /// assert!(a.cmp(b) == Ordering::Less);
+ /// let a_loc: DataLocale = a.parse::<Locale>().unwrap().into();
+ /// assert_eq!(a, a_loc.to_string());
+ /// assert!(
+ /// a_loc.strict_cmp(a.as_bytes()) == Ordering::Equal,
+ /// "{} == {}",
+ /// a,
+ /// a
+ /// );
+ /// assert!(
+ /// a_loc.strict_cmp(b.as_bytes()) == Ordering::Less,
+ /// "{} < {}",
+ /// a,
+ /// b
+ /// );
+ /// let b_loc: DataLocale = b.parse::<Locale>().unwrap().into();
+ /// assert_eq!(b, b_loc.to_string());
+ /// assert!(
+ /// b_loc.strict_cmp(b.as_bytes()) == Ordering::Equal,
+ /// "{} == {}",
+ /// b,
+ /// b
+ /// );
+ /// assert!(
+ /// b_loc.strict_cmp(a.as_bytes()) == Ordering::Greater,
+ /// "{} > {}",
+ /// b,
+ /// a
+ /// );
+ /// }
+ /// ```
+ pub fn strict_cmp(&self, other: &[u8]) -> Ordering {
+ let subtags = other.split(|b| *b == b'-');
+ let mut subtag_result = self.langid.strict_cmp_iter(subtags);
+ if self.has_unicode_ext() {
+ let mut subtags = match subtag_result {
+ SubtagOrderingResult::Subtags(s) => s,
+ SubtagOrderingResult::Ordering(o) => return o,
+ };
+ match subtags.next() {
+ Some(b"u") => (),
+ Some(s) => return s.cmp(b"u").reverse(),
+ None => return Ordering::Greater,
+ }
+ subtag_result = self.keywords.strict_cmp_iter(subtags);
+ }
+ subtag_result.end()
+ }
+}
+
+impl DataLocale {
+ /// Returns whether this [`DataLocale`] has all empty fields (no components).
+ pub fn is_empty(&self) -> bool {
+ self == <&DataLocale>::default()
+ }
+
+ /// Returns whether the [`LanguageIdentifier`] associated with this request is `und`.
+ ///
+ /// Note that this only checks the language identifier; extension keywords may also be set.
+ /// To check the entire `DataLocale`, use [`DataLocale::is_empty()`].
+ pub fn is_langid_und(&self) -> bool {
+ self.langid == LanguageIdentifier::UND
+ }
+
+ /// Gets the [`LanguageIdentifier`] for this [`DataLocale`].
+ ///
+ /// This may allocate memory if there are variant subtags. If you need only the language,
+ /// script, and/or region subtag, use the specific getters for those subtags:
+ ///
+ /// - [`DataLocale::language()`]
+ /// - [`DataLocale::script()`]
+ /// - [`DataLocale::region()`]
+ ///
+ /// If you have ownership over the `DataLocale`, use [`DataLocale::into_locale()`]
+ /// and then access the `id` field.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_locid::langid;
+ /// use icu_provider::prelude::*;
+ ///
+ /// const FOO_BAR: DataKey = icu_provider::data_key!("foo/bar@1");
+ ///
+ /// let req_no_langid = DataRequest {
+ /// locale: &Default::default(),
+ /// metadata: Default::default(),
+ /// };
+ ///
+ /// let req_with_langid = DataRequest {
+ /// locale: &langid!("ar-EG").into(),
+ /// metadata: Default::default(),
+ /// };
+ ///
+ /// assert_eq!(req_no_langid.locale.get_langid(), langid!("und"));
+ /// assert_eq!(req_with_langid.locale.get_langid(), langid!("ar-EG"));
+ /// ```
+ pub fn get_langid(&self) -> LanguageIdentifier {
+ self.langid.clone()
+ }
+
+ /// Overrides the entire [`LanguageIdentifier`] portion of this [`DataLocale`].
+ #[inline]
+ pub fn set_langid(&mut self, lid: LanguageIdentifier) {
+ self.langid = lid;
+ }
+
+ /// Converts this [`DataLocale`] into a [`Locale`].
+ ///
+ /// See also [`DataLocale::get_langid()`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_locid::{
+ /// langid, subtags_language as language, subtags_region as region, Locale,
+ /// };
+ /// use icu_provider::prelude::*;
+ ///
+ /// let locale: Locale = "it-IT-u-ca-coptic".parse().expect("Valid BCP-47");
+ /// let locale: DataLocale = locale.into();
+ ///
+ /// assert_eq!(locale.to_string(), "it-IT-u-ca-coptic");
+ /// assert_eq!(locale.get_langid(), langid!("it-IT"));
+ /// assert_eq!(locale.language(), language!("it"));
+ /// assert_eq!(locale.script(), None);
+ /// assert_eq!(locale.region(), Some(region!("IT")));
+ ///
+ /// let locale = locale.into_locale();
+ /// assert_eq!(locale.to_string(), "it-IT-u-ca-coptic");
+ /// ```
+ pub fn into_locale(self) -> Locale {
+ let mut loc = Locale {
+ id: self.langid,
+ ..Default::default()
+ };
+ loc.extensions.unicode.keywords = self.keywords;
+ loc
+ }
+
+ /// Returns the [`Language`] for this [`DataLocale`].
+ #[inline]
+ pub fn language(&self) -> Language {
+ self.langid.language
+ }
+
+ /// Returns the [`Language`] for this [`DataLocale`].
+ #[inline]
+ pub fn set_language(&mut self, language: Language) {
+ self.langid.language = language;
+ }
+
+ /// Returns the [`Script`] for this [`DataLocale`].
+ #[inline]
+ pub fn script(&self) -> Option<Script> {
+ self.langid.script
+ }
+
+ /// Sets the [`Script`] for this [`DataLocale`].
+ #[inline]
+ pub fn set_script(&mut self, script: Option<Script>) {
+ self.langid.script = script;
+ }
+
+ /// Returns the [`Region`] for this [`DataLocale`].
+ #[inline]
+ pub fn region(&self) -> Option<Region> {
+ self.langid.region
+ }
+
+ /// Sets the [`Region`] for this [`DataLocale`].
+ #[inline]
+ pub fn set_region(&mut self, region: Option<Region>) {
+ self.langid.region = region;
+ }
+
+ /// Returns whether there are any [`Variant`] subtags in this [`DataLocale`].
+ #[inline]
+ pub fn has_variants(&self) -> bool {
+ !self.langid.variants.is_empty()
+ }
+
+ /// Sets all [`Variants`] on this [`DataLocale`], overwriting any that were there previously.
+ #[inline]
+ pub fn set_variants(&mut self, variants: Variants) {
+ self.langid.variants = variants;
+ }
+
+ /// Removes all [`Variant`] subtags in this [`DataLocale`].
+ #[inline]
+ pub fn clear_variants(&mut self) -> Variants {
+ self.langid.variants.clear()
+ }
+
+ /// Gets the value of the specified Unicode extension keyword for this [`DataLocale`].
+ #[inline]
+ pub fn get_unicode_ext(&self, key: &unicode_ext::Key) -> Option<unicode_ext::Value> {
+ self.keywords.get(key).cloned()
+ }
+
+ /// Returns whether there are any Unicode extension keywords in this [`DataLocale`].
+ #[inline]
+ pub fn has_unicode_ext(&self) -> bool {
+ !self.keywords.is_empty()
+ }
+
+ /// Returns whether a specific Unicode extension keyword is present in this [`DataLocale`].
+ #[inline]
+ pub fn contains_unicode_ext(&self, key: &unicode_ext::Key) -> bool {
+ self.keywords.contains_key(key)
+ }
+
+ /// Returns whether this [`DataLocale`] contains a Unicode extension keyword
+ /// with the specified key and value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_locid::{
+ /// extensions_unicode_key as key, extensions_unicode_value as value,
+ /// Locale,
+ /// };
+ /// use icu_provider::prelude::*;
+ ///
+ /// let locale: Locale = "it-IT-u-ca-coptic".parse().expect("Valid BCP-47");
+ /// let locale: DataLocale = locale.into();
+ ///
+ /// assert_eq!(locale.get_unicode_ext(&key!("hc")), None);
+ /// assert_eq!(locale.get_unicode_ext(&key!("ca")), Some(value!("coptic")));
+ /// assert!(locale.matches_unicode_ext(&key!("ca"), &value!("coptic"),));
+ /// ```
+ #[inline]
+ pub fn matches_unicode_ext(&self, key: &unicode_ext::Key, value: &unicode_ext::Value) -> bool {
+ self.keywords.get(key) == Some(value)
+ }
+
+ /// Sets the value for a specific Unicode extension keyword on this [`DataLocale`].
+ #[inline]
+ pub fn set_unicode_ext(
+ &mut self,
+ key: unicode_ext::Key,
+ value: unicode_ext::Value,
+ ) -> Option<unicode_ext::Value> {
+ self.keywords.set(key, value)
+ }
+
+ /// Removes a specific Unicode extension keyword from this [`DataLocale`], returning
+ /// the value if it was present.
+ #[inline]
+ pub fn remove_unicode_ext(&mut self, key: &unicode_ext::Key) -> Option<unicode_ext::Value> {
+ self.keywords.remove(key)
+ }
+
+ /// Retains a subset of keywords as specified by the predicate function.
+ #[inline]
+ pub fn retain_unicode_ext<F>(&mut self, predicate: F)
+ where
+ F: FnMut(&unicode_ext::Key) -> bool,
+ {
+ self.keywords.retain_by_key(predicate)
+ }
+}
+
+#[test]
+fn test_data_locale_to_string() {
+ struct TestCase {
+ pub locale: DataLocale,
+ pub expected: &'static str,
+ }
+
+ for cas in [
+ TestCase {
+ locale: Locale::UND.into(),
+ expected: "und",
+ },
+ TestCase {
+ locale: "und-u-cu-gbp".parse::<Locale>().unwrap().into(),
+ expected: "und-u-cu-gbp",
+ },
+ TestCase {
+ locale: "en-ZA-u-cu-gbp".parse::<Locale>().unwrap().into(),
+ expected: "en-ZA-u-cu-gbp",
+ },
+ ] {
+ assert_eq!(cas.expected, cas.locale.to_string());
+ writeable::assert_writeable_eq!(&cas.locale, cas.expected);
+ }
+}
diff --git a/vendor/icu_provider/src/response.rs b/vendor/icu_provider/src/response.rs
new file mode 100644
index 000000000..653d20a68
--- /dev/null
+++ b/vendor/icu_provider/src/response.rs
@@ -0,0 +1,635 @@
+// 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 ).
+
+use crate::buf::BufferMarker;
+use crate::error::{DataError, DataErrorKind};
+use crate::marker::DataMarker;
+use crate::request::DataLocale;
+use crate::yoke::trait_hack::YokeTraitHack;
+use crate::yoke::*;
+use alloc::boxed::Box;
+use core::convert::TryFrom;
+use core::fmt::Debug;
+use core::marker::PhantomData;
+use core::ops::Deref;
+
+#[cfg(not(feature = "sync"))]
+use alloc::rc::Rc as SelectedRc;
+#[cfg(feature = "sync")]
+use alloc::sync::Arc as SelectedRc;
+
+/// A response object containing metadata about the returned data.
+#[derive(Debug, Clone, PartialEq, Default)]
+#[non_exhaustive]
+pub struct DataResponseMetadata {
+ /// The resolved locale of the returned data, if locale fallbacking was performed.
+ pub locale: Option<DataLocale>,
+ /// The format of the buffer for buffer-backed data, if known (for example, JSON).
+ pub buffer_format: Option<crate::buf::BufferFormat>,
+}
+
+/// A container for data payloads returned from a data provider.
+///
+/// [`DataPayload`] is built on top of the [`yoke`] framework, which allows for cheap, zero-copy
+/// operations on data via the use of self-references.
+///
+/// The type of the data stored in [`DataPayload`] is determined by the [`DataMarker`] type parameter.
+///
+/// ## Accessing the data
+///
+/// To get a reference to the data inside [`DataPayload`], use [`DataPayload::get()`]. If you need
+/// to store the data for later use, you need to store the [`DataPayload`] itself, since `get` only
+/// returns a reference with an ephemeral lifetime.
+///
+/// ## Mutating the data
+///
+/// To modify the data stored in a [`DataPayload`], use [`DataPayload::with_mut()`].
+///
+/// ## Transforming the data to a different type
+///
+/// To transform a [`DataPayload`] to a different type backed by the same data store (cart), use
+/// [`DataPayload::map_project()`] or one of its sister methods.
+///
+/// # `sync` feature
+///
+/// By default, the payload uses non-concurrent reference counting internally, and hence is neither
+/// [`Sync`] nor [`Send`]; if these traits are required, the `sync` feature can be enabled.
+///
+/// # Examples
+///
+/// Basic usage, using the `HelloWorldV1Marker` marker:
+///
+/// ```
+/// use icu_provider::hello_world::*;
+/// use icu_provider::prelude::*;
+/// use std::borrow::Cow;
+///
+/// let payload = DataPayload::<HelloWorldV1Marker>::from_owned(HelloWorldV1 {
+/// message: Cow::Borrowed("Demo"),
+/// });
+///
+/// assert_eq!("Demo", payload.get().message);
+/// ```
+pub struct DataPayload<M>
+where
+ M: DataMarker,
+{
+ pub(crate) yoke: Yoke<M::Yokeable, Option<Cart>>,
+}
+
+/// The type of the "cart" that is used by `DataPayload`.
+#[derive(Clone)]
+#[allow(clippy::redundant_allocation)] // false positive, it's cheaper to wrap an existing Box in an Rc than to reallocate a huge Rc
+pub struct Cart(SelectedRc<Box<[u8]>>);
+
+impl Deref for Cart {
+ type Target = Box<[u8]>;
+ fn deref(&self) -> &Self::Target {
+ &*self.0
+ }
+}
+// Safe because both Rc and Arc are StableDeref, and our impl delegates.
+unsafe impl stable_deref_trait::StableDeref for Cart {}
+// Safe because both Rc and Arc are CloneableCart, and our impl delegates.
+unsafe impl yoke::CloneableCart for Cart {}
+
+impl Cart {
+ /// Creates a Yoke<Y, Option<Cart>> from owned bytes by applying f.
+ pub fn try_make_yoke<Y, F, E>(cart: Box<[u8]>, f: F) -> Result<Yoke<Y, Option<Self>>, E>
+ where
+ for<'a> Y: Yokeable<'a>,
+ F: FnOnce(&[u8]) -> Result<<Y as Yokeable>::Output, E>,
+ {
+ Yoke::try_attach_to_cart(SelectedRc::new(cart), |b| f(&*b))
+ // Safe because the cart is only wrapped
+ .map(|yoke| unsafe { yoke.replace_cart(Cart) })
+ .map(Yoke::wrap_cart_in_option)
+ }
+}
+
+impl<M> Debug for DataPayload<M>
+where
+ M: DataMarker,
+ for<'a> &'a <M::Yokeable as Yokeable<'a>>::Output: Debug,
+{
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ self.get().fmt(f)
+ }
+}
+
+/// Cloning a DataPayload is generally a cheap operation.
+/// See notes in the `Clone` impl for [`Yoke`].
+///
+/// # Examples
+///
+/// ```no_run
+/// use icu_provider::hello_world::*;
+/// use icu_provider::prelude::*;
+///
+/// let resp1: DataPayload<HelloWorldV1Marker> = todo!();
+/// let resp2 = resp1.clone();
+/// ```
+impl<M> Clone for DataPayload<M>
+where
+ M: DataMarker,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
+{
+ fn clone(&self) -> Self {
+ Self {
+ yoke: self.yoke.clone(),
+ }
+ }
+}
+
+impl<M> PartialEq for DataPayload<M>
+where
+ M: DataMarker,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: PartialEq,
+{
+ fn eq(&self, other: &Self) -> bool {
+ YokeTraitHack(self.get()).into_ref() == YokeTraitHack(other.get()).into_ref()
+ }
+}
+
+impl<M> Eq for DataPayload<M>
+where
+ M: DataMarker,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Eq,
+{
+}
+
+#[test]
+fn test_clone_eq() {
+ use crate::hello_world::*;
+ let p1 = DataPayload::<HelloWorldV1Marker>::from_static_str("Demo");
+ let p2 = p1.clone();
+ assert_eq!(p1, p2);
+}
+
+impl<M> DataPayload<M>
+where
+ M: DataMarker,
+{
+ /// Convert a fully owned (`'static`) data struct into a DataPayload.
+ ///
+ /// This constructor creates `'static` payloads.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_provider::hello_world::*;
+ /// use icu_provider::prelude::*;
+ /// use std::borrow::Cow;
+ ///
+ /// let local_struct = HelloWorldV1 {
+ /// message: Cow::Owned("example".to_string()),
+ /// };
+ ///
+ /// let payload =
+ /// DataPayload::<HelloWorldV1Marker>::from_owned(local_struct.clone());
+ ///
+ /// assert_eq!(payload.get(), &local_struct);
+ /// ```
+ #[inline]
+ pub fn from_owned(data: M::Yokeable) -> Self {
+ Self {
+ yoke: Yoke::new_owned(data),
+ }
+ }
+
+ /// Convert a DataPayload that was created via [`DataPayload::from_owned()`] back into the
+ /// concrete type used to construct it.
+ pub fn try_unwrap_owned(self) -> Result<M::Yokeable, DataError> {
+ self.yoke
+ .try_into_yokeable()
+ .map_err(|_| DataErrorKind::InvalidState.with_str_context("try_unwrap_owned"))
+ }
+
+ /// Mutate the data contained in this DataPayload.
+ ///
+ /// For safety, all mutation operations must take place within a helper function that cannot
+ /// borrow data from the surrounding context.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use icu_provider::hello_world::HelloWorldV1Marker;
+ /// use icu_provider::prelude::*;
+ ///
+ /// let mut payload =
+ /// DataPayload::<HelloWorldV1Marker>::from_static_str("Hello");
+ ///
+ /// payload.with_mut(|s| s.message.to_mut().push_str(" World"));
+ ///
+ /// assert_eq!("Hello World", payload.get().message);
+ /// ```
+ ///
+ /// To transfer data from the context into the data struct, use the `move` keyword:
+ ///
+ /// ```
+ /// use icu_provider::hello_world::HelloWorldV1Marker;
+ /// use icu_provider::prelude::*;
+ ///
+ /// let mut payload =
+ /// DataPayload::<HelloWorldV1Marker>::from_static_str("Hello");
+ ///
+ /// let suffix = " World".to_string();
+ /// payload.with_mut(move |s| s.message.to_mut().push_str(&suffix));
+ ///
+ /// assert_eq!("Hello World", payload.get().message);
+ /// ```
+ pub fn with_mut<'a, F>(&'a mut self, f: F)
+ where
+ F: 'static + for<'b> FnOnce(&'b mut <M::Yokeable as Yokeable<'a>>::Output),
+ {
+ self.yoke.with_mut(f)
+ }
+
+ /// Borrows the underlying data.
+ ///
+ /// This function should be used like `Deref` would normally be used. For more information on
+ /// why DataPayload cannot implement `Deref`, see the `yoke` crate.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use icu_provider::hello_world::HelloWorldV1Marker;
+ /// use icu_provider::prelude::*;
+ ///
+ /// let payload = DataPayload::<HelloWorldV1Marker>::from_static_str("Demo");
+ ///
+ /// assert_eq!("Demo", payload.get().message);
+ /// ```
+ #[inline]
+ #[allow(clippy::needless_lifetimes)]
+ pub fn get<'a>(&'a self) -> &'a <M::Yokeable as Yokeable<'a>>::Output {
+ self.yoke.get()
+ }
+
+ /// Maps `DataPayload<M>` to `DataPayload<M2>` by projecting it with [`Yoke::map_project`].
+ ///
+ /// This is accomplished by a function that takes `M`'s data type and returns `M2`'s data
+ /// type. The function takes a second argument which should be ignored. For more details,
+ /// see [`Yoke::map_project()`].
+ ///
+ /// The standard [`DataPayload::map_project()`] function moves `self` and cannot capture any
+ /// data from its context. Use one of the sister methods if you need these capabilities:
+ ///
+ /// - [`DataPayload::map_project_cloned()`] if you don't have ownership of `self`
+ /// - [`DataPayload::try_map_project()`] to bubble up an error
+ /// - [`DataPayload::try_map_project_cloned()`] to do both of the above
+ ///
+ /// # Examples
+ ///
+ /// Map from `HelloWorldV1` to a `Cow<str>` containing just the message:
+ ///
+ /// ```
+ /// use icu_provider::hello_world::*;
+ /// use icu_provider::prelude::*;
+ /// use std::borrow::Cow;
+ ///
+ /// // A custom marker type is required when using `map_project`. The Yokeable should be the
+ /// // target type, and the Cart should correspond to the type being transformed.
+ ///
+ /// struct HelloWorldV1MessageMarker;
+ /// impl DataMarker for HelloWorldV1MessageMarker {
+ /// type Yokeable = Cow<'static, str>;
+ /// }
+ ///
+ /// let p1: DataPayload<HelloWorldV1Marker> = DataPayload::from_owned(HelloWorldV1 {
+ /// message: Cow::Borrowed("Hello World"),
+ /// });
+ ///
+ /// assert_eq!("Hello World", p1.get().message);
+ ///
+ /// let p2: DataPayload<HelloWorldV1MessageMarker> = p1.map_project(|obj, _| obj.message);
+ ///
+ /// // Note: at this point, p1 has been moved.
+ /// assert_eq!("Hello World", p2.get());
+ /// ```
+ #[allow(clippy::type_complexity)]
+ pub fn map_project<M2, F>(self, f: F) -> DataPayload<M2>
+ where
+ M2: DataMarker,
+ F: for<'a> FnOnce(
+ <M::Yokeable as Yokeable<'a>>::Output,
+ PhantomData<&'a ()>,
+ ) -> <M2::Yokeable as Yokeable<'a>>::Output,
+ {
+ DataPayload {
+ yoke: self.yoke.map_project(f),
+ }
+ }
+
+ /// Version of [`DataPayload::map_project()`] that borrows `self` instead of moving `self`.
+ ///
+ /// # Examples
+ ///
+ /// Same example as above, but this time, do not move out of `p1`:
+ ///
+ /// ```
+ /// // Same imports and definitions as above
+ /// # use icu_provider::hello_world::*;
+ /// # use icu_provider::prelude::*;
+ /// # use std::borrow::Cow;
+ /// # struct HelloWorldV1MessageMarker;
+ /// # impl DataMarker for HelloWorldV1MessageMarker {
+ /// # type Yokeable = Cow<'static, str>;
+ /// # }
+ ///
+ /// let p1: DataPayload<HelloWorldV1Marker> =
+ /// DataPayload::from_owned(HelloWorldV1 {
+ /// message: Cow::Borrowed("Hello World"),
+ /// });
+ ///
+ /// assert_eq!("Hello World", p1.get().message);
+ ///
+ /// let p2: DataPayload<HelloWorldV1MessageMarker> =
+ /// p1.map_project_cloned(|obj, _| obj.message.clone());
+ ///
+ /// // Note: p1 is still valid.
+ /// assert_eq!(p1.get().message, *p2.get());
+ /// ```
+ #[allow(clippy::type_complexity)]
+ pub fn map_project_cloned<'this, M2, F>(&'this self, f: F) -> DataPayload<M2>
+ where
+ M2: DataMarker,
+ F: for<'a> FnOnce(
+ &'this <M::Yokeable as Yokeable<'a>>::Output,
+ PhantomData<&'a ()>,
+ ) -> <M2::Yokeable as Yokeable<'a>>::Output,
+ {
+ DataPayload {
+ yoke: self.yoke.map_project_cloned(f),
+ }
+ }
+
+ /// Version of [`DataPayload::map_project()`] that bubbles up an error from `f`.
+ ///
+ /// # Examples
+ ///
+ /// Same example as above, but bubble up an error:
+ ///
+ /// ```
+ /// // Same imports and definitions as above
+ /// # use icu_provider::hello_world::*;
+ /// # use icu_provider::prelude::*;
+ /// # use std::borrow::Cow;
+ /// # struct HelloWorldV1MessageMarker;
+ /// # impl DataMarker for HelloWorldV1MessageMarker {
+ /// # type Yokeable = Cow<'static, str>;
+ /// # }
+ ///
+ /// let p1: DataPayload<HelloWorldV1Marker> =
+ /// DataPayload::from_owned(HelloWorldV1 {
+ /// message: Cow::Borrowed("Hello World"),
+ /// });
+ ///
+ /// assert_eq!("Hello World", p1.get().message);
+ ///
+ /// let string_to_append = "Extra";
+ /// let p2: DataPayload<HelloWorldV1MessageMarker> =
+ /// p1.try_map_project(|mut obj, _| {
+ /// if obj.message.is_empty() {
+ /// return Err("Example error");
+ /// }
+ /// obj.message.to_mut().push_str(string_to_append);
+ /// Ok(obj.message)
+ /// })?;
+ ///
+ /// assert_eq!("Hello WorldExtra", p2.get());
+ /// # Ok::<(), &'static str>(())
+ /// ```
+ #[allow(clippy::type_complexity)]
+ pub fn try_map_project<M2, F, E>(self, f: F) -> Result<DataPayload<M2>, E>
+ where
+ M2: DataMarker,
+ F: for<'a> FnOnce(
+ <M::Yokeable as Yokeable<'a>>::Output,
+ PhantomData<&'a ()>,
+ ) -> Result<<M2::Yokeable as Yokeable<'a>>::Output, E>,
+ {
+ Ok(DataPayload {
+ yoke: self.yoke.try_map_project(f)?,
+ })
+ }
+
+ /// Version of [`DataPayload::map_project_cloned()`] that bubbles up an error from `f`.
+ ///
+ /// # Examples
+ ///
+ /// Same example as above, but bubble up an error:
+ ///
+ /// ```
+ /// // Same imports and definitions as above
+ /// # use icu_provider::hello_world::*;
+ /// # use icu_provider::prelude::*;
+ /// # use std::borrow::Cow;
+ /// # struct HelloWorldV1MessageMarker;
+ /// # impl DataMarker for HelloWorldV1MessageMarker {
+ /// # type Yokeable = Cow<'static, str>;
+ /// # }
+ ///
+ /// let p1: DataPayload<HelloWorldV1Marker> =
+ /// DataPayload::from_owned(HelloWorldV1 {
+ /// message: Cow::Borrowed("Hello World"),
+ /// });
+ ///
+ /// assert_eq!("Hello World", p1.get().message);
+ ///
+ /// let string_to_append = "Extra";
+ /// let p2: DataPayload<HelloWorldV1MessageMarker> = p1
+ /// .try_map_project_cloned(|obj, _| {
+ /// if obj.message.is_empty() {
+ /// return Err("Example error");
+ /// }
+ /// let mut message = obj.message.clone();
+ /// message.to_mut().push_str(string_to_append);
+ /// Ok(message)
+ /// })?;
+ ///
+ /// // Note: p1 is still valid, but the values no longer equal.
+ /// assert_ne!(p1.get().message, *p2.get());
+ /// assert_eq!("Hello WorldExtra", p2.get());
+ /// # Ok::<(), &'static str>(())
+ /// ```
+ #[allow(clippy::type_complexity)]
+ pub fn try_map_project_cloned<'this, M2, F, E>(&'this self, f: F) -> Result<DataPayload<M2>, E>
+ where
+ M2: DataMarker,
+ F: for<'a> FnOnce(
+ &'this <M::Yokeable as Yokeable<'a>>::Output,
+ PhantomData<&'a ()>,
+ ) -> Result<<M2::Yokeable as Yokeable<'a>>::Output, E>,
+ {
+ Ok(DataPayload {
+ yoke: self.yoke.try_map_project_cloned(f)?,
+ })
+ }
+
+ /// Convert between two [`DataMarker`] types that are compatible with each other.
+ ///
+ /// This happens if they both have the same [`DataMarker::Yokeable`] type.
+ ///
+ /// Can be used to erase the key of a data payload in cases where multiple keys correspond
+ /// to the same data struct.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use icu_locid::locale;
+ /// use icu_provider::hello_world::*;
+ /// use icu_provider::prelude::*;
+ ///
+ /// struct CustomHelloWorldV1Marker;
+ /// impl DataMarker for CustomHelloWorldV1Marker {
+ /// type Yokeable = HelloWorldV1<'static>;
+ /// }
+ ///
+ /// let hello_world: DataPayload<HelloWorldV1Marker> = todo!();
+ /// let custom: DataPayload<CustomHelloWorldV1Marker> = hello_world.cast();
+ /// ```
+ #[inline]
+ pub fn cast<M2>(self) -> DataPayload<M2>
+ where
+ M2: DataMarker<Yokeable = M::Yokeable>,
+ {
+ DataPayload { yoke: self.yoke }
+ }
+}
+
+impl DataPayload<BufferMarker> {
+ /// Converts an owned byte buffer into a `DataPayload<BufferMarker>`.
+ pub fn from_owned_buffer(buffer: Box<[u8]>) -> Self {
+ let yoke = Yoke::attach_to_cart(SelectedRc::new(buffer), |b| &**b);
+ // Safe because cart is wrapped
+ let yoke = unsafe { yoke.replace_cart(|b| Some(Cart(b))) };
+ Self { yoke }
+ }
+
+ /// Converts a yoked byte buffer into a `DataPayload<BufferMarker>`.
+ pub fn from_yoked_buffer(yoke: Yoke<&'static [u8], Option<Cart>>) -> Self {
+ Self { yoke }
+ }
+
+ /// Converts a static byte buffer into a `DataPayload<BufferMarker>`.
+ pub fn from_static_buffer(buffer: &'static [u8]) -> Self {
+ Self {
+ yoke: Yoke::new_owned(buffer),
+ }
+ }
+}
+
+impl<M> Default for DataPayload<M>
+where
+ M: DataMarker,
+ M::Yokeable: Default,
+{
+ fn default() -> Self {
+ Self::from_owned(Default::default())
+ }
+}
+
+/// A response object containing an object as payload and metadata about it.
+#[allow(clippy::exhaustive_structs)] // this type is stable
+pub struct DataResponse<M>
+where
+ M: DataMarker,
+{
+ /// Metadata about the returned object.
+ pub metadata: DataResponseMetadata,
+
+ /// The object itself; None if it was not loaded.
+ pub payload: Option<DataPayload<M>>,
+}
+
+impl<M> DataResponse<M>
+where
+ M: DataMarker,
+{
+ /// Takes ownership of the underlying payload. Error if not present.
+ ///
+ /// To take the metadata, too, use [`Self::take_metadata_and_payload()`].
+ #[inline]
+ pub fn take_payload(self) -> Result<DataPayload<M>, DataError> {
+ Ok(self.take_metadata_and_payload()?.1)
+ }
+
+ /// Takes ownership of the underlying metadata and payload. Error if payload is not present.
+ #[inline]
+ pub fn take_metadata_and_payload(
+ self,
+ ) -> Result<(DataResponseMetadata, DataPayload<M>), DataError> {
+ Ok((
+ self.metadata,
+ self.payload
+ .ok_or_else(|| DataErrorKind::MissingPayload.with_type_context::<M>())?,
+ ))
+ }
+}
+
+impl<M> TryFrom<DataResponse<M>> for DataPayload<M>
+where
+ M: DataMarker,
+{
+ type Error = DataError;
+
+ fn try_from(response: DataResponse<M>) -> Result<Self, Self::Error> {
+ response.take_payload()
+ }
+}
+
+impl<M> Debug for DataResponse<M>
+where
+ M: DataMarker,
+ for<'a> &'a <M::Yokeable as Yokeable<'a>>::Output: Debug,
+{
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "DataResponse {{ metadata: {:?}, payload: {:?} }}",
+ self.metadata, self.payload
+ )
+ }
+}
+
+/// Cloning a DataResponse is generally a cheap operation.
+/// See notes in the `Clone` impl for [`Yoke`].
+///
+/// # Examples
+///
+/// ```no_run
+/// use icu_provider::hello_world::*;
+/// use icu_provider::prelude::*;
+///
+/// let resp1: DataResponse<HelloWorldV1Marker> = todo!();
+/// let resp2 = resp1.clone();
+/// ```
+impl<M> Clone for DataResponse<M>
+where
+ M: DataMarker,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
+{
+ fn clone(&self) -> Self {
+ Self {
+ metadata: self.metadata.clone(),
+ payload: self.payload.clone(),
+ }
+ }
+}
+
+#[test]
+fn test_debug() {
+ use crate::hello_world::*;
+ use alloc::borrow::Cow;
+ let resp = DataResponse::<HelloWorldV1Marker> {
+ metadata: Default::default(),
+ payload: Some(DataPayload::from_owned(HelloWorldV1 {
+ message: Cow::Borrowed("foo"),
+ })),
+ };
+ assert_eq!("DataResponse { metadata: DataResponseMetadata { locale: None, buffer_format: None }, payload: Some(HelloWorldV1 { message: \"foo\" }) }", format!("{:?}", resp));
+}
diff --git a/vendor/icu_provider/src/serde/borrow_de_utils.rs b/vendor/icu_provider/src/serde/borrow_de_utils.rs
new file mode 100644
index 000000000..afce7641e
--- /dev/null
+++ b/vendor/icu_provider/src/serde/borrow_de_utils.rs
@@ -0,0 +1,80 @@
+// 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 ).
+
+use alloc::borrow::Cow;
+use serde::de::Deserializer;
+use serde::Deserialize;
+
+#[derive(Deserialize)]
+#[serde(transparent)]
+// Cows fail to borrow in some situations (array, option), but structs of Cows don't.
+#[allow(clippy::exhaustive_structs)] // newtype
+pub struct CowWrap<'data>(#[serde(borrow)] pub Cow<'data, str>);
+
+#[derive(Deserialize)]
+#[serde(transparent)]
+// Cows fail to borrow in some situations (array, option), but structs of Cows don't.
+#[allow(clippy::exhaustive_structs)] // newtype
+pub struct CowBytesWrap<'data>(#[serde(borrow)] pub Cow<'data, [u8]>);
+
+pub fn array_of_cow<'de, D, const N: usize>(deserializer: D) -> Result<[Cow<'de, str>; N], D::Error>
+where
+ D: Deserializer<'de>,
+ [CowWrap<'de>; N]: Deserialize<'de>,
+{
+ <[CowWrap<'de>; N]>::deserialize(deserializer).map(|array| array.map(|wrap| wrap.0))
+}
+
+pub fn option_of_cow<'de, D>(deserializer: D) -> Result<Option<Cow<'de, str>>, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ <Option<CowWrap<'de>>>::deserialize(deserializer).map(|opt| opt.map(|wrap| wrap.0))
+}
+
+pub fn tuple_of_cow<'de, D>(deserializer: D) -> Result<(Cow<'de, str>, Cow<'de, str>), D::Error>
+where
+ D: Deserializer<'de>,
+ (CowWrap<'de>, CowWrap<'de>): Deserialize<'de>,
+{
+ <(CowWrap<'de>, CowWrap<'de>)>::deserialize(deserializer).map(|x| (x.0 .0, x.1 .0))
+}
+
+#[test]
+fn test_option() {
+ #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
+ struct Demo<'s>(#[serde(borrow, deserialize_with = "option_of_cow")] Option<Cow<'s, str>>);
+
+ let data_orig = Demo(Some("Hello world".into()));
+ let json = serde_json::to_string(&data_orig).expect("serialize");
+ let data_new = serde_json::from_str::<Demo>(&json).expect("deserialize");
+ assert_eq!(data_orig, data_new);
+ assert!(matches!(data_new.0, Some(Cow::Borrowed(_))));
+}
+
+#[test]
+fn test_tuple() {
+ #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
+ struct Demo<'s>(
+ #[serde(borrow, deserialize_with = "tuple_of_cow")] (Cow<'s, str>, Cow<'s, str>),
+ );
+
+ let data_orig = Demo(("Hello world".into(), "Hello earth".into()));
+ let json = serde_json::to_string(&data_orig).expect("serialize");
+ let data_new = serde_json::from_str::<Demo>(&json).expect("deserialize");
+ assert_eq!(data_orig, data_new);
+ assert!(matches!(data_new.0, (Cow::Borrowed(_), Cow::Borrowed(_))));
+}
+
+#[test]
+fn test_array() {
+ #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
+ struct Demo<'s>(#[serde(borrow, deserialize_with = "array_of_cow")] [Cow<'s, str>; 1]);
+
+ let data_orig = Demo(["Hello world".into()]);
+ let json = serde_json::to_string(&data_orig).expect("serialize");
+ let data_new = serde_json::from_str::<Demo>(&json).expect("deserialize");
+ assert_eq!(data_orig, data_new);
+ assert!(matches!(data_new.0, [Cow::Borrowed(_)]));
+}
diff --git a/vendor/icu_provider/src/serde/mod.rs b/vendor/icu_provider/src/serde/mod.rs
new file mode 100644
index 000000000..d32148f02
--- /dev/null
+++ b/vendor/icu_provider/src/serde/mod.rs
@@ -0,0 +1,187 @@
+// 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 ).
+
+//! Provides the [`DeserializingBufferProvider`] wrapper, which deserializes data using Serde.
+//!
+//! Providers that produce opaque buffers that need to be deserialized into concrete data structs,
+//! such as `FsDataProvider`, should implement [`BufferProvider`]. These can be converted into
+//! [`DeserializingBufferProvider`] using the [`as_deserializing`](AsDeserializingBufferProvider::as_deserializing)
+//! convenience method.
+//!
+//! [`BufferProvider`]: crate::buf::BufferProvider
+
+// Hidden for now, but could be made public-stable in the future.
+#[doc(hidden)]
+pub mod borrow_de_utils;
+
+use crate::buf::BufferFormat;
+use crate::buf::BufferProvider;
+use crate::prelude::*;
+use serde::de::Deserialize;
+use yoke::trait_hack::YokeTraitHack;
+use yoke::Yokeable;
+
+/// A [`BufferProvider`] that deserializes its data using Serde.
+pub struct DeserializingBufferProvider<'a, P: ?Sized>(&'a P);
+
+/// Blanket-implemented trait adding the [`Self::as_deserializing()`] function.
+pub trait AsDeserializingBufferProvider {
+ /// Wrap this [`BufferProvider`] in a [`DeserializingBufferProvider`].
+ fn as_deserializing(&self) -> DeserializingBufferProvider<Self>;
+}
+
+impl<P> AsDeserializingBufferProvider for P
+where
+ P: BufferProvider + ?Sized,
+{
+ /// Wrap this [`BufferProvider`] in a [`DeserializingBufferProvider`].
+ fn as_deserializing(&self) -> DeserializingBufferProvider<Self> {
+ DeserializingBufferProvider(self)
+ }
+}
+
+fn deserialize_impl<'data, M>(
+ // Allow `bytes` to be unused in case all buffer formats are disabled
+ #[allow(unused_variables)] bytes: &'data [u8],
+ buffer_format: BufferFormat,
+) -> Result<<M::Yokeable as Yokeable<'data>>::Output, DataError>
+where
+ M: DataMarker,
+ // Actual bound:
+ // for<'de> <M::Yokeable as Yokeable<'de>>::Output: Deserialize<'de>,
+ // Necessary workaround bound (see `yoke::trait_hack` docs):
+ for<'de> YokeTraitHack<<M::Yokeable as Yokeable<'de>>::Output>: Deserialize<'de>,
+{
+ match buffer_format {
+ #[cfg(feature = "deserialize_json")]
+ BufferFormat::Json => {
+ let mut d = serde_json::Deserializer::from_slice(bytes);
+ let data = YokeTraitHack::<<M::Yokeable as Yokeable>::Output>::deserialize(&mut d)?;
+ Ok(data.0)
+ }
+
+ #[cfg(feature = "deserialize_bincode_1")]
+ BufferFormat::Bincode1 => {
+ use bincode::Options;
+ let options = bincode::DefaultOptions::new()
+ .with_fixint_encoding()
+ .allow_trailing_bytes();
+ let mut d = bincode::de::Deserializer::from_slice(bytes, options);
+ let data = YokeTraitHack::<<M::Yokeable as Yokeable>::Output>::deserialize(&mut d)?;
+ Ok(data.0)
+ }
+
+ #[cfg(feature = "deserialize_postcard_1")]
+ BufferFormat::Postcard1 => {
+ let mut d = postcard::Deserializer::from_bytes(bytes);
+ let data = YokeTraitHack::<<M::Yokeable as Yokeable>::Output>::deserialize(&mut d)?;
+ Ok(data.0)
+ }
+
+ // Allowed for cases in which all features are enabled
+ #[allow(unreachable_patterns)]
+ _ => Err(DataErrorKind::UnavailableBufferFormat(buffer_format).into_error()),
+ }
+}
+
+impl DataPayload<BufferMarker> {
+ /// Deserialize a [`DataPayload`]`<`[`BufferMarker`]`>` into a [`DataPayload`] of a
+ /// specific concrete type.
+ ///
+ /// This function takes the buffer format as an argument. When a buffer payload is returned
+ /// from a data provider, the buffer format is stored in the [`DataResponseMetadata`].
+ ///
+ /// # Examples
+ ///
+ /// Requires the `deserialize_json` feature:
+ ///
+ /// ```
+ /// use icu_provider::buf::BufferFormat;
+ /// use icu_provider::hello_world::*;
+ /// use icu_provider::prelude::*;
+ ///
+ /// let buffer: &[u8] = b"{\"message\":\"Hallo Welt\"}";
+ ///
+ /// let buffer_payload = DataPayload::from_owned(buffer);
+ /// let payload: DataPayload<HelloWorldV1Marker> = buffer_payload
+ /// .into_deserialized(BufferFormat::Json)
+ /// .expect("Deserialization successful");
+ ///
+ /// assert_eq!(payload.get().message, "Hallo Welt");
+ /// ```
+ pub fn into_deserialized<M>(
+ self,
+ buffer_format: BufferFormat,
+ ) -> Result<DataPayload<M>, DataError>
+ where
+ M: DataMarker,
+ // Actual bound:
+ // for<'de> <M::Yokeable as Yokeable<'de>>::Output: Deserialize<'de>,
+ // Necessary workaround bound (see `yoke::trait_hack` docs):
+ for<'de> YokeTraitHack<<M::Yokeable as Yokeable<'de>>::Output>: Deserialize<'de>,
+ {
+ self.try_map_project(|bytes, _| deserialize_impl::<M>(bytes, buffer_format))
+ }
+}
+
+impl<P, M> DynamicDataProvider<M> for DeserializingBufferProvider<'_, P>
+where
+ M: DataMarker,
+ P: BufferProvider + ?Sized,
+ // Actual bound:
+ // for<'de> <M::Yokeable as Yokeable<'de>>::Output: serde::de::Deserialize<'de>,
+ // Necessary workaround bound (see `yoke::trait_hack` docs):
+ for<'de> YokeTraitHack<<M::Yokeable as Yokeable<'de>>::Output>: Deserialize<'de>,
+{
+ fn load_data(&self, key: DataKey, req: DataRequest) -> Result<DataResponse<M>, DataError> {
+ let buffer_response = BufferProvider::load_buffer(self.0, key, req)?;
+ let buffer_format = buffer_response
+ .metadata
+ .buffer_format
+ .ok_or_else(|| DataError::custom("BufferProvider didn't set BufferFormat"))?;
+ Ok(DataResponse {
+ metadata: buffer_response.metadata,
+ payload: buffer_response
+ .payload
+ .map(|p| p.into_deserialized(buffer_format))
+ .transpose()?,
+ })
+ }
+}
+
+impl<P, M> DataProvider<M> for DeserializingBufferProvider<'_, P>
+where
+ M: KeyedDataMarker,
+ P: BufferProvider + ?Sized,
+ // Actual bound:
+ // for<'de> <M::Yokeable as Yokeable<'de>>::Output: Deserialize<'de>,
+ // Necessary workaround bound (see `yoke::trait_hack` docs):
+ for<'de> YokeTraitHack<<M::Yokeable as Yokeable<'de>>::Output>: Deserialize<'de>,
+{
+ /// Converts a buffer into a concrete type by deserializing from a supported buffer format.
+ fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
+ self.load_data(M::KEY, req)
+ }
+}
+
+#[cfg(feature = "serde_json")]
+impl From<serde_json::error::Error> for crate::DataError {
+ fn from(e: serde_json::error::Error) -> Self {
+ crate::DataError::custom("JSON deserialize").with_display_context(&e)
+ }
+}
+
+#[cfg(feature = "bincode")]
+impl From<bincode::Error> for crate::DataError {
+ fn from(e: bincode::Error) -> Self {
+ crate::DataError::custom("Bincode deserialize").with_display_context(&e)
+ }
+}
+
+#[cfg(feature = "postcard")]
+impl From<postcard::Error> for crate::DataError {
+ fn from(e: postcard::Error) -> Self {
+ crate::DataError::custom("Postcard deserialize").with_display_context(&e)
+ }
+}