// 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 ExportableYoke for Yoke where Y: for<'a> Yokeable<'a>, for<'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, } impl UpcastDataPayload for ExportMarker where M: DataMarker, M::Yokeable: Sync, for<'a> >::Output: Bake + serde::Serialize, { fn upcast(other: DataPayload) -> DataPayload { DataPayload::from_owned(ExportBox { payload: Box::new(other.yoke), }) } } impl DataPayload { /// 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 = Default::default(); /// let export: DataPayload = UpcastDataPayload::upcast(payload); /// /// // Serialize the payload to a JSON string /// let mut buffer: Vec = 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(&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 ::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 = Default::default(); /// let export: DataPayload = 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::>(), /// ["icu_provider", "alloc"] /// .into_iter() /// .collect::>() /// ); /// ``` 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; }