|
|
|
@ -33,12 +33,11 @@ |
|
|
|
|
#![allow(unused)] |
|
|
|
|
|
|
|
|
|
use crate::__internal::Private; |
|
|
|
|
use crate::{Mut, MutProxy, Proxied, SettableValue, View, ViewProxy}; |
|
|
|
|
use crate::{Mut, MutProxy, Proxied, ProxiedWithPresence, SettableValue, View, ViewProxy}; |
|
|
|
|
use std::convert::{AsMut, AsRef}; |
|
|
|
|
use std::fmt::{self, Debug}; |
|
|
|
|
|
|
|
|
|
/// The type that will go here is not yet defined.
|
|
|
|
|
pub type Todo<T = ()> = (std::marker::PhantomData<T>, std::convert::Infallible); |
|
|
|
|
use std::panic; |
|
|
|
|
use std::ptr; |
|
|
|
|
|
|
|
|
|
/// A protobuf value from a field that may not be set.
|
|
|
|
|
///
|
|
|
|
@ -51,13 +50,15 @@ pub type Todo<T = ()> = (std::marker::PhantomData<T>, std::convert::Infallible); |
|
|
|
|
/// Two `Optional`s are equal if they match both presence and the field values.
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)] |
|
|
|
|
pub enum Optional<SetVal, UnsetVal = SetVal> { |
|
|
|
|
/// The field is present. It can be accessed through this `T`.
|
|
|
|
|
/// The field is set; it is present in the serialized message.
|
|
|
|
|
///
|
|
|
|
|
/// - For an `_opt()` accessor, this contains a `View<impl Proxied>`.
|
|
|
|
|
/// - For a `_mut()` accessor, this contains a [`PresentField`].
|
|
|
|
|
/// - For a `_mut()` accessor, this contains a [`PresentField`] that can be
|
|
|
|
|
/// used to access the current value, convert to [`Mut`], clear presence,
|
|
|
|
|
/// or set a new value.
|
|
|
|
|
Set(SetVal), |
|
|
|
|
|
|
|
|
|
/// The field is unset.
|
|
|
|
|
/// The field is unset; it is absent in the serialized message.
|
|
|
|
|
///
|
|
|
|
|
/// - For an `_opt()` accessor, this contains a `View<impl Proxied>` with
|
|
|
|
|
/// the default value.
|
|
|
|
@ -73,6 +74,11 @@ impl<T> Optional<T> { |
|
|
|
|
Optional::Set(x) | Optional::Unset(x) => x, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Constructs an `Optional<T>` with a `T` value and presence bit.
|
|
|
|
|
pub fn new(val: T, is_set: bool) -> Self { |
|
|
|
|
if is_set { Optional::Set(val) } else { Optional::Unset(val) } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<T, A> Optional<T, A> { |
|
|
|
@ -105,7 +111,7 @@ pub type FieldEntry<'a, T> = Optional<PresentField<'a, T>, AbsentField<'a, T>>; |
|
|
|
|
/// Methods for `_mut()` accessors of optional types.
|
|
|
|
|
///
|
|
|
|
|
/// The most common methods are [`set`] and [`or_default`].
|
|
|
|
|
impl<'msg, T: Proxied + ?Sized + 'msg> FieldEntry<'msg, T> { |
|
|
|
|
impl<'msg, T: ProxiedWithPresence + ?Sized + 'msg> FieldEntry<'msg, T> { |
|
|
|
|
// is_set() is provided by `impl<T, A> Optional<T, A>`
|
|
|
|
|
|
|
|
|
|
/// Gets a mutator for this field. Sets to the default value if not set.
|
|
|
|
@ -118,30 +124,27 @@ impl<'msg, T: Proxied + ?Sized + 'msg> FieldEntry<'msg, T> { |
|
|
|
|
|
|
|
|
|
/// Sets the value of this field to `val`.
|
|
|
|
|
///
|
|
|
|
|
/// Equivalent to `self.or_default().set(val)`.
|
|
|
|
|
/// Equivalent to `self.or_default().set(val)`, but does not consume `self`.
|
|
|
|
|
pub fn set(&mut self, val: impl SettableValue<T>) { |
|
|
|
|
match self { |
|
|
|
|
Optional::Set(x) => x.set(val), |
|
|
|
|
Optional::Unset(x) => todo!(), |
|
|
|
|
} |
|
|
|
|
transform_mut(self, |mut self_| match self_ { |
|
|
|
|
Optional::Set(ref mut present) => { |
|
|
|
|
present.set(val); |
|
|
|
|
self_ |
|
|
|
|
} |
|
|
|
|
Optional::Unset(absent) => Optional::Set(absent.set(val)), |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Clears the field; `is_set()` will return `false`.
|
|
|
|
|
pub fn clear(&mut self) { |
|
|
|
|
todo!("b/285308646: Requires a trait method") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Gets an immutable view of this field, using its default value if not
|
|
|
|
|
/// set.
|
|
|
|
|
///
|
|
|
|
|
/// This has a shorter lifetime than the `field_name()` message accessor;
|
|
|
|
|
/// `into_view` provides that lifetime.
|
|
|
|
|
pub fn get(self) -> View<'msg, T> { |
|
|
|
|
self.into_view() |
|
|
|
|
transform_mut(self, |self_| match self_ { |
|
|
|
|
Optional::Set(present) => Optional::Unset(present.clear()), |
|
|
|
|
absent => absent, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'msg, T: Proxied + ?Sized + 'msg> ViewProxy<'msg> for FieldEntry<'msg, T> { |
|
|
|
|
impl<'msg, T: ProxiedWithPresence + ?Sized + 'msg> ViewProxy<'msg> for FieldEntry<'msg, T> { |
|
|
|
|
type Proxied = T; |
|
|
|
|
|
|
|
|
|
fn as_view(&self) -> View<'_, T> { |
|
|
|
@ -169,20 +172,21 @@ impl<'msg, T: Proxied + ?Sized + 'msg> ViewProxy<'msg> for FieldEntry<'msg, T> { |
|
|
|
|
/// set field.
|
|
|
|
|
pub struct PresentField<'msg, T> |
|
|
|
|
where |
|
|
|
|
T: Proxied + ?Sized + 'msg, |
|
|
|
|
T: ProxiedWithPresence + ?Sized + 'msg, |
|
|
|
|
{ |
|
|
|
|
inner: Todo<Mut<'msg, T>>, |
|
|
|
|
inner: T::PresentMutData<'msg>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'msg, T: Proxied + ?Sized + 'msg> Debug for PresentField<'msg, T> { |
|
|
|
|
impl<'msg, T: ProxiedWithPresence + ?Sized + 'msg> Debug for PresentField<'msg, T> { |
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
|
|
|
|
todo!() |
|
|
|
|
self.inner.fmt(f) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'msg, T: Proxied + ?Sized + 'msg> PresentField<'msg, T> { |
|
|
|
|
pub fn get(self) -> View<'msg, T> { |
|
|
|
|
self.into_view() |
|
|
|
|
impl<'msg, T: ProxiedWithPresence + ?Sized + 'msg> PresentField<'msg, T> { |
|
|
|
|
#[doc(hidden)] |
|
|
|
|
pub fn from_inner(_private: Private, inner: T::PresentMutData<'msg>) -> Self { |
|
|
|
|
Self { inner } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn set(&mut self, val: impl SettableValue<T>) { |
|
|
|
@ -190,8 +194,8 @@ impl<'msg, T: Proxied + ?Sized + 'msg> PresentField<'msg, T> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// See [`FieldEntry::clear`].
|
|
|
|
|
pub fn clear(self) -> AbsentField<'msg, T> { |
|
|
|
|
todo!("b/285308646: Requires a trait method") |
|
|
|
|
pub fn clear(mut self) -> AbsentField<'msg, T> { |
|
|
|
|
AbsentField { inner: T::clear_present_field(self.inner) } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// This cannot provide `reborrow` - `clear` consumes after setting the field
|
|
|
|
@ -200,35 +204,35 @@ impl<'msg, T: Proxied + ?Sized + 'msg> PresentField<'msg, T> { |
|
|
|
|
|
|
|
|
|
impl<'msg, T> ViewProxy<'msg> for PresentField<'msg, T> |
|
|
|
|
where |
|
|
|
|
T: Proxied + ?Sized + 'msg, |
|
|
|
|
T: ProxiedWithPresence + ?Sized + 'msg, |
|
|
|
|
{ |
|
|
|
|
type Proxied = T; |
|
|
|
|
|
|
|
|
|
fn as_view(&self) -> View<'_, T> { |
|
|
|
|
todo!("b/285308646: Requires a trait method") |
|
|
|
|
self.inner.as_view() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn into_view<'shorter>(self) -> View<'shorter, T> |
|
|
|
|
where |
|
|
|
|
'msg: 'shorter, |
|
|
|
|
{ |
|
|
|
|
todo!("b/285308646: Requires a trait method") |
|
|
|
|
self.inner.into_view() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'msg, T> MutProxy<'msg> for PresentField<'msg, T> |
|
|
|
|
where |
|
|
|
|
T: Proxied + ?Sized + 'msg, |
|
|
|
|
T: ProxiedWithPresence + ?Sized + 'msg, |
|
|
|
|
{ |
|
|
|
|
fn as_mut(&mut self) -> Mut<'_, T> { |
|
|
|
|
todo!("b/285308646: Requires a trait method") |
|
|
|
|
self.inner.as_mut() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn into_mut<'shorter>(self) -> Mut<'shorter, T> |
|
|
|
|
where |
|
|
|
|
'msg: 'shorter, |
|
|
|
|
{ |
|
|
|
|
todo!("b/285308646: Requires a trait method") |
|
|
|
|
self.inner.into_mut() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -236,18 +240,23 @@ where |
|
|
|
|
/// non-set field.
|
|
|
|
|
pub struct AbsentField<'a, T> |
|
|
|
|
where |
|
|
|
|
T: Proxied + ?Sized + 'a, |
|
|
|
|
T: ProxiedWithPresence + ?Sized + 'a, |
|
|
|
|
{ |
|
|
|
|
inner: Todo<Option<Mut<'a, T>>>, |
|
|
|
|
inner: T::AbsentMutData<'a>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'msg, T: Proxied + ?Sized + 'msg> Debug for AbsentField<'msg, T> { |
|
|
|
|
impl<'msg, T: ProxiedWithPresence + ?Sized + 'msg> Debug for AbsentField<'msg, T> { |
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
|
|
|
|
todo!() |
|
|
|
|
self.inner.fmt(f) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'msg, T: Proxied + ?Sized> AbsentField<'msg, T> { |
|
|
|
|
impl<'msg, T: ProxiedWithPresence + ?Sized> AbsentField<'msg, T> { |
|
|
|
|
#[doc(hidden)] |
|
|
|
|
pub fn from_inner(_private: Private, inner: T::AbsentMutData<'msg>) -> Self { |
|
|
|
|
Self { inner } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Gets the default value for this unset field.
|
|
|
|
|
///
|
|
|
|
|
/// This is the same value that the primitive accessor would provide.
|
|
|
|
@ -258,12 +267,12 @@ impl<'msg, T: Proxied + ?Sized> AbsentField<'msg, T> { |
|
|
|
|
/// See [`FieldEntry::set`]. Note that this consumes and returns a
|
|
|
|
|
/// `PresentField`.
|
|
|
|
|
pub fn set(self, val: impl SettableValue<T>) -> PresentField<'msg, T> { |
|
|
|
|
todo!("b/285308646: Requires a trait method") |
|
|
|
|
PresentField { inner: val.set_on_absent(Private, self.inner) } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Sets this absent field to its default value.
|
|
|
|
|
pub fn set_default(self) -> PresentField<'msg, T> { |
|
|
|
|
todo!("b/285308646: Requires a trait method") |
|
|
|
|
PresentField { inner: T::set_absent_to_default(self.inner) } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// This cannot provide `reborrow` - `set` consumes after setting the field
|
|
|
|
@ -273,18 +282,373 @@ impl<'msg, T: Proxied + ?Sized> AbsentField<'msg, T> { |
|
|
|
|
|
|
|
|
|
impl<'msg, T> ViewProxy<'msg> for AbsentField<'msg, T> |
|
|
|
|
where |
|
|
|
|
T: Proxied + ?Sized + 'msg, |
|
|
|
|
T: ProxiedWithPresence + ?Sized + 'msg, |
|
|
|
|
{ |
|
|
|
|
type Proxied = T; |
|
|
|
|
|
|
|
|
|
fn as_view(&self) -> View<'_, T> { |
|
|
|
|
todo!("b/285308646: Requires a trait method") |
|
|
|
|
self.inner.as_view() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn into_view<'shorter>(self) -> View<'shorter, T> |
|
|
|
|
where |
|
|
|
|
'msg: 'shorter, |
|
|
|
|
{ |
|
|
|
|
todo!("b/285308646: Requires a trait method") |
|
|
|
|
self.inner.into_view() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Transforms a mutable reference in-place, treating it as if it were owned.
|
|
|
|
|
///
|
|
|
|
|
/// The program will abort if `transform` panics.
|
|
|
|
|
///
|
|
|
|
|
/// This is the same operation as provided by [`take_mut::take`].
|
|
|
|
|
///
|
|
|
|
|
/// [`take_mut::take`]: https://docs.rs/take_mut/latest/take_mut/fn.take.html
|
|
|
|
|
fn transform_mut<T>(mut_ref: &mut T, transform: impl FnOnce(T) -> T) { |
|
|
|
|
#[cold] |
|
|
|
|
#[inline(never)] |
|
|
|
|
fn panicked_in_transform_mut() -> ! { |
|
|
|
|
use std::io::Write as _; |
|
|
|
|
let backtrace = std::backtrace::Backtrace::force_capture(); |
|
|
|
|
let stderr = std::io::stderr(); |
|
|
|
|
let mut stderr = stderr.lock(); |
|
|
|
|
let _ = write!(&mut stderr, "BUG: A protobuf mutator panicked! Backtrace:\n{backtrace}\n"); |
|
|
|
|
let _ = stderr.flush(); |
|
|
|
|
std::process::abort() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// https://play.rust-lang.org/?edition=2021&gist=f3014e1f209013f0a38352e211f4a240
|
|
|
|
|
// provides a sample test to confirm this operation is sound in Miri.
|
|
|
|
|
// SAFETY:
|
|
|
|
|
// - `old_t` is not dropped without also replacing `*mut_ref`, preventing a
|
|
|
|
|
// double-free.
|
|
|
|
|
// - If `transform` panics, the process aborts since `*mut_ref` has no possible
|
|
|
|
|
// valid value.
|
|
|
|
|
// - After `ptr::write`, a valid `T` is located at `*mut_ref`
|
|
|
|
|
unsafe { |
|
|
|
|
let p: *mut T = mut_ref; |
|
|
|
|
let old_t = p.read(); |
|
|
|
|
let new_t = panic::catch_unwind(panic::AssertUnwindSafe(move || transform(old_t))) |
|
|
|
|
.unwrap_or_else(|_| panicked_in_transform_mut()); |
|
|
|
|
p.write(new_t); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
|
mod tests { |
|
|
|
|
use super::*; |
|
|
|
|
use std::borrow::Cow; |
|
|
|
|
|
|
|
|
|
/// A sample message with custom presence bits, meant to mirror a C++
|
|
|
|
|
/// message.
|
|
|
|
|
#[derive(Default, Debug)] |
|
|
|
|
struct MyMessage { |
|
|
|
|
/// has a default of `0`
|
|
|
|
|
a: i32, |
|
|
|
|
|
|
|
|
|
/// has a default of `5`
|
|
|
|
|
b: i32, |
|
|
|
|
|
|
|
|
|
/// Packed presence bitfield for `a` and `b`
|
|
|
|
|
presence: u8, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl MyMessage { |
|
|
|
|
fn a(&self) -> View<'_, VtableProxied> { |
|
|
|
|
VtableProxiedView { val: get_a(self) } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn a_opt(&self) -> Optional<View<'_, VtableProxied>> { |
|
|
|
|
Optional::new(self.a(), has_a(self)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn a_mut(&mut self) -> FieldEntry<'_, VtableProxied> { |
|
|
|
|
static A_VTABLE: ProxyVtable = |
|
|
|
|
ProxyVtable { get: get_a, set: set_a, clear: clear_a, has: has_a }; |
|
|
|
|
make_field_entry(self, &A_VTABLE) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn b(&self) -> View<'_, VtableProxied> { |
|
|
|
|
VtableProxiedView { val: get_b(self) } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn b_opt(&self) -> Optional<View<'_, VtableProxied>> { |
|
|
|
|
Optional::new(self.b(), has_b(self)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn b_mut(&mut self) -> FieldEntry<'_, VtableProxied> { |
|
|
|
|
static B_VTABLE: ProxyVtable = |
|
|
|
|
ProxyVtable { get: get_b, set: set_b, clear: clear_b, has: has_b }; |
|
|
|
|
make_field_entry(self, &B_VTABLE) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn make_field_entry<'a>( |
|
|
|
|
msg: &'a mut MyMessage, |
|
|
|
|
vtable: &'a ProxyVtable, |
|
|
|
|
) -> FieldEntry<'a, VtableProxied> { |
|
|
|
|
if (vtable.has)(&*msg) { |
|
|
|
|
Optional::Set(PresentField::from_inner(Private, VtableProxiedMut { msg, vtable })) |
|
|
|
|
} else { |
|
|
|
|
Optional::Unset(AbsentField::from_inner(Private, VtableProxiedMut { msg, vtable })) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Thunks used for the vtable. For a C++ message these would be defined in C++
|
|
|
|
|
// and exported via a C API
|
|
|
|
|
const A_BIT: u8 = 0; |
|
|
|
|
const B_BIT: u8 = 1; |
|
|
|
|
|
|
|
|
|
fn get_a(msg: &MyMessage) -> i32 { |
|
|
|
|
if has_a(msg) { msg.a } else { 0 } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn get_b(msg: &MyMessage) -> i32 { |
|
|
|
|
if has_b(msg) { msg.b } else { 5 } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn set_a(msg: &mut MyMessage, val: i32) { |
|
|
|
|
msg.presence |= (1 << A_BIT); |
|
|
|
|
msg.a = val; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn set_b(msg: &mut MyMessage, val: i32) { |
|
|
|
|
msg.presence |= (1 << B_BIT); |
|
|
|
|
msg.b = val; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn clear_a(msg: &mut MyMessage) { |
|
|
|
|
msg.presence &= !(1 << A_BIT); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn clear_b(msg: &mut MyMessage) { |
|
|
|
|
msg.presence &= !(1 << B_BIT); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn has_a(msg: &MyMessage) -> bool { |
|
|
|
|
msg.presence & (1 << A_BIT) != 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn has_b(msg: &MyMessage) -> bool { |
|
|
|
|
msg.presence & (1 << B_BIT) != 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct ProxyVtable { |
|
|
|
|
get: fn(&MyMessage) -> i32, |
|
|
|
|
set: fn(&mut MyMessage, val: i32), |
|
|
|
|
clear: fn(&mut MyMessage), |
|
|
|
|
has: fn(&MyMessage) -> bool, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Debug for ProxyVtable { |
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
|
|
|
|
// Manual `Debug` impl to work around `fmt::Debug` not being implemented for
|
|
|
|
|
// functions pointers with higher-ranked lifetimes, which was fixed
|
|
|
|
|
// in Rust 1.70.
|
|
|
|
|
// TODO(hlopko): replace with `#[derive(Debug)]` when rustc is updated.
|
|
|
|
|
f.debug_struct("ProxyVtable") |
|
|
|
|
.field("get", &(self.get as *const ())) |
|
|
|
|
.field("set", &(self.set as *const ())) |
|
|
|
|
.field("clear", &(self.clear as *const ())) |
|
|
|
|
.field("has", &(self.has as *const ())) |
|
|
|
|
.finish() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// A proxy for a `i32` that is accessed through methods on a vtable.
|
|
|
|
|
struct VtableProxied; |
|
|
|
|
|
|
|
|
|
impl Proxied for VtableProxied { |
|
|
|
|
type View<'a> = VtableProxiedView; |
|
|
|
|
type Mut<'a> = VtableProxiedMut<'a>; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl ProxiedWithPresence for VtableProxied { |
|
|
|
|
// In this case, the `PresentMutData` and `AbsentMutData` are identical to the
|
|
|
|
|
// `Mut` in layout. Other types/runtimes could require otherwise, e.g. `Mut`
|
|
|
|
|
// could be defined to only have get/set functions in its vtable, and not
|
|
|
|
|
// has/clear.
|
|
|
|
|
type PresentMutData<'a> = VtableProxiedMut<'a>; |
|
|
|
|
type AbsentMutData<'a> = VtableProxiedMut<'a>; |
|
|
|
|
|
|
|
|
|
fn clear_present_field<'a>( |
|
|
|
|
present_mutator: Self::PresentMutData<'a>, |
|
|
|
|
) -> Self::AbsentMutData<'a> { |
|
|
|
|
(present_mutator.vtable.clear)(&mut *present_mutator.msg); |
|
|
|
|
present_mutator |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn set_absent_to_default<'a>( |
|
|
|
|
absent_mutator: Self::AbsentMutData<'a>, |
|
|
|
|
) -> Self::PresentMutData<'a> { |
|
|
|
|
absent_mutator.as_view().val().set_on_absent(Private, absent_mutator) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)] |
|
|
|
|
struct VtableProxiedView { |
|
|
|
|
val: i32, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl VtableProxiedView { |
|
|
|
|
fn val(&self) -> i32 { |
|
|
|
|
self.val |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn read(msg: &MyMessage, vtable: &ProxyVtable) -> Self { |
|
|
|
|
VtableProxiedView { val: (vtable.get)(msg) } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'a> ViewProxy<'a> for VtableProxiedView { |
|
|
|
|
type Proxied = VtableProxied; |
|
|
|
|
|
|
|
|
|
fn as_view(&self) -> View<'a, VtableProxied> { |
|
|
|
|
*self |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn into_view<'shorter>(self) -> View<'shorter, VtableProxied> |
|
|
|
|
where |
|
|
|
|
'a: 'shorter, |
|
|
|
|
{ |
|
|
|
|
self |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Debug)] |
|
|
|
|
struct VtableProxiedMut<'a> { |
|
|
|
|
msg: &'a mut MyMessage, |
|
|
|
|
vtable: &'a ProxyVtable, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'a> ViewProxy<'a> for VtableProxiedMut<'a> { |
|
|
|
|
type Proxied = VtableProxied; |
|
|
|
|
|
|
|
|
|
fn as_view(&self) -> View<'_, VtableProxied> { |
|
|
|
|
VtableProxiedView::read(self.msg, self.vtable) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn into_view<'shorter>(self) -> View<'shorter, VtableProxied> |
|
|
|
|
where |
|
|
|
|
'a: 'shorter, |
|
|
|
|
{ |
|
|
|
|
VtableProxiedView::read(self.msg, self.vtable) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'a> MutProxy<'a> for VtableProxiedMut<'a> { |
|
|
|
|
fn as_mut(&mut self) -> Mut<'_, VtableProxied> { |
|
|
|
|
VtableProxiedMut { msg: self.msg, vtable: self.vtable } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn into_mut<'shorter>(self) -> Mut<'shorter, VtableProxied> |
|
|
|
|
where |
|
|
|
|
'a: 'shorter, |
|
|
|
|
{ |
|
|
|
|
self |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl SettableValue<VtableProxied> for View<'_, VtableProxied> { |
|
|
|
|
fn set_on(self, _private: Private, mutator: Mut<VtableProxied>) { |
|
|
|
|
self.val().set_on(Private, mutator) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn set_on_absent<'a>( |
|
|
|
|
self, |
|
|
|
|
_private: Private, |
|
|
|
|
absent_mutator: <VtableProxied as ProxiedWithPresence>::AbsentMutData<'a>, |
|
|
|
|
) -> <VtableProxied as ProxiedWithPresence>::PresentMutData<'a> { |
|
|
|
|
self.val().set_on_absent(Private, absent_mutator) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl SettableValue<VtableProxied> for i32 { |
|
|
|
|
fn set_on(self, _private: Private, mutator: Mut<VtableProxied>) { |
|
|
|
|
(mutator.vtable.set)(mutator.msg, self) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn set_on_absent<'a>( |
|
|
|
|
self, |
|
|
|
|
_private: Private, |
|
|
|
|
absent_mutator: <VtableProxied as ProxiedWithPresence>::AbsentMutData<'a>, |
|
|
|
|
) -> <VtableProxied as ProxiedWithPresence>::PresentMutData<'a> { |
|
|
|
|
(absent_mutator.vtable.set)(absent_mutator.msg, self); |
|
|
|
|
absent_mutator |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_field_entry() { |
|
|
|
|
let mut m1 = MyMessage::default(); |
|
|
|
|
let mut m2 = MyMessage::default(); |
|
|
|
|
|
|
|
|
|
let mut m1_a = m1.a_mut(); |
|
|
|
|
assert!(matches!(m1_a, Optional::Unset(_))); |
|
|
|
|
assert_eq!(m1_a.as_view().val(), 0); |
|
|
|
|
|
|
|
|
|
assert_eq!(m2.b().val(), 5); |
|
|
|
|
|
|
|
|
|
let mut m2_b = m2.b_mut(); |
|
|
|
|
assert!(m2_b.is_unset()); |
|
|
|
|
assert_eq!(m2_b.as_view().val(), 5); |
|
|
|
|
|
|
|
|
|
m2_b.set(10); |
|
|
|
|
assert!(m2_b.is_set()); |
|
|
|
|
assert!(matches!(m2_b, Optional::Set(_))); |
|
|
|
|
assert_eq!(m2_b.as_view().val(), 10); |
|
|
|
|
|
|
|
|
|
assert_eq!(m1_a.or_default().as_view().val(), 0); |
|
|
|
|
assert_eq!(m1.a_opt(), Optional::Set(VtableProxiedView { val: 0 })); |
|
|
|
|
m1.a_mut().clear(); |
|
|
|
|
|
|
|
|
|
assert_eq!(m1.a().val(), 0); |
|
|
|
|
assert_eq!(m1.b().val(), 5); |
|
|
|
|
assert_eq!(m2.a().val(), 0); |
|
|
|
|
assert_eq!(m2.b().val(), 10); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_present_field() { |
|
|
|
|
let mut m = MyMessage::default(); |
|
|
|
|
m.a_mut().set(10); |
|
|
|
|
match m.a_mut() { |
|
|
|
|
Optional::Set(mut present) => { |
|
|
|
|
assert_eq!(present.as_view().val(), 10); |
|
|
|
|
present.set(20); |
|
|
|
|
assert_eq!(present.as_view().val(), 20); |
|
|
|
|
present.into_mut().set(30); |
|
|
|
|
} |
|
|
|
|
Optional::Unset(_) => unreachable!(), |
|
|
|
|
} |
|
|
|
|
assert_eq!(m.a_opt(), Optional::Set(VtableProxiedView { val: 30 })); |
|
|
|
|
m.b_mut().set(20); |
|
|
|
|
match m.b_mut() { |
|
|
|
|
Optional::Set(present) => present.clear(), |
|
|
|
|
Optional::Unset(_) => unreachable!(), |
|
|
|
|
}; |
|
|
|
|
assert_eq!(m.b_opt(), Optional::Unset(VtableProxiedView { val: 5 })); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_absent_field() { |
|
|
|
|
let mut m = MyMessage::default(); |
|
|
|
|
match m.a_mut() { |
|
|
|
|
Optional::Set(_) => unreachable!(), |
|
|
|
|
Optional::Unset(absent) => { |
|
|
|
|
assert_eq!(absent.as_view().val(), 0); |
|
|
|
|
absent.set(20); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
assert_eq!(m.a_opt(), Optional::Set(VtableProxiedView { val: 20 })); |
|
|
|
|
match m.b_mut() { |
|
|
|
|
Optional::Set(_) => unreachable!(), |
|
|
|
|
Optional::Unset(absent) => { |
|
|
|
|
assert_eq!(absent.as_view().val(), 5); |
|
|
|
|
absent.set_default(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
assert_eq!(m.b_opt(), Optional::Set(VtableProxiedView { val: 5 })); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|