diff --git a/rust/BUILD b/rust/BUILD index 0e541069bf..7640ac98f3 100644 --- a/rust/BUILD +++ b/rust/BUILD @@ -50,6 +50,7 @@ rust_library( name = "protobuf_upb", srcs = [ "internal.rs", + "optional.rs", "proxied.rs", "shared.rs", "upb.rs", @@ -85,6 +86,7 @@ rust_library( srcs = [ "cpp.rs", "internal.rs", + "optional.rs", "proxied.rs", "shared.rs", ], diff --git a/rust/optional.rs b/rust/optional.rs new file mode 100644 index 0000000000..b5b4169760 --- /dev/null +++ b/rust/optional.rs @@ -0,0 +1,286 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//! Items specific to `optional` fields. +#![allow(dead_code)] +#![allow(unused)] + +use crate::{Mut, MutProxy, Proxied, 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 = (std::marker::PhantomData, std::convert::Infallible); + +/// 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 present. It can be accessed through this `T`. + /// + /// - For an `_opt()` accessor, this contains a `View`. + /// - For a `_mut()` accessor, this contains a [`PresentField`]. + Set(SetVal), + + /// The field is unset. + /// + /// - 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, + } + } +} + +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<'a, T> = Optional, 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> { + // 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(), + } + } + + /// Sets the value of this field to `val`. + /// + /// Equivalent to `self.or_default().set(val)`. + pub fn set(&mut self, val: Todo) { + todo!("b/285308646: Requires a trait method") + } + + /// 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() + } +} + +impl<'msg, T: Proxied + ?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: Proxied + ?Sized + 'msg, +{ + inner: Todo>, +} + +impl<'msg, T: Proxied + ?Sized + 'msg> Debug for PresentField<'msg, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + todo!() + } +} + +impl<'msg, T: Proxied + ?Sized + 'msg> PresentField<'msg, T> { + pub fn get(self) -> View<'msg, T> { + self.into_view() + } + + pub fn set(&mut self, val: Todo) { + todo!("b/285308646: Requires a trait method") + } + + /// See [`FieldEntry::clear`]. + pub fn clear(self) -> AbsentField<'msg, T> { + todo!("b/285308646: Requires a trait method") + } + + // 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: Proxied + ?Sized + 'msg, +{ + type Proxied = T; + + fn as_view(&self) -> View<'_, T> { + todo!("b/285308646: Requires a trait method") + } + + fn into_view<'shorter>(self) -> View<'shorter, T> + where + 'msg: 'shorter, + { + todo!("b/285308646: Requires a trait method") + } +} + +impl<'msg, T> MutProxy<'msg> for PresentField<'msg, T> +where + T: Proxied + ?Sized + 'msg, +{ + fn as_mut(&mut self) -> Mut<'_, T> { + todo!("b/285308646: Requires a trait method") + } + + fn into_mut<'shorter>(self) -> Mut<'shorter, T> + where + 'msg: 'shorter, + { + todo!("b/285308646: Requires a trait method") + } +} + +/// A field mutator capable of setting that is statically known to point to a +/// non-set field. +pub struct AbsentField<'a, T> +where + T: Proxied + ?Sized + 'a, +{ + inner: Todo>>, +} + +impl<'msg, T: Proxied + ?Sized + 'msg> Debug for AbsentField<'msg, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + todo!() + } +} + +impl<'msg, T: Proxied + ?Sized> AbsentField<'msg, T> { + /// Gets the default value for this unset field. + /// + /// This is the same value that the primitive accessor would provide. + pub fn default_value(self) -> View<'msg, T> { + self.into_view() + } + + /// See [`FieldEntry::set`]. Note that this consumes and returns a + /// `PresentField`. + pub fn set(self, val: Todo) -> PresentField<'msg, T> { + todo!("b/285308646: Requires a trait method") + } + + /// Sets this absent field to its default value. + pub fn set_default(self) -> PresentField<'msg, T> { + todo!("b/285308646: Requires a trait method") + } + + // 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: Proxied + ?Sized + 'msg, +{ + type Proxied = T; + + fn as_view(&self) -> View<'_, T> { + todo!("b/285308646: Requires a trait method") + } + + fn into_view<'shorter>(self) -> View<'shorter, T> + where + 'msg: 'shorter, + { + todo!("b/285308646: Requires a trait method") + } +} diff --git a/rust/shared.rs b/rust/shared.rs index 64bedabf67..aab8693ebc 100644 --- a/rust/shared.rs +++ b/rust/shared.rs @@ -43,8 +43,10 @@ pub mod __runtime; #[path = "upb.rs"] pub mod __runtime; +mod optional; mod proxied; +pub use optional::{AbsentField, FieldEntry, Optional, PresentField}; pub use proxied::{Mut, MutProxy, Proxied, View, ViewProxy}; /// Everything in `__internal` is allowed to change without it being considered