Skip to content

Commit

Permalink
Make DataPayload constructible from &'static M::Yokeable (#3467)
Browse files Browse the repository at this point in the history
  • Loading branch information
robertbastian committed Jun 7, 2023
1 parent b152800 commit a576f41
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 54 deletions.
24 changes: 12 additions & 12 deletions components/datetime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Gregorian>);
check_size_of!(1112 | 1024, TimeZoneFormatter);
check_size_of!(5752 | 4544, TypedDateFormatter::<Gregorian>);
check_size_of!(6744 | 5408, TypedDateTimeFormatter::<Gregorian>);

check_size_of!(80, DateTimeError);
Expand All @@ -224,19 +224,19 @@ mod tests {
type DP<M> = DataPayload<M>;
check_size_of!(208, DP::<PatternPluralsFromPatternsV1Marker>);
check_size_of!(1032 | 904, DP::<TimeSymbolsV1Marker>);
check_size_of!(32, DP::<GenericPatternV1Marker>);
check_size_of!(40, DP::<GenericPatternV1Marker>);
check_size_of!(208, DP::<PatternPluralsFromPatternsV1Marker>);
check_size_of!(5064 | 3904, DP::<ErasedDateSymbolsV1Marker>);
check_size_of!(16, DP::<WeekDataV1Marker>);
check_size_of!(288 | 224, DP::<TimeZoneFormatsV1Marker>);
check_size_of!(288 | 232, DP::<TimeZoneFormatsV1Marker>);
check_size_of!(64 | 56, DP::<ExemplarCitiesV1Marker>);
check_size_of!(120 | 104, DP::<MetazoneGenericNamesLongV1Marker>);
check_size_of!(120 | 104, DP::<MetazoneGenericNamesShortV1Marker>);
check_size_of!(216 | 200, DP::<MetazoneSpecificNamesLongV1Marker>);
check_size_of!(216 | 200, DP::<MetazoneSpecificNamesShortV1Marker>);
check_size_of!(120 | 112, DP::<MetazoneGenericNamesLongV1Marker>);
check_size_of!(120 | 112, DP::<MetazoneGenericNamesShortV1Marker>);
check_size_of!(216 | 208, DP::<MetazoneSpecificNamesLongV1Marker>);
check_size_of!(216 | 208, DP::<MetazoneSpecificNamesShortV1Marker>);
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);
}
}
11 changes: 5 additions & 6 deletions provider/core/src/datagen/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,17 @@ 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,
serializer: &mut dyn erased_serde::Serializer,
) -> Result<(), DataError>;
}

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,
{
fn bake_yoke(&self, ctx: &CrateEnv) -> TokenStream {
self.get().bake(ctx)
Expand All @@ -40,7 +39,7 @@ where
#[doc(hidden)] // exposed for make_exportable_provider
#[derive(yoke::Yokeable)]
pub struct ExportBox {
payload: Box<dyn ExportableYoke + Sync>,
payload: Box<dyn ExportableDataPayload + Sync>,
}

impl core::fmt::Debug for ExportBox {
Expand All @@ -59,7 +58,7 @@ where
{
fn upcast(other: DataPayload<M>) -> DataPayload<ExportMarker> {
DataPayload::from_owned(ExportBox {
payload: Box::new(other.yoke),
payload: Box::new(other),
})
}
}
Expand Down
109 changes: 75 additions & 34 deletions provider/core/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ pub struct DataResponseMetadata {
///
/// assert_eq!("Demo", payload.get().message);
/// ```
pub struct DataPayload<M>
where
M: DataMarker,
{
pub(crate) yoke: Yoke<M::Yokeable, Option<Cart>>,
pub struct DataPayload<M: DataMarker>(pub(crate) DataPayloadInner<M>);

pub(crate) enum DataPayloadInner<M: DataMarker> {
Yoke(Yoke<M::Yokeable, Option<Cart>>),
StaticRef(&'static M::Yokeable),
}

/// The type of the "cart" that is used by `DataPayload`.
Expand Down Expand Up @@ -136,9 +136,10 @@ where
for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::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),
})
}
}

Expand Down Expand Up @@ -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<M::Yokeable, DataError> {
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.
Expand Down Expand Up @@ -245,8 +252,15 @@ where
pub fn with_mut<'a, F>(&'a mut self, f: F)
where
F: 'static + for<'b> FnOnce(&'b mut <M::Yokeable as Yokeable<'a>>::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.
Expand All @@ -267,7 +281,10 @@ where
#[inline]
#[allow(clippy::needless_lifetimes)]
pub fn get<'a>(&'a self) -> &'a <M::Yokeable as Yokeable<'a>>::Output {
self.yoke.get()
match &self.0 {
DataPayloadInner::Yoke(yoke) => yoke.get(),
DataPayloadInner::StaticRef(r) => Yokeable::transform(*r),
}
}

/// Maps `DataPayload<M>` to `DataPayload<M2>` by projecting it with [`Yoke::map_project`].
Expand Down Expand Up @@ -319,10 +336,15 @@ where
<M::Yokeable as Yokeable<'a>>::Output,
PhantomData<&'a ()>,
) -> <M2::Yokeable as Yokeable<'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`.
Expand Down Expand Up @@ -363,9 +385,16 @@ where
PhantomData<&'a ()>,
) -> <M2::Yokeable as Yokeable<'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: <M2::Yokeable as Yokeable<'static>>::Output =
f(Yokeable::transform(*r), PhantomData);
// Safety: <M2::Yokeable as Yokeable<'static>>::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`.
Expand Down Expand Up @@ -412,10 +441,15 @@ where
<M::Yokeable as Yokeable<'a>>::Output,
PhantomData<&'a ()>,
) -> Result<<M2::Yokeable as Yokeable<'a>>::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`.
Expand Down Expand Up @@ -466,9 +500,15 @@ where
PhantomData<&'a ()>,
) -> Result<<M2::Yokeable as Yokeable<'a>>::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: <M2::Yokeable as Yokeable<'static>>::Output =
f(Yokeable::transform(*r), PhantomData)?;
// Safety: <M2::Yokeable as Yokeable<'static>>::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.
Expand Down Expand Up @@ -498,7 +538,10 @@ where
where
M2: DataMarker<Yokeable = M::Yokeable>,
{
DataPayload { yoke: self.yoke }
DataPayload(match self.0 {
DataPayloadInner::Yoke(yoke) => DataPayloadInner::Yoke(yoke),
DataPayloadInner::StaticRef(r) => DataPayloadInner::StaticRef(r),
})
}
}

Expand All @@ -508,19 +551,17 @@ impl DataPayload<BufferMarker> {
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<BufferMarker>`.
pub fn from_yoked_buffer(yoke: Yoke<&'static [u8], Option<Cart>>) -> Self {
Self { yoke }
Self(DataPayloadInner::Yoke(yoke))
}

/// Converts a static byte buffer into a `DataPayload<BufferMarker>`.
pub fn from_static_buffer(buffer: &'static [u8]) -> Self {
Self {
yoke: Yoke::new_owned(buffer),
}
Self(DataPayloadInner::Yoke(Yoke::new_owned(buffer)))
}
}

Expand Down
4 changes: 2 additions & 2 deletions utils/zerofrom/src/zero_from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down

0 comments on commit a576f41

Please sign in to comment.