// 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 { /// The field is set; it is present in the serialized message. /// /// - For an `_opt()` accessor, this contains a `View`. /// - 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` 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 Optional { /// 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` 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 Optional { /// Converts into an `Option` of the set value, ignoring any unset value. pub fn into_option(self) -> Option { 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 From> for Option { fn from(x: Optional) -> Option { 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, 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 Optional` /// 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) -> 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(self, val: impl FnOnce() -> S) -> Mut<'msg, T> where S: SettableValue, { 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) { 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> { 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> { 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) { 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) -> 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(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> { 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> { 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::::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 for View<'_, VtableProxied> { fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, VtableProxied>) where VtableProxied: 'msg, { SettableValue::::set_on(self.val(), Private, mutator) } fn set_on_absent<'msg>( self, _private: Private, absent_mutator: ::AbsentMutData<'msg>, ) -> ::PresentMutData<'msg> { SettableValue::::set_on_absent(self.val(), Private, absent_mutator) } } impl SettableValue 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: ::AbsentMutData<'msg>, ) -> ::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::.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 }))); } }