| // 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 |
| |
| //! Items specific to `optional` fields. |
| #![allow(dead_code)] |
| #![allow(unused)] |
| |
| use crate::__internal::Private; |
| use crate::{Mut, MutProxy, Proxied, ProxiedWithPresence, SettableValue, View, ViewProxy}; |
| use std::convert::{AsMut, AsRef}; |
| use std::fmt::{self, Debug}; |
| use std::panic; |
| use std::ptr; |
| |
| /// A protobuf value from a field that may not be set. |
| /// |
| /// This can be pattern matched with `match` or `if let` to determine if the |
| /// field is set and access the field data. |
| /// |
| /// [`FieldEntry`], a specific type alias for `Optional`, provides much of the |
| /// functionality for this type. |
| /// |
| /// 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 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`] 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; it is absent in the serialized message. |
| /// |
| /// - For an `_opt()` accessor, this contains a `View<impl Proxied>` with |
| /// the default value. |
| /// - For a `_mut()` accessor, this contains an [`AbsentField`] that can be |
| /// used to access the default or set a new value. |
| Unset(UnsetVal), |
| } |
| |
| impl<T> Optional<T> { |
| /// Gets the field value, ignoring whether it was set or not. |
| pub fn into_inner(self) -> T { |
| match self { |
| 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> { |
| /// Converts into an `Option` of the set value, ignoring any unset value. |
| pub fn into_option(self) -> Option<T> { |
| if let Optional::Set(x) = self { Some(x) } else { None } |
| } |
| |
| /// Returns if the field is set. |
| pub fn is_set(&self) -> bool { |
| matches!(self, Optional::Set(_)) |
| } |
| |
| /// Returns if the field is unset. |
| pub fn is_unset(&self) -> bool { |
| matches!(self, Optional::Unset(_)) |
| } |
| } |
| |
| impl<T> From<Optional<T>> for Option<T> { |
| fn from(x: Optional<T>) -> Option<T> { |
| x.into_option() |
| } |
| } |
| |
| /// A mutable view into the value of an optional field, which may be set or |
| /// unset. |
| pub type FieldEntry<'msg, T> = Optional<PresentField<'msg, T>, AbsentField<'msg, T>>; |
| |
| /// Methods for `_mut()` accessors of optional types. |
| /// |
| /// The most common methods are [`set`] and [`or_default`]. |
| 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. |
| pub fn or_default(self) -> Mut<'msg, T> { |
| match self { |
| Optional::Set(x) => x.into_mut(), |
| Optional::Unset(x) => x.set_default().into_mut(), |
| } |
| } |
| |
| /// Gets a mutator for this field. Sets to the given `val` if not set. |
| /// |
| /// If the field is already set, `val` is ignored. |
| pub fn or_set(self, val: impl SettableValue<T>) -> Mut<'msg, T> { |
| self.or_set_with(move || val) |
| } |
| |
| /// Gets a mutator for this field. Sets using the given `val` function if |
| /// not set. |
| /// |
| /// If the field is already set, `val` is not invoked. |
| pub fn or_set_with<S>(self, val: impl FnOnce() -> S) -> Mut<'msg, T> |
| where |
| S: SettableValue<T>, |
| { |
| match self { |
| Optional::Set(x) => x.into_mut(), |
| Optional::Unset(x) => x.set(val()).into_mut(), |
| } |
| } |
| |
| /// Sets the value of this field to `val`. |
| /// |
| /// Equivalent to `self.or_default().set(val)`, but does not consume `self`. |
| /// |
| /// `set` has the same parameters as in [`MutProxy`], so making a field |
| /// `optional` will switch to using this method. This makes transitioning |
| /// from implicit to explicit presence easier. |
| pub fn set(&mut self, val: impl SettableValue<T>) { |
| 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) { |
| transform_mut(self, |self_| match self_ { |
| Optional::Set(present) => Optional::Unset(present.clear()), |
| absent => absent, |
| }) |
| } |
| |
| /// Gets an immutable view of this field, using its default value if not |
| /// set. This is shorthand for `as_view`. |
| /// |
| /// This provides a shorter lifetime than `into_view` but can also be called |
| /// multiple times - if the result of `get` is not living long enough |
| /// for your use, use that instead. |
| /// |
| /// `get` has the same parameters as in [`MutProxy`], so making a field |
| /// `optional` will switch to using this method. This makes transitioning |
| /// from implicit to explicit presence easier. |
| pub fn get(&self) -> View<'_, T> { |
| self.as_view() |
| } |
| |
| /// Converts to an immutable view of this optional field, preserving the |
| /// field's presence. |
| pub fn into_optional_view(self) -> Optional<View<'msg, T>> { |
| let is_set = self.is_set(); |
| Optional::new(self.into_view(), is_set) |
| } |
| |
| /// Returns a field mutator if the field is set. |
| /// |
| /// Returns `None` if the field is not set. This does not affect `is_set()`. |
| /// |
| /// This returns `Option` and _not_ `Optional` since returning a defaulted |
| /// `Mut` would require mutating the presence of the field - for that |
| /// behavior, use `or_default()`. |
| pub fn try_into_mut(self) -> Option<Mut<'msg, T>> { |
| match self { |
| Optional::Set(x) => Some(x.into_mut()), |
| Optional::Unset(_) => None, |
| } |
| } |
| } |
| |
| impl<'msg, T: ProxiedWithPresence + ?Sized + 'msg> ViewProxy<'msg> for FieldEntry<'msg, T> { |
| type Proxied = T; |
| |
| fn as_view(&self) -> View<'_, T> { |
| match self { |
| Optional::Set(x) => x.as_view(), |
| Optional::Unset(x) => x.as_view(), |
| } |
| } |
| |
| fn into_view<'shorter>(self) -> View<'shorter, T> |
| where |
| 'msg: 'shorter, |
| { |
| match self { |
| Optional::Set(x) => x.into_view(), |
| Optional::Unset(x) => x.into_view(), |
| } |
| } |
| } |
| |
| // `MutProxy` not implemented for `FieldEntry` since the field may not be set, |
| // and `as_mut`/`into_mut` should not insert. |
| |
| /// A field mutator capable of clearing that is statically known to point to a |
| /// set field. |
| pub struct PresentField<'msg, T> |
| where |
| T: ProxiedWithPresence + ?Sized + 'msg, |
| { |
| pub(crate) inner: T::PresentMutData<'msg>, |
| } |
| |
| impl<'msg, T: ProxiedWithPresence + ?Sized + 'msg> Debug for PresentField<'msg, T> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| self.inner.fmt(f) |
| } |
| } |
| |
| impl<'msg, T: ProxiedWithPresence + ?Sized + 'msg> PresentField<'msg, T> { |
| #[doc(hidden)] |
| pub fn from_inner(_private: Private, inner: T::PresentMutData<'msg>) -> Self { |
| Self { inner } |
| } |
| |
| /// Gets an immutable view of this present field. This is shorthand for |
| /// `as_view`. |
| /// |
| /// This provides a shorter lifetime than `into_view` but can also be called |
| /// multiple times - if the result of `get` is not living long enough |
| /// for your use, use that instead. |
| pub fn get(&self) -> View<'_, T> { |
| self.as_view() |
| } |
| |
| pub fn set(&mut self, val: impl SettableValue<T>) { |
| val.set_on(Private, self.as_mut()) |
| } |
| |
| /// See [`FieldEntry::clear`]. |
| 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 |
| // because it would violate a condition of `PresentField` - the field being set. |
| } |
| |
| impl<'msg, T> ViewProxy<'msg> for PresentField<'msg, T> |
| where |
| T: ProxiedWithPresence + ?Sized + 'msg, |
| { |
| type Proxied = T; |
| |
| fn as_view(&self) -> View<'_, T> { |
| self.inner.as_view() |
| } |
| |
| fn into_view<'shorter>(self) -> View<'shorter, T> |
| where |
| 'msg: 'shorter, |
| { |
| self.inner.into_view() |
| } |
| } |
| |
| impl<'msg, T> MutProxy<'msg> for PresentField<'msg, T> |
| where |
| T: ProxiedWithPresence + ?Sized + 'msg, |
| { |
| fn as_mut(&mut self) -> Mut<'_, T> { |
| self.inner.as_mut() |
| } |
| |
| fn into_mut<'shorter>(self) -> Mut<'shorter, T> |
| where |
| 'msg: 'shorter, |
| { |
| self.inner.into_mut() |
| } |
| } |
| |
| /// A field mutator capable of setting that is statically known to point to a |
| /// non-set field. |
| pub struct AbsentField<'msg, T> |
| where |
| T: ProxiedWithPresence + ?Sized + 'msg, |
| { |
| pub(crate) inner: T::AbsentMutData<'msg>, |
| } |
| |
| impl<'msg, T: ProxiedWithPresence + ?Sized + 'msg> Debug for AbsentField<'msg, T> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| self.inner.fmt(f) |
| } |
| } |
| |
| 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, though |
| /// with the shorter lifetime of `as_view`. |
| pub fn default_value(&self) -> View<'_, T> { |
| self.as_view() |
| } |
| |
| /// See [`FieldEntry::set`]. Note that this consumes and returns a |
| /// `PresentField`. |
| pub fn set(self, val: impl SettableValue<T>) -> PresentField<'msg, T> { |
| 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> { |
| PresentField { inner: T::set_absent_to_default(self.inner) } |
| } |
| |
| // This cannot provide `reborrow` - `set` consumes after setting the field |
| // because it would violate a condition of `AbsentField` - the field being |
| // unset. |
| } |
| |
| impl<'msg, T> ViewProxy<'msg> for AbsentField<'msg, T> |
| where |
| T: ProxiedWithPresence + ?Sized + 'msg, |
| { |
| type Proxied = T; |
| |
| fn as_view(&self) -> View<'_, T> { |
| self.inner.as_view() |
| } |
| |
| fn into_view<'shorter>(self) -> View<'shorter, T> |
| where |
| 'msg: 'shorter, |
| { |
| 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<'msg>( |
| msg: &'msg mut MyMessage, |
| vtable: &'msg ProxyVtable, |
| ) -> FieldEntry<'msg, 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 |
| } |
| |
| #[derive(Debug)] |
| struct ProxyVtable { |
| get: fn(&MyMessage) -> i32, |
| set: fn(&mut MyMessage, val: i32), |
| clear: fn(&mut MyMessage), |
| has: fn(&MyMessage) -> bool, |
| } |
| |
| /// A proxy for a `i32` that is accessed through methods on a vtable. |
| struct VtableProxied; |
| |
| impl Proxied for VtableProxied { |
| type View<'msg> = VtableProxiedView; |
| type Mut<'msg> = VtableProxiedMut<'msg>; |
| } |
| |
| 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<'msg> = VtableProxiedMut<'msg>; |
| type AbsentMutData<'msg> = VtableProxiedMut<'msg>; |
| |
| fn clear_present_field<'msg>( |
| present_mutator: Self::PresentMutData<'msg>, |
| ) -> Self::AbsentMutData<'msg> { |
| (present_mutator.vtable.clear)(&mut *present_mutator.msg); |
| present_mutator |
| } |
| |
| fn set_absent_to_default<'msg>( |
| absent_mutator: Self::AbsentMutData<'msg>, |
| ) -> Self::PresentMutData<'msg> { |
| SettableValue::<VtableProxied>::set_on_absent( |
| absent_mutator.as_view().val(), |
| 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<'msg> ViewProxy<'msg> for VtableProxiedView { |
| type Proxied = VtableProxied; |
| |
| fn as_view(&self) -> View<'msg, VtableProxied> { |
| *self |
| } |
| |
| fn into_view<'shorter>(self) -> View<'shorter, VtableProxied> |
| where |
| 'msg: 'shorter, |
| { |
| self |
| } |
| } |
| |
| #[derive(Debug)] |
| struct VtableProxiedMut<'msg> { |
| msg: &'msg mut MyMessage, |
| vtable: &'msg ProxyVtable, |
| } |
| |
| impl<'msg> ViewProxy<'msg> for VtableProxiedMut<'msg> { |
| type Proxied = VtableProxied; |
| |
| fn as_view(&self) -> View<'_, VtableProxied> { |
| VtableProxiedView::read(self.msg, self.vtable) |
| } |
| |
| fn into_view<'shorter>(self) -> View<'shorter, VtableProxied> |
| where |
| 'msg: 'shorter, |
| { |
| VtableProxiedView::read(self.msg, self.vtable) |
| } |
| } |
| |
| impl<'msg> MutProxy<'msg> for VtableProxiedMut<'msg> { |
| fn as_mut(&mut self) -> Mut<'_, VtableProxied> { |
| VtableProxiedMut { msg: self.msg, vtable: self.vtable } |
| } |
| |
| fn into_mut<'shorter>(self) -> Mut<'shorter, VtableProxied> |
| where |
| 'msg: 'shorter, |
| { |
| self |
| } |
| } |
| |
| impl SettableValue<VtableProxied> for View<'_, VtableProxied> { |
| fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, VtableProxied>) |
| where |
| VtableProxied: 'msg, |
| { |
| SettableValue::<VtableProxied>::set_on(self.val(), Private, mutator) |
| } |
| |
| fn set_on_absent<'msg>( |
| self, |
| _private: Private, |
| absent_mutator: <VtableProxied as ProxiedWithPresence>::AbsentMutData<'msg>, |
| ) -> <VtableProxied as ProxiedWithPresence>::PresentMutData<'msg> { |
| SettableValue::<VtableProxied>::set_on_absent(self.val(), Private, absent_mutator) |
| } |
| } |
| |
| impl SettableValue<VtableProxied> for i32 { |
| fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, VtableProxied>) |
| where |
| VtableProxied: 'msg, |
| { |
| (mutator.vtable.set)(mutator.msg, self) |
| } |
| |
| fn set_on_absent<'msg>( |
| self, |
| _private: Private, |
| absent_mutator: <VtableProxied as ProxiedWithPresence>::AbsentMutData<'msg>, |
| ) -> <VtableProxied as ProxiedWithPresence>::PresentMutData<'msg> { |
| (absent_mutator.vtable.set)(absent_mutator.msg, self); |
| absent_mutator |
| } |
| } |
| |
| #[test] |
| fn test_field_entry() { |
| use googletest::prelude::*; |
| let mut m1 = MyMessage::default(); |
| let mut m2 = MyMessage::default(); |
| |
| let mut m1_a = m1.a_mut(); |
| assert_that!(m1_a, matches_pattern!(Optional::Unset(_))); |
| |
| assert_that!(m1_a.as_view().val(), eq(0)); |
| |
| assert_that!(m2.b().val(), eq(5)); |
| |
| let mut m2_b = m2.b_mut(); |
| assert_that!(m2_b.is_unset(), eq(true)); |
| assert_that!(m2_b.as_view().val(), eq(5)); |
| |
| m2_b.set(10); |
| assert_that!(m2_b.is_set(), eq(true)); |
| assert_that!(m2_b, matches_pattern!(Optional::Set(_))); |
| assert_that!(m2_b.as_view().val(), eq(10)); |
| |
| assert_that!(m1_a.or_default().as_view().val(), eq(0)); |
| assert_that!(m1.a_opt(), eq(Optional::Set(VtableProxiedView { val: 0 }))); |
| m1.a_mut().clear(); |
| |
| assert_that!(m1.a().val(), eq(0)); |
| assert_that!(m1.b().val(), eq(5)); |
| assert_that!(m2.a().val(), eq(0)); |
| assert_that!(m2.b().val(), eq(10)); |
| } |
| |
| #[test] |
| fn test_or_set() { |
| use googletest::prelude::*; |
| let mut m1 = MyMessage::default(); |
| let mut m2 = MyMessage::default(); |
| |
| assert_that!(m1.a_mut().or_set(10).get().val(), eq(10)); |
| assert_that!(m1.a_opt(), eq(Optional::Set(VtableProxiedView { val: 10 }))); |
| assert_that!(m1.a_mut().or_set(20).get().val(), eq(10)); |
| assert_that!(m1.a_opt(), eq(Optional::Set(VtableProxiedView { val: 10 }))); |
| |
| assert_that!(m2.a_mut().or_set_with(|| m1.a().val() + m1.b().val()).get().val(), eq(15)); |
| assert_that!(m2.a_opt(), eq(Optional::Set(VtableProxiedView { val: 15 }))); |
| assert_that!(m2.a_mut().or_set_with(|| None::<i32>.unwrap()).get().val(), eq(15)); |
| assert_that!(m2.a_opt(), eq(Optional::Set(VtableProxiedView { val: 15 }))); |
| } |
| |
| #[test] |
| fn test_into_optional_view() { |
| use googletest::prelude::*; |
| let mut m1 = MyMessage::default(); |
| assert_that!( |
| m1.a_mut().into_optional_view(), |
| eq(Optional::Unset(VtableProxiedView { val: 0 })) |
| ); |
| m1.a_mut().set(10); |
| assert_that!( |
| m1.a_mut().into_optional_view(), |
| eq(Optional::Set(VtableProxiedView { val: 10 })) |
| ); |
| assert_that!( |
| m1.b_mut().into_optional_view(), |
| eq(Optional::Unset(VtableProxiedView { val: 5 })) |
| ); |
| } |
| |
| #[test] |
| fn test_try_into_mut() { |
| use googletest::prelude::*; |
| let mut m1 = MyMessage::default(); |
| assert_that!(m1.a_mut().try_into_mut().is_none(), eq(true)); |
| m1.a_mut().set(10); |
| let mut a_mut = m1.a_mut().try_into_mut().expect("field to be set"); |
| a_mut.set(20); |
| assert_that!(m1.a().val(), eq(20)); |
| } |
| |
| #[test] |
| fn test_present_field() { |
| use googletest::prelude::*; |
| let mut m = MyMessage::default(); |
| m.a_mut().set(10); |
| match m.a_mut() { |
| Optional::Set(mut present) => { |
| assert_that!(present.as_view().val(), eq(10)); |
| present.set(20); |
| assert_that!(present.as_view().val(), eq(20)); |
| present.into_mut().set(30); |
| } |
| Optional::Unset(_) => unreachable!(), |
| } |
| assert_that!(m.a_opt(), eq(Optional::Set(VtableProxiedView { val: 30 }))); |
| m.b_mut().set(20); |
| match m.b_mut() { |
| Optional::Set(present) => present.clear(), |
| Optional::Unset(_) => unreachable!(), |
| }; |
| assert_that!(m.b_opt(), eq(Optional::Unset(VtableProxiedView { val: 5 }))); |
| } |
| |
| #[test] |
| fn test_absent_field() { |
| use googletest::prelude::*; |
| let mut m = MyMessage::default(); |
| match m.a_mut() { |
| Optional::Set(_) => unreachable!(), |
| Optional::Unset(absent) => { |
| assert_that!(absent.as_view().val(), eq(0)); |
| absent.set(20); |
| } |
| } |
| assert_that!(m.a_opt(), eq(Optional::Set(VtableProxiedView { val: 20 }))); |
| match m.b_mut() { |
| Optional::Set(_) => unreachable!(), |
| Optional::Unset(absent) => { |
| assert_that!(absent.as_view().val(), eq(5)); |
| absent.set_default(); |
| } |
| } |
| assert_that!(m.b_opt(), eq(Optional::Set(VtableProxiedView { val: 5 }))); |
| } |
| } |