Simplify the type bounds on PrimitiveMut via type erasure PiperOrigin-RevId: 591046477
diff --git a/rust/primitive.rs b/rust/primitive.rs index 539ddf2..ea74218 100644 --- a/rust/primitive.rs +++ b/rust/primitive.rs
@@ -15,17 +15,20 @@ /// A mutator for a primitive (numeric or enum) value of `T`. /// /// This type is `protobuf::Mut<'msg, T>`. -pub struct PrimitiveMut<'msg, T: ProxiedWithRawVTable> { +pub struct PrimitiveMut<'msg, T> { inner: InnerPrimitiveMut<'msg, T>, } -impl<'msg, T: ProxiedWithRawVTable> Debug for PrimitiveMut<'msg, T> { +impl<'msg, T> Debug for PrimitiveMut<'msg, T> +where + T: PrimitiveWithRawVTable, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("PrimitiveMut").field("inner", &self.inner).finish() } } -impl<'msg, T: ProxiedWithRawVTable> PrimitiveMut<'msg, T> { +impl<'msg, T> PrimitiveMut<'msg, T> { /// # Safety /// `inner` must be valid and non-aliased for `T` for `'msg` #[doc(hidden)] @@ -34,7 +37,7 @@ } } -unsafe impl<'msg, T: ProxiedWithRawVTable> Sync for PrimitiveMut<'msg, T> {} +unsafe impl<'msg, T> Sync for PrimitiveMut<'msg, T> {} impl<'msg, T> PrimitiveMut<'msg, T> where
diff --git a/rust/vtable.rs b/rust/vtable.rs index f0128db..2691125 100644 --- a/rust/vtable.rs +++ b/rust/vtable.rs
@@ -14,6 +14,8 @@ ProxiedWithPresence, View, ViewProxy, }; use std::fmt::{self, Debug}; +use std::marker::PhantomData; +use std::ptr::NonNull; /// A proxied type that can use a vtable to provide get/set access for a /// present field. @@ -67,7 +69,8 @@ AbsentMutData<'msg> = RawVTableOptionalMutatorData<'msg, T>, >, { - let data = RawVTableOptionalMutatorData { msg_ref, vtable: optional_vtable }; + // SAFETY: safe as promised by the caller of the function + let data = unsafe { RawVTableOptionalMutatorData::new(Private, msg_ref, optional_vtable) }; if is_set { Optional::Set(PresentField::from_inner(Private, data)) } else { @@ -89,26 +92,29 @@ /// /// [`RawVTableOptionalMutatorData`] is similar, but also includes the /// capability to has/clear. -pub struct RawVTableMutator<'msg, T: ProxiedWithRawVTable + ?Sized> { +pub struct RawVTableMutator<'msg, T: ?Sized> { msg_ref: MutatorMessageRef<'msg>, - vtable: &'static T::VTable, + /// Stores `&'static <T as ProxiedWithRawVTable>::Vtable` + /// as a type-erased pointer to avoid a bound on the struct. + vtable: NonNull<()>, + _phantom: PhantomData<&'msg T>, } // These use manual impls instead of derives to avoid unnecessary bounds on `T`. // This problem is referred to as "perfect derive". // https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/ -impl<'msg, T: ProxiedWithRawVTable + ?Sized> Clone for RawVTableMutator<'msg, T> { +impl<'msg, T: ?Sized> Clone for RawVTableMutator<'msg, T> { fn clone(&self) -> Self { *self } } -impl<'msg, T: ProxiedWithRawVTable + ?Sized> Copy for RawVTableMutator<'msg, T> {} +impl<'msg, T: ?Sized> Copy for RawVTableMutator<'msg, T> {} impl<'msg, T: ProxiedWithRawVTable + ?Sized> Debug for RawVTableMutator<'msg, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawVTableMutator") .field("msg_ref", &self.msg_ref) - .field("vtable", &self.vtable) + .field("vtable", self.vtable()) .finish() } } @@ -125,7 +131,12 @@ msg_ref: MutatorMessageRef<'msg>, vtable: &'static T::VTable, ) -> Self { - RawVTableMutator { msg_ref, vtable } + RawVTableMutator { msg_ref, vtable: NonNull::from(vtable).cast(), _phantom: PhantomData } + } + + fn vtable(self) -> &'static T::VTable { + // SAFETY: This was cast from `&'static T::VTable`. + unsafe { self.vtable.cast().as_ref() } } } @@ -138,30 +149,27 @@ /// /// This has the same representation for "present" and "absent" data; /// differences like default values are obviated by the vtable. -pub struct RawVTableOptionalMutatorData<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> { +pub struct RawVTableOptionalMutatorData<'msg, T: ?Sized> { msg_ref: MutatorMessageRef<'msg>, - vtable: &'static T::OptionalVTable, + /// Stores `&'static <T as ProxiedWithRawOptionalVTable>::Vtable` + /// as a type-erased pointer to avoid a bound on the struct. + optional_vtable: NonNull<()>, + _phantom: PhantomData<&'msg T>, } -unsafe impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> Sync - for RawVTableOptionalMutatorData<'msg, T> -{ -} +// SAFETY: all `T` that can perform mutations don't mutate through a shared +// reference. +unsafe impl<'msg, T: ?Sized> Sync for RawVTableOptionalMutatorData<'msg, T> {} // These use manual impls instead of derives to avoid unnecessary bounds on `T`. // This problem is referred to as "perfect derive". // https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/ -impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> Clone - for RawVTableOptionalMutatorData<'msg, T> -{ +impl<'msg, T: ?Sized> Clone for RawVTableOptionalMutatorData<'msg, T> { fn clone(&self) -> Self { *self } } -impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> Copy - for RawVTableOptionalMutatorData<'msg, T> -{ -} +impl<'msg, T: ?Sized> Copy for RawVTableOptionalMutatorData<'msg, T> {} impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> Debug for RawVTableOptionalMutatorData<'msg, T> @@ -169,7 +177,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawVTableOptionalMutatorData") .field("msg_ref", &self.msg_ref) - .field("vtable", &self.vtable) + .field("vtable", self.optional_vtable()) .finish() } } @@ -186,11 +194,23 @@ msg_ref: MutatorMessageRef<'msg>, vtable: &'static T::OptionalVTable, ) -> Self { - Self { msg_ref, vtable } + Self { msg_ref, optional_vtable: NonNull::from(vtable).cast(), _phantom: PhantomData } + } + + fn optional_vtable(self) -> &'static T::OptionalVTable { + // SAFETY: This was cast from `&'static T::OptionalVTable` in `new`. + unsafe { self.optional_vtable.cast().as_ref() } } fn into_raw_mut(self) -> RawVTableMutator<'msg, T> { - RawVTableMutator { msg_ref: self.msg_ref, vtable: T::upcast_vtable(Private, self.vtable) } + // SAFETY: the safety requirements have been met by the caller of `new`. + unsafe { + RawVTableMutator::new( + Private, + self.msg_ref, + T::upcast_vtable(Private, self.optional_vtable()), + ) + } } } @@ -342,7 +362,7 @@ // - `msg_ref` is valid for `'msg` as promised by the caller of `new`. // - The caller of `BytesMutVTable` promised that the returned `PtrAndLen` is // valid for `'msg`. - unsafe { (self.vtable.getter)(self.msg_ref.msg()).as_ref() } + unsafe { (self.vtable().getter)(self.msg_ref.msg()).as_ref() } } /// # Safety @@ -353,7 +373,7 @@ let val = copy_bytes_in_arena_if_needed_by_runtime(self.msg_ref, val); // SAFETY: // - `msg_ref` is valid for `'msg` as promised by the caller of `new`. - unsafe { (self.vtable.setter)(self.msg_ref.msg(), val.into()) } + unsafe { (self.vtable().setter)(self.msg_ref.msg(), val.into()) } } pub(crate) fn truncate(&self, len: usize) { @@ -373,7 +393,7 @@ pub(crate) fn set_absent_to_default(self) -> Self { // SAFETY: The default value is UTF-8 if required by the // runtime as promised by the caller of `BytesOptionalMutVTable::new`. - unsafe { self.set(self.vtable.default) } + unsafe { self.set(self.optional_vtable().default) } } /// # Safety @@ -383,7 +403,7 @@ let val = copy_bytes_in_arena_if_needed_by_runtime(self.msg_ref, val); // SAFETY: // - `msg_ref` is valid for `'msg` as promised by the caller. - unsafe { (self.vtable.base.setter)(self.msg_ref.msg(), val.into()) } + unsafe { (self.optional_vtable().base.setter)(self.msg_ref.msg(), val.into()) } self } @@ -392,7 +412,7 @@ // - `msg_ref` is valid for `'msg` as promised by the caller. // - The caller of `new` promised that the returned `PtrAndLen` is valid for // `'msg`. - unsafe { (self.vtable.clearer)(self.msg_ref.msg()) } + unsafe { (self.optional_vtable().clearer)(self.msg_ref.msg()) } self } } @@ -446,7 +466,7 @@ // SAFETY: // - `msg_ref` is valid for the lifetime of `RawVTableMutator` as promised by // the caller of `new`. - unsafe { (self.vtable.getter)(self.msg_ref.msg()) } + unsafe { (self.vtable().getter)(self.msg_ref.msg()) } } /// # Safety @@ -455,7 +475,7 @@ // SAFETY: // - `msg_ref` is valid for the lifetime of `RawVTableMutator` as promised by // the caller of `new`. - unsafe { (self.vtable.setter)(self.msg_ref.msg(), val) } + unsafe { (self.vtable().setter)(self.msg_ref.msg(), val) } } } @@ -464,14 +484,14 @@ // SAFETY: // - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as // promised by the caller of `new`. - self.set(self.vtable.default) + self.set(self.optional_vtable().default) } pub(crate) fn set(self, val: T) -> Self { // SAFETY: // - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as // promised by the caller of `new`. - unsafe { (self.vtable.base.setter)(self.msg_ref.msg(), val) } + unsafe { (self.optional_vtable().base.setter)(self.msg_ref.msg(), val) } self } @@ -479,7 +499,7 @@ // SAFETY: // - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as // promised by the caller of `new`. - unsafe { (self.vtable.clearer)(self.msg_ref.msg()) } + unsafe { (self.optional_vtable().clearer)(self.msg_ref.msg()) } self } }