diff --git a/components/datetime/src/lib.rs b/components/datetime/src/lib.rs index 9946291ca94..e98b2dad3f1 100644 --- a/components/datetime/src/lib.rs +++ b/components/datetime/src/lib.rs @@ -207,12 +207,12 @@ mod tests { #[test] fn check_sizes() { - check_size_of!(5784 | 4576, DateFormatter); - check_size_of!(6784 | 5448, DateTimeFormatter); - check_size_of!(7896 | 6464, ZonedDateTimeFormatter); + check_size_of!(5800 | 4592, DateFormatter); + check_size_of!(6792 | 5456, DateTimeFormatter); + check_size_of!(7904 | 6480, ZonedDateTimeFormatter); check_size_of!(1496 | 1320, TimeFormatter); - check_size_of!(1112 | 1016, TimeZoneFormatter); - check_size_of!(5744 | 4536, TypedDateFormatter::); + check_size_of!(1112 | 1024, TimeZoneFormatter); + check_size_of!(5752 | 4544, TypedDateFormatter::); check_size_of!(6744 | 5408, TypedDateTimeFormatter::); check_size_of!(80, DateTimeError); @@ -224,19 +224,19 @@ mod tests { type DP = DataPayload; check_size_of!(208, DP::); check_size_of!(1032 | 904, DP::); - check_size_of!(32, DP::); + check_size_of!(40, DP::); check_size_of!(208, DP::); check_size_of!(5064 | 3904, DP::); check_size_of!(16, DP::); - check_size_of!(288 | 224, DP::); + check_size_of!(288 | 232, DP::); check_size_of!(64 | 56, DP::); - check_size_of!(120 | 104, DP::); - check_size_of!(120 | 104, DP::); - check_size_of!(216 | 200, DP::); - check_size_of!(216 | 200, DP::); + check_size_of!(120 | 112, DP::); + check_size_of!(120 | 112, DP::); + check_size_of!(216 | 208, DP::); + check_size_of!(216 | 208, DP::); check_size_of!(168, PluralRules); check_size_of!(256 | 208, FixedDecimalFormatter); - check_size_of!(1024 | 928, TimeZoneDataPayloads); + check_size_of!(1024 | 936, TimeZoneDataPayloads); check_size_of!(3, TimeZoneFormatterUnit); } } diff --git a/provider/core/src/datagen/payload.rs b/provider/core/src/datagen/payload.rs index 665760d82ce..d9e3012434e 100644 --- a/provider/core/src/datagen/payload.rs +++ b/provider/core/src/datagen/payload.rs @@ -8,7 +8,7 @@ use alloc::boxed::Box; use databake::{Bake, CrateEnv, TokenStream}; use yoke::*; -trait ExportableYoke { +trait ExportableDataPayload { fn bake_yoke(&self, env: &CrateEnv) -> TokenStream; fn serialize_yoke( &self, @@ -16,10 +16,9 @@ trait ExportableYoke { ) -> Result<(), DataError>; } -impl ExportableYoke for Yoke +impl ExportableDataPayload for DataPayload where - Y: for<'a> Yokeable<'a>, - for<'a> >::Output: Bake + serde::Serialize, + for<'a> >::Output: Bake + serde::Serialize, { fn bake_yoke(&self, ctx: &CrateEnv) -> TokenStream { self.get().bake(ctx) @@ -40,7 +39,7 @@ where #[doc(hidden)] // exposed for make_exportable_provider #[derive(yoke::Yokeable)] pub struct ExportBox { - payload: Box, + payload: Box, } impl core::fmt::Debug for ExportBox { @@ -59,7 +58,7 @@ where { fn upcast(other: DataPayload) -> DataPayload { DataPayload::from_owned(ExportBox { - payload: Box::new(other.yoke), + payload: Box::new(other), }) } } diff --git a/provider/core/src/response.rs b/provider/core/src/response.rs index 1acad513a5f..4e0b103fc46 100644 --- a/provider/core/src/response.rs +++ b/provider/core/src/response.rs @@ -71,11 +71,11 @@ pub struct DataResponseMetadata { /// /// assert_eq!("Demo", payload.get().message); /// ``` -pub struct DataPayload -where - M: DataMarker, -{ - pub(crate) yoke: Yoke>, +pub struct DataPayload(pub(crate) DataPayloadInner); + +pub(crate) enum DataPayloadInner { + Yoke(Yoke>), + StaticRef(&'static M::Yokeable), } /// The type of the "cart" that is used by `DataPayload`. @@ -136,9 +136,10 @@ where for<'a> YokeTraitHack<>::Output>: Clone, { fn clone(&self) -> Self { - Self { - yoke: self.yoke.clone(), - } + Self(match &self.0 { + DataPayloadInner::Yoke(yoke) => DataPayloadInner::Yoke(yoke.clone()), + DataPayloadInner::StaticRef(r) => DataPayloadInner::StaticRef(*r), + }) } } @@ -194,17 +195,23 @@ where /// ``` #[inline] pub fn from_owned(data: M::Yokeable) -> Self { - Self { - yoke: Yoke::new_owned(data), - } + Self(DataPayloadInner::Yoke(Yoke::new_owned(data))) + } + + #[doc(hidden)] + #[inline] + pub const fn from_static_ref(data: &'static M::Yokeable) -> Self { + Self(DataPayloadInner::StaticRef(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 { - self.yoke - .try_into_yokeable() - .map_err(|_| DataErrorKind::InvalidState.with_str_context("try_unwrap_owned")) + match self.0 { + DataPayloadInner::Yoke(yoke) => yoke.try_into_yokeable().ok(), + DataPayloadInner::StaticRef(_) => None, + } + .ok_or(DataErrorKind::InvalidState.with_str_context("try_unwrap_owned")) } /// Mutate the data contained in this DataPayload. @@ -245,8 +252,15 @@ where pub fn with_mut<'a, F>(&'a mut self, f: F) where F: 'static + for<'b> FnOnce(&'b mut >::Output), + M::Yokeable: zerofrom::ZeroFrom<'static, M::Yokeable>, { - self.yoke.with_mut(f) + if let DataPayloadInner::StaticRef(r) = self.0 { + self.0 = DataPayloadInner::Yoke(Yoke::new_owned(zerofrom::ZeroFrom::zero_from(r))); + } + match &mut self.0 { + DataPayloadInner::Yoke(yoke) => yoke.with_mut(f), + _ => unreachable!(), + } } /// Borrows the underlying data. @@ -267,7 +281,10 @@ where #[inline] #[allow(clippy::needless_lifetimes)] pub fn get<'a>(&'a self) -> &'a >::Output { - self.yoke.get() + match &self.0 { + DataPayloadInner::Yoke(yoke) => yoke.get(), + DataPayloadInner::StaticRef(r) => Yokeable::transform(*r), + } } /// Maps `DataPayload` to `DataPayload` by projecting it with [`Yoke::map_project`]. @@ -319,10 +336,15 @@ where >::Output, PhantomData<&'a ()>, ) -> >::Output, + M::Yokeable: zerofrom::ZeroFrom<'static, M::Yokeable>, { - DataPayload { - yoke: self.yoke.map_project(f), - } + DataPayload(DataPayloadInner::Yoke( + match self.0 { + DataPayloadInner::Yoke(yoke) => yoke, + DataPayloadInner::StaticRef(r) => Yoke::new_owned(zerofrom::ZeroFrom::zero_from(r)), + } + .map_project(f), + )) } /// Version of [`DataPayload::map_project()`] that borrows `self` instead of moving `self`. @@ -363,9 +385,16 @@ where PhantomData<&'a ()>, ) -> >::Output, { - DataPayload { - yoke: self.yoke.map_project_cloned(f), - } + DataPayload(DataPayloadInner::Yoke(match &self.0 { + DataPayloadInner::Yoke(yoke) => yoke.map_project_cloned(f), + DataPayloadInner::StaticRef(r) => { + let output: >::Output = + f(Yokeable::transform(*r), PhantomData); + // Safety: >::Output is the same type as M2::Yokeable + let yokeable: M2::Yokeable = unsafe { M2::Yokeable::make(output) }; + Yoke::new_owned(yokeable) + } + })) } /// Version of [`DataPayload::map_project()`] that bubbles up an error from `f`. @@ -412,10 +441,15 @@ where >::Output, PhantomData<&'a ()>, ) -> Result<>::Output, E>, + M::Yokeable: zerofrom::ZeroFrom<'static, M::Yokeable>, { - Ok(DataPayload { - yoke: self.yoke.try_map_project(f)?, - }) + Ok(DataPayload(DataPayloadInner::Yoke( + match self.0 { + DataPayloadInner::Yoke(yoke) => yoke, + DataPayloadInner::StaticRef(r) => Yoke::new_owned(zerofrom::ZeroFrom::zero_from(r)), + } + .try_map_project(f)?, + ))) } /// Version of [`DataPayload::map_project_cloned()`] that bubbles up an error from `f`. @@ -466,9 +500,15 @@ where PhantomData<&'a ()>, ) -> Result<>::Output, E>, { - Ok(DataPayload { - yoke: self.yoke.try_map_project_cloned(f)?, - }) + Ok(DataPayload(DataPayloadInner::Yoke(match &self.0 { + DataPayloadInner::Yoke(yoke) => yoke.try_map_project_cloned(f)?, + DataPayloadInner::StaticRef(r) => { + let output: >::Output = + f(Yokeable::transform(*r), PhantomData)?; + // Safety: >::Output is the same type as M2::Yokeable + Yoke::new_owned(unsafe { M2::Yokeable::make(output) }) + } + }))) } /// Convert between two [`DataMarker`] types that are compatible with each other. @@ -498,7 +538,10 @@ where where M2: DataMarker, { - DataPayload { yoke: self.yoke } + DataPayload(match self.0 { + DataPayloadInner::Yoke(yoke) => DataPayloadInner::Yoke(yoke), + DataPayloadInner::StaticRef(r) => DataPayloadInner::StaticRef(r), + }) } } @@ -508,19 +551,17 @@ impl DataPayload { 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 } + Self(DataPayloadInner::Yoke(yoke)) } /// Converts a yoked byte buffer into a `DataPayload`. pub fn from_yoked_buffer(yoke: Yoke<&'static [u8], Option>) -> Self { - Self { yoke } + Self(DataPayloadInner::Yoke(yoke)) } /// Converts a static byte buffer into a `DataPayload`. pub fn from_static_buffer(buffer: &'static [u8]) -> Self { - Self { - yoke: Yoke::new_owned(buffer), - } + Self(DataPayloadInner::Yoke(Yoke::new_owned(buffer))) } } diff --git a/utils/zerofrom/src/zero_from.rs b/utils/zerofrom/src/zero_from.rs index 5b89ea5fb3e..204b3b635cd 100644 --- a/utils/zerofrom/src/zero_from.rs +++ b/utils/zerofrom/src/zero_from.rs @@ -113,9 +113,9 @@ impl<'zf, B: ToOwned + ?Sized> ZeroFrom<'zf, Cow<'_, B>> for Cow<'zf, B> { } } -impl<'zf> ZeroFrom<'zf, &'_ str> for &'zf str { +impl<'zf, T: ?Sized> ZeroFrom<'zf, &'_ T> for &'zf T { #[inline] - fn zero_from(other: &'zf &'_ str) -> &'zf str { + fn zero_from(other: &'zf &'_ T) -> &'zf T { other } }