diff --git a/components/icu/Cargo.toml b/components/icu/Cargo.toml index f68edba47ec..829e124569e 100644 --- a/components/icu/Cargo.toml +++ b/components/icu/Cargo.toml @@ -153,6 +153,10 @@ required-features = ["compiled_data"] name = "code_line_diff" required-features = ["serde"] +[[example]] +name = "coll_mis" +required-features = ["serde"] + [[example]] name = "and_list" diff --git a/components/icu/examples/coll_mis.rs b/components/icu/examples/coll_mis.rs new file mode 100644 index 00000000000..387ac573bd6 --- /dev/null +++ b/components/icu/examples/coll_mis.rs @@ -0,0 +1,104 @@ +// 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 ). + +#![no_main] // https://github.com/unicode-org/icu4x/issues/395 +icu_benchmark_macros::instrument!(); + +use icu_benchmark_macros::println; + +use icu::collator::Collator; +use icu::locale::locale; +use icu_collator::options::CollatorOptions; +use icu_collator::provider::*; +use icu_collator::CollatorPreferences; +use icu_normalizer::provider::*; +use icu_provider_adapters::fork::ForkByMarkerProvider; +use icu_provider_blob::BlobDataProvider; + +fn main() { + let mis_blob = std::fs::read("mis_collation.postcard").unwrap(); + let root_blob = std::fs::read("root_collation.postcard").unwrap(); + + let blob_provider = ForkByMarkerProvider::new( + BlobDataProvider::try_new_from_blob(mis_blob.clone().into()).unwrap(), + BlobDataProvider::try_new_from_blob(root_blob.into()).unwrap(), + ); + + struct MyProvider { + blob: BlobDataProvider, + collator: icu::collator::provider::Baked, + normalizer: icu::normalizer::provider::Baked, + } + + icu_provider_adapters::delegate::data_provider_to_field!( + MyProvider, + CollationMetadataV1, + &self.blob.as_deserializing() + ); + icu_provider_adapters::delegate::data_provider_to_field!( + MyProvider, + CollationTailoringV1, + &self.blob.as_deserializing() + ); + icu_provider_adapters::delegate::data_provider_to_field!( + MyProvider, + CollationDiacriticsV1, + &self.collator + ); + icu_provider_adapters::delegate::data_provider_to_field!( + MyProvider, + CollationJamoV1, + &self.collator + ); + icu_provider_adapters::delegate::data_provider_to_field!( + MyProvider, + CollationReorderingV1, + &self.collator + ); + icu_provider_adapters::delegate::data_provider_to_field!( + MyProvider, + CollationRootV1, + &self.collator + ); + icu_provider_adapters::delegate::data_provider_to_field!( + MyProvider, + CollationSpecialPrimariesV1, + &self.collator + ); + icu_provider_adapters::delegate::data_provider_to_field!( + MyProvider, + NormalizerNfdDataV1, + &self.normalizer + ); + icu_provider_adapters::delegate::data_provider_to_field!( + MyProvider, + NormalizerNfdTablesV1, + &self.normalizer + ); + + let prefs = CollatorPreferences::from(locale!("mis")); + let options = CollatorOptions::default(); + + let blob_or_baked_provider = MyProvider { + blob: BlobDataProvider::try_new_from_blob(mis_blob.into()).unwrap(), + collator: icu::collator::provider::Baked, + normalizer: icu::normalizer::provider::Baked, + }; + + let default_collator = Collator::try_new(prefs, options).unwrap(); + let custom_blob_collator = + Collator::try_new_with_buffer_provider(&blob_provider, prefs, options).unwrap(); + let custom_baked_collator = + Collator::try_new_unstable(&blob_or_baked_provider, prefs, options).unwrap(); + + println!("Default: {:?}", default_collator.compare("ı", "I")); + println!( + "Custom All Blob: {:?}", + custom_blob_collator.as_borrowed().compare("ı", "I") + ); + println!( + "Custom Blob Baked Hybrid: {:?}", + custom_baked_collator.as_borrowed().compare("ı", "I") + ); +} diff --git a/components/icu/mis_collation.postcard b/components/icu/mis_collation.postcard new file mode 100644 index 00000000000..a35075f2f2b Binary files /dev/null and b/components/icu/mis_collation.postcard differ diff --git a/components/icu/root_collation.postcard b/components/icu/root_collation.postcard new file mode 100644 index 00000000000..8106dbf65c3 Binary files /dev/null and b/components/icu/root_collation.postcard differ diff --git a/provider/adapters/src/delegate.rs b/provider/adapters/src/delegate.rs new file mode 100644 index 00000000000..936c795c09a --- /dev/null +++ b/provider/adapters/src/delegate.rs @@ -0,0 +1,97 @@ +// 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 ). + +//! Macros for delegating impls to inner data providers. + +/// Delegate an impl of `DataProvider` to a field of a struct. +/// +/// # Examples +/// +/// ``` +/// use icu_provider::hello_world::*; +/// use icu_locale::locale; +/// +/// struct Wrap(HelloWorldProvider); +/// +/// // Delegate `DataProvider` to the field `self.0` +/// icu_provider_adapters::delegate::data_provider_to_field!(Wrap, HelloWorldV1, &self.0); +/// +/// // Test that it works +/// let wrap = Wrap(HelloWorldProvider::default()); +/// HelloWorldFormatter::try_new_unstable(&wrap, locale!("de").into()).unwrap(); +/// ``` +/// +/// Also works if the field is a [`BufferProvider`]: +/// +/// ``` +/// use icu_provider::hello_world::*; +/// use icu_locale::locale; +/// +/// struct Wrap(HelloWorldJsonProvider); +/// +/// // Delegate `DataProvider` to the field `self.0`, calling `as_deserializing()` on the field +/// icu_provider_adapters::delegate::data_provider_to_field!(Wrap, HelloWorldV1, &self.0.as_deserializing()); +/// +/// // Test that it works +/// let wrap = Wrap(HelloWorldProvider::default().into_json_provider()); +/// HelloWorldFormatter::try_new_unstable(&wrap, locale!("de").into()).unwrap(); +/// ``` +/// +/// [`BufferProvider`]: icu_provider::prelude::BufferProvider +#[doc(hidden)] // macro +#[macro_export] +macro_rules! __data_provider_to_field { + ($provider:path, $marker:path, &self.$field:tt.as_deserializing()) => { + impl $crate::icu_provider::DataProvider<$marker> for $provider { + fn load(&self, req: $crate::icu_provider::DataRequest) -> Result<$crate::icu_provider::DataResponse<$marker>, $crate::icu_provider::DataError> { + let provider = $crate::icu_provider::prelude::AsDeserializingBufferProvider::as_deserializing(&self.$field); + $crate::icu_provider::DataProvider::<$marker>::load(&provider, req) + } + } + }; + ($provider:path, $marker:path, &self.$field:tt) => { + impl $crate::icu_provider::DataProvider<$marker> for $provider { + fn load(&self, req: $crate::icu_provider::DataRequest) -> Result<$crate::icu_provider::DataResponse<$marker>, $crate::icu_provider::DataError> { + $crate::icu_provider::DataProvider::<$marker>::load(&self.$field, req) + } + } + }; +} + +#[doc(inline)] +pub use __data_provider_to_field as data_provider_to_field; + +#[cfg(test)] +mod tests { + use icu_locale::locale; + use icu_provider::hello_world::{ + HelloWorldFormatter, HelloWorldJsonProvider, HelloWorldProvider, HelloWorldV1, + }; + + use super::*; + + #[test] + fn test_delegate() { + struct Wrap(HelloWorldProvider); + data_provider_to_field!(Wrap, HelloWorldV1, &self.0); + + let hello1 = HelloWorldProvider::default(); + let wrap = Wrap(hello1); + + let formatter = HelloWorldFormatter::try_new_unstable(&wrap, locale!("de").into()).unwrap(); + assert_eq!(formatter.format_to_string(), "Hallo Welt"); + } + + #[test] + fn test_delegate_to_buffer() { + struct Wrap(HelloWorldJsonProvider); + data_provider_to_field!(Wrap, HelloWorldV1, &self.0.as_deserializing()); + + let hello1 = HelloWorldProvider::default().into_json_provider(); + let wrap = Wrap(hello1); + + let formatter = HelloWorldFormatter::try_new_unstable(&wrap, locale!("de").into()).unwrap(); + assert_eq!(formatter.format_to_string(), "Hallo Welt"); + } +} diff --git a/provider/adapters/src/lib.rs b/provider/adapters/src/lib.rs index 2b172a5d733..d238009a3a9 100644 --- a/provider/adapters/src/lib.rs +++ b/provider/adapters/src/lib.rs @@ -28,9 +28,13 @@ extern crate alloc; +pub mod delegate; pub mod either; pub mod empty; pub mod fallback; pub mod filter; pub mod fixed; pub mod fork; + +#[doc(hidden)] // internal for macros +pub use icu_provider;