summaryrefslogtreecommitdiffstats
path: root/vendor/icu_provider/src/datagen
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/icu_provider/src/datagen')
-rw-r--r--vendor/icu_provider/src/datagen/data_conversion.rs10
-rw-r--r--vendor/icu_provider/src/datagen/mod.rs128
-rw-r--r--vendor/icu_provider/src/datagen/payload.rs99
3 files changed, 210 insertions, 27 deletions
diff --git a/vendor/icu_provider/src/datagen/data_conversion.rs b/vendor/icu_provider/src/datagen/data_conversion.rs
index 59146352a..f3ca948e1 100644
--- a/vendor/icu_provider/src/datagen/data_conversion.rs
+++ b/vendor/icu_provider/src/datagen/data_conversion.rs
@@ -9,16 +9,12 @@ 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.
+/// [`AnyMarker`], [`BufferMarker`], or [`ExportMarker`](crate::datagen::ExportMarker), 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.
diff --git a/vendor/icu_provider/src/datagen/mod.rs b/vendor/icu_provider/src/datagen/mod.rs
index 6596a0c07..ae1779ab3 100644
--- a/vendor/icu_provider/src/datagen/mod.rs
+++ b/vendor/icu_provider/src/datagen/mod.rs
@@ -21,6 +21,14 @@ pub use payload::{ExportBox, ExportMarker};
use crate::prelude::*;
+/// The type of built-in fallback that the data was generated for, if applicable.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum BuiltInFallbackMode {
+ /// Data uses full UTS 35 fallbacking.
+ Standard,
+}
+
/// An object capable of exporting data payloads in some form.
pub trait DataExporter: Sync {
/// Save a `payload` corresponding to the given key and locale.
@@ -32,7 +40,34 @@ pub trait DataExporter: Sync {
payload: &DataPayload<ExportMarker>,
) -> Result<(), DataError>;
- /// Function called after all keys have been fully dumped.
+ /// Function called for singleton keys.
+ /// Takes non-mut self as it can be called concurrently.
+ fn flush_singleton(
+ &self,
+ key: DataKey,
+ payload: &DataPayload<ExportMarker>,
+ ) -> Result<(), DataError> {
+ self.put_payload(key, &Default::default(), payload)?;
+ self.flush(key)
+ }
+
+ /// Function called after a non-singleton key has been fully enumerated,
+ /// flushing that key with built-in fallback.
+ ///
+ /// Takes non-mut self as it can be called concurrently.
+ fn flush_with_built_in_fallback(
+ &self,
+ _key: DataKey,
+ _fallback_mode: BuiltInFallbackMode,
+ ) -> Result<(), DataError> {
+ Err(DataError::custom(
+ "Exporter does not implement built-in fallback",
+ ))
+ }
+
+ /// Function called after a non-singleton key has been fully enumerated.
+ /// Does not include built-in fallback.
+ ///
/// Takes non-mut self as it can be called concurrently.
fn flush(&self, _key: DataKey) -> Result<(), DataError> {
Ok(())
@@ -44,13 +79,26 @@ pub trait DataExporter: Sync {
fn close(&mut self) -> Result<(), DataError> {
Ok(())
}
+
+ /// Returns whether the provider supports built-in fallback. If `true`, the provider must
+ /// implement [`Self::flush_with_built_in_fallback()`].
+ fn supports_built_in_fallback(&self) -> bool {
+ false
+ }
}
/// A [`DynamicDataProvider`] that can be used for exporting data.
///
/// Use [`make_exportable_provider`](crate::make_exportable_provider) to implement this.
-pub trait ExportableProvider: IterableDynamicDataProvider<ExportMarker> + Sync {}
-impl<T> ExportableProvider for T where T: IterableDynamicDataProvider<ExportMarker> + Sync {}
+pub trait ExportableProvider:
+ IterableDynamicDataProvider<ExportMarker> + DynamicDataProvider<AnyMarker> + Sync
+{
+}
+
+impl<T> ExportableProvider for T where
+ T: IterableDynamicDataProvider<ExportMarker> + DynamicDataProvider<AnyMarker> + Sync
+{
+}
/// This macro can be used on a data provider to allow it to be used for data generation.
///
@@ -66,28 +114,24 @@ impl<T> ExportableProvider for T where T: IterableDynamicDataProvider<ExportMark
/// [`BakedDataProvider`]: ../../icu_datagen/index.html
#[macro_export]
macro_rules! make_exportable_provider {
- ($provider:ty, [ $($struct_m:ident),+, ]) => {
+ ($provider:ty, [ $($(#[$cfg:meta])? $struct_m:ty),+, ]) => {
$crate::impl_dynamic_data_provider!(
$provider,
- [ $($struct_m),+, ],
+ [ $($(#[$cfg])? $struct_m),+, ],
$crate::datagen::ExportMarker
);
$crate::impl_dynamic_data_provider!(
$provider,
- [ $($struct_m),+, ],
+ [ $($(#[$cfg])? $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 => {
+ $(#[$cfg])?
+ h if h == <$struct_m as $crate::KeyedDataMarker>::KEY.hashed() => {
$crate::datagen::IterableDataProvider::<$struct_m>::supported_locales(self)
}
)+,
@@ -97,3 +141,63 @@ macro_rules! make_exportable_provider {
}
};
}
+
+/// A `DataExporter` that forks to multiple `DataExporter`s.
+#[derive(Default)]
+pub struct MultiExporter(Vec<Box<dyn DataExporter>>);
+
+impl MultiExporter {
+ /// Creates a `MultiExporter` for the given exporters.
+ pub const fn new(exporters: Vec<Box<dyn DataExporter>>) -> Self {
+ Self(exporters)
+ }
+}
+
+impl core::fmt::Debug for MultiExporter {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("MultiExporter")
+ .field("0", &format!("vec[len = {}]", self.0.len()))
+ .finish()
+ }
+}
+
+impl DataExporter for MultiExporter {
+ fn put_payload(
+ &self,
+ key: DataKey,
+ locale: &DataLocale,
+ payload: &DataPayload<ExportMarker>,
+ ) -> Result<(), DataError> {
+ self.0
+ .iter()
+ .try_for_each(|e| e.put_payload(key, locale, payload))
+ }
+
+ fn flush_singleton(
+ &self,
+ key: DataKey,
+ payload: &DataPayload<ExportMarker>,
+ ) -> Result<(), DataError> {
+ self.0
+ .iter()
+ .try_for_each(|e| e.flush_singleton(key, payload))
+ }
+
+ fn flush(&self, key: DataKey) -> Result<(), DataError> {
+ self.0.iter().try_for_each(|e| e.flush(key))
+ }
+
+ fn flush_with_built_in_fallback(
+ &self,
+ key: DataKey,
+ fallback_mode: BuiltInFallbackMode,
+ ) -> Result<(), DataError> {
+ self.0
+ .iter()
+ .try_for_each(|e| e.flush_with_built_in_fallback(key, fallback_mode))
+ }
+
+ fn close(&mut self) -> Result<(), DataError> {
+ self.0.iter_mut().try_for_each(|e| e.close())
+ }
+}
diff --git a/vendor/icu_provider/src/datagen/payload.rs b/vendor/icu_provider/src/datagen/payload.rs
index c0d0a8bb9..97e540b07 100644
--- a/vendor/icu_provider/src/datagen/payload.rs
+++ b/vendor/icu_provider/src/datagen/payload.rs
@@ -2,24 +2,29 @@
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
+use core::any::Any;
+
use crate::dynutil::UpcastDataPayload;
use crate::prelude::*;
use alloc::boxed::Box;
use databake::{Bake, CrateEnv, TokenStream};
+use yoke::trait_hack::YokeTraitHack;
use yoke::*;
-trait ExportableYoke {
+trait ExportableDataPayload {
fn bake_yoke(&self, env: &CrateEnv) -> TokenStream;
fn serialize_yoke(
&self,
serializer: &mut dyn erased_serde::Serializer,
) -> Result<(), DataError>;
+ fn as_any(&self) -> &dyn Any;
+ fn eq_dyn(&self, other: &dyn ExportableDataPayload) -> bool;
}
-impl<Y, C> ExportableYoke for Yoke<Y, C>
+impl<M: DataMarker> ExportableDataPayload for DataPayload<M>
where
- Y: for<'a> Yokeable<'a>,
- for<'a> <Y as Yokeable<'a>>::Output: Bake + serde::Serialize,
+ for<'a> <M::Yokeable as Yokeable<'a>>::Output: Bake + serde::Serialize,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: PartialEq,
{
fn bake_yoke(&self, ctx: &CrateEnv) -> TokenStream {
self.get().bake(ctx)
@@ -35,12 +40,37 @@ where
.map_err(|e| DataError::custom("Serde export").with_display_context(&e))?;
Ok(())
}
+
+ fn as_any(&self) -> &dyn Any {
+ self
+ }
+
+ fn eq_dyn(&self, other: &dyn ExportableDataPayload) -> bool {
+ match other.as_any().downcast_ref::<Self>() {
+ Some(downcasted) => (*self).eq(downcasted),
+ None => {
+ debug_assert!(
+ false,
+ "cannot compare ExportableDataPayloads of different types: self is {:?} but other is {:?}",
+ self.type_id(),
+ other.as_any().type_id(),
+ );
+ false
+ }
+ }
+ }
}
#[doc(hidden)] // exposed for make_exportable_provider
#[derive(yoke::Yokeable)]
pub struct ExportBox {
- payload: Box<dyn ExportableYoke + Sync>,
+ payload: Box<dyn ExportableDataPayload + Sync + Send>,
+}
+
+impl PartialEq for ExportBox {
+ fn eq(&self, other: &Self) -> bool {
+ self.payload.eq_dyn(&*other.payload)
+ }
}
impl core::fmt::Debug for ExportBox {
@@ -54,12 +84,13 @@ impl core::fmt::Debug for ExportBox {
impl<M> UpcastDataPayload<M> for ExportMarker
where
M: DataMarker,
- M::Yokeable: Sync,
+ M::Yokeable: Sync + Send,
for<'a> <M::Yokeable as Yokeable<'a>>::Output: Bake + serde::Serialize,
+ for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: PartialEq,
{
fn upcast(other: DataPayload<M>) -> DataPayload<ExportMarker> {
DataPayload::from_owned(ExportBox {
- payload: Box::new(other.yoke),
+ payload: Box::new(other),
})
}
}
@@ -117,7 +148,7 @@ impl DataPayload<ExportMarker> {
/// let tokens = export.tokenize(&env);
/// assert_eq!(
/// quote! {
- /// ::icu_provider::hello_world::HelloWorldV1 {
+ /// icu_provider::hello_world::HelloWorldV1 {
/// message: alloc::borrow::Cow::Borrowed("(und) Hello World"),
/// }
/// }
@@ -144,3 +175,55 @@ pub struct ExportMarker {}
impl DataMarker for ExportMarker {
type Yokeable = ExportBox;
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::hello_world::*;
+
+ #[test]
+ fn test_compare_with_dyn() {
+ let payload1: DataPayload<HelloWorldV1Marker> = DataPayload::from_owned(HelloWorldV1 {
+ message: "abc".into(),
+ });
+ let payload2: DataPayload<HelloWorldV1Marker> = DataPayload::from_owned(HelloWorldV1 {
+ message: "abc".into(),
+ });
+ let payload3: DataPayload<HelloWorldV1Marker> = DataPayload::from_owned(HelloWorldV1 {
+ message: "def".into(),
+ });
+
+ assert!(payload1.eq_dyn(&payload2));
+ assert!(payload2.eq_dyn(&payload1));
+
+ assert!(!payload1.eq_dyn(&payload3));
+ assert!(!payload3.eq_dyn(&payload1));
+ }
+
+ #[test]
+ fn test_export_marker_partial_eq() {
+ let payload1: DataPayload<ExportMarker> =
+ UpcastDataPayload::upcast(DataPayload::<HelloWorldV1Marker>::from_owned(
+ HelloWorldV1 {
+ message: "abc".into(),
+ },
+ ));
+ let payload2: DataPayload<ExportMarker> =
+ UpcastDataPayload::upcast(DataPayload::<HelloWorldV1Marker>::from_owned(
+ HelloWorldV1 {
+ message: "abc".into(),
+ },
+ ));
+ let payload3: DataPayload<ExportMarker> =
+ UpcastDataPayload::upcast(DataPayload::<HelloWorldV1Marker>::from_owned(
+ HelloWorldV1 {
+ message: "def".into(),
+ },
+ ));
+
+ assert_eq!(payload1, payload2);
+ assert_eq!(payload2, payload1);
+ assert_ne!(payload1, payload3);
+ assert_ne!(payload3, payload1);
+ }
+}