diff options
Diffstat (limited to 'vendor/icu_provider/src/datagen')
-rw-r--r-- | vendor/icu_provider/src/datagen/data_conversion.rs | 10 | ||||
-rw-r--r-- | vendor/icu_provider/src/datagen/mod.rs | 128 | ||||
-rw-r--r-- | vendor/icu_provider/src/datagen/payload.rs | 99 |
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); + } +} |