|
|
|
// Protocol Buffers - Google's data interchange format
|
|
|
|
// Copyright 2023 Google LLC. All rights reserved.
|
|
|
|
//
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file or at
|
|
|
|
// https://developers.google.com/open-source/licenses/bsd
|
|
|
|
|
|
|
|
use crate::__internal::{Private, PtrAndLen, RawMessage};
|
|
|
|
use crate::__runtime::{
|
|
|
|
copy_bytes_in_arena_if_needed_by_runtime, InnerPrimitiveMut, MutatorMessageRef,
|
|
|
|
};
|
|
|
|
use crate::{
|
|
|
|
AbsentField, FieldEntry, Mut, MutProxy, Optional, PresentField, PrimitiveMut, Proxied,
|
|
|
|
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.
|
|
|
|
///
|
|
|
|
/// This vtable should consist of `unsafe fn`s that call thunks that operate on
|
|
|
|
/// `RawMessage`. The structure of this vtable is different per proxied type.
|
|
|
|
pub trait ProxiedWithRawVTable: Proxied {
|
|
|
|
/// The vtable for get/set access, stored in static memory.
|
|
|
|
type VTable: Debug + 'static;
|
|
|
|
|
|
|
|
fn make_view(_private: Private, mut_inner: RawVTableMutator<'_, Self>) -> View<'_, Self>;
|
|
|
|
fn make_mut(_private: Private, inner: RawVTableMutator<'_, Self>) -> Mut<'_, Self>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A proxied type that can use a vtable to provide get/set/clear access for
|
|
|
|
/// an optional field.
|
|
|
|
///
|
|
|
|
/// This vtable should consist of `unsafe fn`s that call thunks that operate on
|
|
|
|
/// `RawMessage`. The structure of this vtable is different per-proxied type.
|
|
|
|
pub trait ProxiedWithRawOptionalVTable: ProxiedWithRawVTable + ProxiedWithPresence {
|
|
|
|
/// The vtable for get/set/clear, must contain `Self::VTable`.
|
|
|
|
type OptionalVTable: Debug + 'static;
|
|
|
|
|
|
|
|
/// Cast from a static reference of `OptionalVTable` to `VTable`.
|
|
|
|
/// This should mean `OptionalVTable` contains a `VTable`.
|
|
|
|
fn upcast_vtable(
|
|
|
|
_private: Private,
|
|
|
|
optional_vtable: &'static Self::OptionalVTable,
|
|
|
|
) -> &'static Self::VTable;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs a new field entry from a raw message, a vtable for manipulation,
|
|
|
|
/// and an eager check for whether the value is present or not.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
/// - `msg_ref` must be valid to provide as an argument for `vtable`'s methods
|
|
|
|
/// for `'msg`.
|
|
|
|
/// - If given `msg_ref` as an argument, any values returned by `vtable` methods
|
|
|
|
/// must be valid for `'msg`.
|
|
|
|
/// - Operations on the vtable must be thread-compatible.
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub unsafe fn new_vtable_field_entry<'msg, T: ProxiedWithRawOptionalVTable + ?Sized>(
|
|
|
|
_private: Private,
|
|
|
|
msg_ref: MutatorMessageRef<'msg>,
|
|
|
|
optional_vtable: &'static T::OptionalVTable,
|
|
|
|
is_set: bool,
|
|
|
|
) -> FieldEntry<'msg, T>
|
|
|
|
where
|
|
|
|
T: ProxiedWithPresence<
|
|
|
|
PresentMutData<'msg> = RawVTableOptionalMutatorData<'msg, T>,
|
|
|
|
AbsentMutData<'msg> = RawVTableOptionalMutatorData<'msg, T>,
|
|
|
|
>,
|
|
|
|
{
|
|
|
|
// 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 {
|
|
|
|
Optional::Unset(AbsentField::from_inner(Private, data))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The internal implementation type for a vtable-based `protobuf::Mut<T>`.
|
|
|
|
///
|
|
|
|
/// This stores the two components necessary to mutate the field:
|
|
|
|
/// borrowed message data and a vtable reference.
|
|
|
|
///
|
|
|
|
/// The borrowed message data varies per runtime: C++ needs a message pointer,
|
|
|
|
/// while UPB needs a message pointer and an `&Arena`.
|
|
|
|
///
|
|
|
|
/// Implementations of `ProxiedWithRawVTable` implement get/set
|
|
|
|
/// on top of `RawVTableMutator<T>`, and the top-level mutator (e.g.
|
|
|
|
/// `BytesMut`) calls these methods.
|
|
|
|
///
|
|
|
|
/// [`RawVTableOptionalMutatorData`] is similar, but also includes the
|
|
|
|
/// capability to has/clear.
|
|
|
|
pub struct RawVTableMutator<'msg, T: ?Sized> {
|
|
|
|
msg_ref: MutatorMessageRef<'msg>,
|
|
|
|
/// 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: ?Sized> Clone for RawVTableMutator<'msg, T> {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
*self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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())
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'msg, T: ProxiedWithRawVTable + ?Sized> RawVTableMutator<'msg, T> {
|
|
|
|
/// # Safety
|
|
|
|
/// - `msg_ref` must be valid to provide as an argument for `vtable`'s
|
|
|
|
/// methods for `'msg`.
|
|
|
|
/// - If given `msg_ref` as an argument, any values returned by `vtable`
|
|
|
|
/// methods must be valid for `'msg`.
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub unsafe fn new(
|
|
|
|
_private: Private,
|
|
|
|
msg_ref: MutatorMessageRef<'msg>,
|
|
|
|
vtable: &'static T::VTable,
|
|
|
|
) -> Self {
|
|
|
|
RawVTableMutator { msg_ref, vtable: NonNull::from(vtable).cast(), _phantom: PhantomData }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn vtable(self) -> &'static T::VTable {
|
|
|
|
// SAFETY: This was cast from `&'static T::VTable`.
|
|
|
|
unsafe { self.vtable.cast().as_ref() }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn msg_ref(self) -> MutatorMessageRef<'msg> {
|
|
|
|
self.msg_ref
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// [`RawVTableMutator`], but also includes has/clear.
|
|
|
|
///
|
|
|
|
/// This is used as the `PresentData` and `AbsentData` for `impl
|
|
|
|
/// ProxiedWithPresence for T`. In that implementation, `clear_present_field`
|
|
|
|
/// and `set_absent_to_default` will use methods implemented on
|
|
|
|
/// `RawVTableOptionalMutatorData<T>` to do the setting and clearing.
|
|
|
|
///
|
|
|
|
/// This has the same representation for "present" and "absent" data;
|
|
|
|
/// differences like default values are obviated by the vtable.
|
|
|
|
pub struct RawVTableOptionalMutatorData<'msg, T: ?Sized> {
|
|
|
|
msg_ref: MutatorMessageRef<'msg>,
|
|
|
|
/// 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>,
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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: ?Sized> Clone for RawVTableOptionalMutatorData<'msg, T> {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
*self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl<'msg, T: ?Sized> Copy for RawVTableOptionalMutatorData<'msg, T> {}
|
|
|
|
|
|
|
|
impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> Debug
|
|
|
|
for RawVTableOptionalMutatorData<'msg, T>
|
|
|
|
{
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.debug_struct("RawVTableOptionalMutatorData")
|
|
|
|
.field("msg_ref", &self.msg_ref)
|
|
|
|
.field("vtable", self.optional_vtable())
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> RawVTableOptionalMutatorData<'msg, T> {
|
|
|
|
/// # Safety
|
|
|
|
/// - `msg_ref` must be valid to provide as an argument for `vtable`'s
|
|
|
|
/// methods for `'msg`.
|
|
|
|
/// - If given `msg_ref` as an argument, any values returned by `vtable`
|
|
|
|
/// methods must be valid for `'msg`.
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub unsafe fn new(
|
|
|
|
_private: Private,
|
|
|
|
msg_ref: MutatorMessageRef<'msg>,
|
|
|
|
vtable: &'static T::OptionalVTable,
|
|
|
|
) -> Self {
|
|
|
|
Self { msg_ref, optional_vtable: NonNull::from(vtable).cast(), _phantom: PhantomData }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn msg_ref(self) -> MutatorMessageRef<'msg> {
|
|
|
|
self.msg_ref
|
|
|
|
}
|
|
|
|
|
|
|
|
pub 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> {
|
|
|
|
// 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()),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized + 'msg> ViewProxy<'msg>
|
|
|
|
for RawVTableOptionalMutatorData<'msg, T>
|
|
|
|
{
|
|
|
|
type Proxied = T;
|
|
|
|
|
|
|
|
fn as_view(&self) -> View<'_, T> {
|
|
|
|
T::make_view(Private, self.into_raw_mut())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn into_view<'shorter>(self) -> View<'shorter, T>
|
|
|
|
where
|
|
|
|
'msg: 'shorter,
|
|
|
|
{
|
|
|
|
T::make_view(Private, self.into_raw_mut())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: though this raw value implements `MutProxy`, the `as_mut` is only valid
|
|
|
|
// when the field is known to be present. `FieldEntry` enforces this in its
|
|
|
|
// design: `AbsentField { inner: RawVTableOptionalMutatorData<T> }` does not
|
|
|
|
// implement `MutProxy`.
|
|
|
|
impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized + 'msg> MutProxy<'msg>
|
|
|
|
for RawVTableOptionalMutatorData<'msg, T>
|
|
|
|
{
|
|
|
|
fn as_mut(&mut self) -> Mut<'_, T> {
|
|
|
|
T::make_mut(Private, self.into_raw_mut())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn into_mut<'shorter>(self) -> Mut<'shorter, T>
|
|
|
|
where
|
|
|
|
'msg: 'shorter,
|
|
|
|
{
|
|
|
|
T::make_mut(Private, self.into_raw_mut())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ProxiedWithRawVTable for [u8] {
|
|
|
|
type VTable = BytesMutVTable;
|
|
|
|
|
|
|
|
fn make_view(_private: Private, mut_inner: RawVTableMutator<'_, Self>) -> View<'_, Self> {
|
|
|
|
mut_inner.get()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn make_mut(_private: Private, inner: RawVTableMutator<'_, Self>) -> Mut<'_, Self> {
|
|
|
|
crate::string::BytesMut::from_inner(Private, inner)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ProxiedWithRawOptionalVTable for [u8] {
|
|
|
|
type OptionalVTable = BytesOptionalMutVTable;
|
|
|
|
fn upcast_vtable(
|
|
|
|
_private: Private,
|
|
|
|
optional_vtable: &'static Self::OptionalVTable,
|
|
|
|
) -> &'static Self::VTable {
|
|
|
|
&optional_vtable.base
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A generic thunk vtable for mutating a present primitive field.
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PrimitiveVTable<T> {
|
|
|
|
pub(crate) setter: unsafe extern "C" fn(msg: RawMessage, val: T),
|
|
|
|
pub(crate) getter: unsafe extern "C" fn(msg: RawMessage) -> T,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
/// A generic thunk vtable for mutating an `optional` primitive field.
|
|
|
|
pub struct PrimitiveOptionalMutVTable<T> {
|
|
|
|
pub(crate) base: PrimitiveVTable<T>,
|
|
|
|
pub(crate) clearer: unsafe extern "C" fn(msg: RawMessage),
|
|
|
|
pub(crate) default: T,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> PrimitiveVTable<T> {
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub const fn new(
|
|
|
|
_private: Private,
|
|
|
|
getter: unsafe extern "C" fn(msg: RawMessage) -> T,
|
|
|
|
setter: unsafe extern "C" fn(msg: RawMessage, val: T),
|
|
|
|
) -> Self {
|
|
|
|
Self { getter, setter }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> PrimitiveOptionalMutVTable<T> {
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub const fn new(
|
|
|
|
_private: Private,
|
|
|
|
getter: unsafe extern "C" fn(msg: RawMessage) -> T,
|
|
|
|
setter: unsafe extern "C" fn(msg: RawMessage, val: T),
|
|
|
|
clearer: unsafe extern "C" fn(msg: RawMessage),
|
|
|
|
default: T,
|
|
|
|
) -> Self {
|
|
|
|
Self { base: PrimitiveVTable { getter, setter }, clearer, default }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A generic thunk vtable for mutating a present `bytes` or `string` field.
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct BytesMutVTable {
|
|
|
|
pub(crate) setter: unsafe extern "C" fn(msg: RawMessage, val: PtrAndLen),
|
|
|
|
pub(crate) getter: unsafe extern "C" fn(msg: RawMessage) -> PtrAndLen,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A generic thunk vtable for mutating an `optional` `bytes` or `string` field.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct BytesOptionalMutVTable {
|
|
|
|
pub(crate) base: BytesMutVTable,
|
|
|
|
pub(crate) clearer: unsafe extern "C" fn(msg: RawMessage),
|
|
|
|
pub(crate) default: &'static [u8],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BytesMutVTable {
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub const fn new(
|
|
|
|
_private: Private,
|
|
|
|
getter: unsafe extern "C" fn(msg: RawMessage) -> PtrAndLen,
|
|
|
|
setter: unsafe extern "C" fn(msg: RawMessage, val: PtrAndLen),
|
|
|
|
) -> Self {
|
|
|
|
Self { getter, setter }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BytesOptionalMutVTable {
|
|
|
|
/// # Safety
|
|
|
|
/// The `default` value must be UTF-8 if required by
|
|
|
|
/// the runtime and this is for a `string` field.
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub const unsafe fn new(
|
|
|
|
_private: Private,
|
|
|
|
getter: unsafe extern "C" fn(msg: RawMessage) -> PtrAndLen,
|
|
|
|
setter: unsafe extern "C" fn(msg: RawMessage, val: PtrAndLen),
|
|
|
|
clearer: unsafe extern "C" fn(msg: RawMessage),
|
|
|
|
default: &'static [u8],
|
|
|
|
) -> Self {
|
|
|
|
Self { base: BytesMutVTable { getter, setter }, clearer, default }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'msg> RawVTableMutator<'msg, [u8]> {
|
|
|
|
pub(crate) fn get(self) -> &'msg [u8] {
|
|
|
|
// SAFETY:
|
|
|
|
// - `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() }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// # Safety
|
|
|
|
/// - `msg_ref` must be valid for `'msg`
|
|
|
|
/// - If this is for a `string` field, `val` must be valid UTF-8 if the
|
|
|
|
/// runtime requires it.
|
|
|
|
pub(crate) unsafe fn set(self, val: &[u8]) {
|
|
|
|
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()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn truncate(&self, len: usize) {
|
|
|
|
if len == 0 {
|
|
|
|
// SAFETY: The empty string is valid UTF-8.
|
|
|
|
unsafe {
|
|
|
|
self.set(b"");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
todo!("b/294252563")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'msg> RawVTableOptionalMutatorData<'msg, [u8]> {
|
|
|
|
/// Sets an absent `bytes`/`string` field to its default value.
|
|
|
|
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.optional_vtable().default) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// # Safety
|
|
|
|
/// - If this is a `string` field, `val` must be valid UTF-8 if required by
|
|
|
|
/// the runtime.
|
|
|
|
pub(crate) unsafe fn set(self, val: &[u8]) -> Self {
|
|
|
|
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.optional_vtable().base.setter)(self.msg_ref.msg(), val.into()) }
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn clear(self) -> Self {
|
|
|
|
// SAFETY:
|
|
|
|
// - `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.optional_vtable().clearer)(self.msg_ref.msg()) }
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Primitive types using a vtable for message access that are trivial to copy
|
|
|
|
/// and have a `'static` lifetime.
|
|
|
|
///
|
|
|
|
/// Implementing this trait automatically implements `ProxiedWithRawVTable`,
|
|
|
|
/// `ProxiedWithRawOptionalVTable`, and get/set/clear methods on
|
|
|
|
/// `RawVTableMutator` and `RawVTableOptionalMutatorData` that use the vtable.
|
|
|
|
///
|
|
|
|
/// It doesn't implement `Proxied`, `ViewProxy`, `SettableValue` or
|
|
|
|
/// `ProxiedWithPresence` for `Self` to avoid future conflicting blanket impls
|
|
|
|
/// on those traits.
|
|
|
|
pub trait PrimitiveWithRawVTable:
|
|
|
|
Copy
|
|
|
|
+ Debug
|
|
|
|
+ 'static
|
|
|
|
+ ProxiedWithPresence
|
|
|
|
+ Sync
|
|
|
|
+ Send
|
|
|
|
+ for<'msg> Proxied<View<'msg> = Self, Mut<'msg> = PrimitiveMut<'msg, Self>>
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: PrimitiveWithRawVTable> ProxiedWithRawVTable for T {
|
|
|
|
type VTable = PrimitiveVTable<T>;
|
|
|
|
|
|
|
|
fn make_view(_private: Private, mut_inner: InnerPrimitiveMut<'_, Self>) -> Self {
|
|
|
|
mut_inner.get()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn make_mut(_private: Private, inner: InnerPrimitiveMut<'_, Self>) -> PrimitiveMut<'_, Self> {
|
|
|
|
// SAFETY: `inner` is valid for the necessary lifetime and `T` as promised by
|
|
|
|
// the caller of `InnerPrimitiveMut::new`.
|
|
|
|
unsafe { PrimitiveMut::from_inner(Private, inner) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: PrimitiveWithRawVTable> ProxiedWithRawOptionalVTable for T {
|
|
|
|
type OptionalVTable = PrimitiveOptionalMutVTable<T>;
|
|
|
|
|
|
|
|
fn upcast_vtable(
|
|
|
|
_private: Private,
|
|
|
|
optional_vtable: &'static Self::OptionalVTable,
|
|
|
|
) -> &'static Self::VTable {
|
|
|
|
&optional_vtable.base
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: PrimitiveWithRawVTable> RawVTableMutator<'_, T> {
|
|
|
|
pub(crate) fn get(self) -> T {
|
|
|
|
// 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()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// # Safety
|
|
|
|
/// - `msg_ref` must be valid for the lifetime of `RawVTableMutator`.
|
|
|
|
pub(crate) unsafe fn set(self, val: T) {
|
|
|
|
// 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) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'msg, T: PrimitiveWithRawVTable> RawVTableOptionalMutatorData<'msg, T> {
|
|
|
|
pub fn set_absent_to_default(self, private: Private) -> Self {
|
|
|
|
// SAFETY:
|
|
|
|
// - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as
|
|
|
|
// promised by the caller of `new`.
|
|
|
|
self.set(private, self.optional_vtable().default)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set(self, _private: Private, val: T) -> Self {
|
|
|
|
// SAFETY:
|
|
|
|
// - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as
|
|
|
|
// promised by the caller of `new`.
|
|
|
|
unsafe { (self.optional_vtable().base.setter)(self.msg_ref.msg(), val) }
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn clear(self, _private: Private) -> Self {
|
|
|
|
// SAFETY:
|
|
|
|
// - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as
|
|
|
|
// promised by the caller of `new`.
|
|
|
|
unsafe { (self.optional_vtable().clearer)(self.msg_ref.msg()) }
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct MessageVTable {
|
|
|
|
pub getter: unsafe extern "C" fn(msg: RawMessage) -> RawMessage,
|
|
|
|
pub mut_getter: unsafe extern "C" fn(msg: RawMessage) -> RawMessage,
|
|
|
|
pub clearer: unsafe extern "C" fn(msg: RawMessage),
|
|
|
|
}
|