Implement mutators for singular primitive fields without presence

PiperOrigin-RevId: 563043919
pull/13868/head
Adrian Sadłocha 1 year ago committed by Copybara-Service
parent dcc1f61973
commit 8c08df5a84
  1. 1
      rust/BUILD
  2. 1
      rust/cpp.rs
  3. 3
      rust/internal.rs
  4. 10
      rust/optional.rs
  5. 134
      rust/primitive.rs
  6. 2
      rust/shared.rs
  7. 24
      rust/test/shared/accessors_proto3_test.rs
  8. 1
      rust/upb.rs
  9. 45
      rust/vtable.rs
  10. 54
      src/google/protobuf/compiler/rust/accessors/singular_scalar.cc

@ -48,6 +48,7 @@ PROTOBUF_SHARED = [
"internal.rs",
"macros.rs",
"optional.rs",
"primitive.rs",
"proxied.rs",
"shared.rs",
"string.rs",

@ -159,6 +159,7 @@ impl fmt::Debug for SerializedData {
pub type BytesPresentMutData<'msg> = crate::vtable::RawVTableOptionalMutatorData<'msg, [u8]>;
pub type BytesAbsentMutData<'msg> = crate::vtable::RawVTableOptionalMutatorData<'msg, [u8]>;
pub type InnerBytesMut<'msg> = crate::vtable::RawVTableMutator<'msg, [u8]>;
pub type InnerPrimitiveMut<'a, T> = crate::vtable::RawVTableMutator<'a, T>;
/// The raw contents of every generated message.
#[derive(Debug)]

@ -33,7 +33,8 @@
//! generated code.
pub use crate::vtable::{
new_vtable_field_entry, BytesMutVTable, BytesOptionalMutVTable, RawVTableMutator,
new_vtable_field_entry, BytesMutVTable, BytesOptionalMutVTable, PrimitiveVTable,
RawVTableMutator,
};
use std::ptr::NonNull;
use std::slice;

@ -539,7 +539,11 @@ mod tests {
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)
SettableValue::<VtableProxied>::set_on_absent(
absent_mutator.as_view().val(),
Private,
absent_mutator,
)
}
}
@ -609,7 +613,7 @@ mod tests {
impl SettableValue<VtableProxied> for View<'_, VtableProxied> {
fn set_on(self, _private: Private, mutator: Mut<VtableProxied>) {
self.val().set_on(Private, mutator)
SettableValue::<VtableProxied>::set_on(self.val(), Private, mutator)
}
fn set_on_absent<'a>(
@ -617,7 +621,7 @@ mod tests {
_private: Private,
absent_mutator: <VtableProxied as ProxiedWithPresence>::AbsentMutData<'a>,
) -> <VtableProxied as ProxiedWithPresence>::PresentMutData<'a> {
self.val().set_on_absent(Private, absent_mutator)
SettableValue::<VtableProxied>::set_on_absent(self.val(), Private, absent_mutator)
}
}

@ -0,0 +1,134 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2023 Google LLC. 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 LLC. 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.
use crate::__internal::Private;
use crate::__runtime::InnerPrimitiveMut;
use crate::vtable::{PrimitiveVTable, ProxiedWithRawVTable};
use crate::{Mut, MutProxy, Proxied, SettableValue, View, ViewProxy};
#[derive(Debug)]
pub struct PrimitiveMut<'a, T: ProxiedWithRawVTable> {
inner: InnerPrimitiveMut<'a, T>,
}
impl<'a, T: ProxiedWithRawVTable> PrimitiveMut<'a, T> {
#[doc(hidden)]
pub fn from_inner(_private: Private, inner: InnerPrimitiveMut<'a, T>) -> Self {
Self { inner }
}
}
unsafe impl<'a, T: ProxiedWithRawVTable> Sync for PrimitiveMut<'a, T> {}
macro_rules! impl_singular_primitives {
($($t:ty),*) => {
$(
impl Proxied for $t {
type View<'a> = $t;
type Mut<'a> = PrimitiveMut<'a, $t>;
}
impl<'a> ViewProxy<'a> for $t {
type Proxied = $t;
fn as_view(&self) -> View<'_, Self::Proxied> {
*self
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied> {
self
}
}
impl<'a> ViewProxy<'a> for PrimitiveMut<'a, $t> {
type Proxied = $t;
fn as_view(&self) -> View<'_, Self::Proxied> {
self.get()
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied> {
self.get()
}
}
impl<'a> MutProxy<'a> for PrimitiveMut<'a, $t> {
fn as_mut(&mut self) -> Mut<'_, Self::Proxied> {
PrimitiveMut::from_inner(Private, self.inner)
}
fn into_mut<'shorter>(self) -> Mut<'shorter, Self::Proxied>
where 'a: 'shorter,
{
self
}
}
impl SettableValue<$t> for $t {
fn set_on(self, _private: Private, mutator: Mut<'_, $t>) {
unsafe { (mutator.inner).set(self) };
}
}
impl<'a> PrimitiveMut<'a, $t> {
pub fn set(&mut self, val: impl SettableValue<$t>) {
val.set_on(Private, self.as_mut());
}
pub fn get(&self) -> $t {
self.inner.get()
}
pub fn clear(&mut self) {
// The default value for a boolean field is false and 0 for numerical types. It
// matches the Rust default values for corresponding types. Let's use this fact.
SettableValue::<$t>::set_on(<$t>::default(), Private, MutProxy::as_mut(self));
}
}
impl ProxiedWithRawVTable for $t {
type VTable = PrimitiveVTable<$t>;
fn make_view(
_private: Private,
mut_inner: InnerPrimitiveMut<'_, Self>
) -> View<'_, Self> {
mut_inner.get()
}
fn make_mut(_private: Private, inner: InnerPrimitiveMut<'_, Self>) -> Mut<'_, Self> {
PrimitiveMut::from_inner(Private, inner)
}
}
)*
}
}
impl_singular_primitives!(bool, f32, f64, i32, i64, u32, u64);

@ -41,6 +41,7 @@ use std::fmt;
#[doc(hidden)]
pub mod __public {
pub use crate::optional::{AbsentField, FieldEntry, Optional, PresentField};
pub use crate::primitive::PrimitiveMut;
pub use crate::proxied::{
Mut, MutProxy, Proxied, ProxiedWithPresence, SettableValue, View, ViewProxy,
};
@ -66,6 +67,7 @@ pub mod __runtime;
mod macros;
mod optional;
mod primitive;
mod proxied;
mod string;
mod vtable;

@ -38,12 +38,30 @@ use unittest_proto3_optional::proto2_unittest::TestProto3Optional;
fn test_fixed32_accessors() {
let mut msg = TestAllTypes::new();
assert_eq!(msg.optional_fixed32(), 0);
assert_eq!(msg.optional_fixed32_mut().get(), 0);
msg.optional_fixed32_set(Some(99));
assert_eq!(msg.optional_fixed32(), 99);
msg.optional_fixed32_mut().set(42);
assert_eq!(msg.optional_fixed32_mut().get(), 42);
assert_eq!(msg.optional_fixed32(), 42);
msg.optional_fixed32_set(None);
msg.optional_fixed32_mut().clear();
assert_eq!(msg.optional_fixed32(), 0);
assert_eq!(msg.optional_fixed32_mut().get(), 0);
}
#[test]
fn test_bool_accessors() {
let mut msg = TestAllTypes::new();
assert!(!msg.optional_bool());
assert!(!msg.optional_bool_mut().get());
msg.optional_bool_mut().set(true);
assert!(msg.optional_bool());
assert!(msg.optional_bool_mut().get());
msg.optional_bool_mut().clear();
assert!(!msg.optional_bool());
assert!(!msg.optional_bool_mut().get());
}
#[test]

@ -204,6 +204,7 @@ impl fmt::Debug for SerializedData {
pub type BytesPresentMutData<'msg> = crate::vtable::RawVTableOptionalMutatorData<'msg, [u8]>;
pub type BytesAbsentMutData<'msg> = crate::vtable::RawVTableOptionalMutatorData<'msg, [u8]>;
pub type InnerBytesMut<'msg> = crate::vtable::RawVTableMutator<'msg, [u8]>;
pub type InnerPrimitiveMut<'a, T> = crate::vtable::RawVTableMutator<'a, T>;
/// The raw contents of every generated message.
#[derive(Debug)]

@ -273,6 +273,51 @@ impl ProxiedWithRawOptionalVTable for [u8] {
}
}
/// 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,
}
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 }
}
}
macro_rules! impl_raw_vtable_mutator_get_set {
($($t:ty),*) => {
$(
impl 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_raw_vtable_mutator_get_set!(bool, f32, f64, i32, i64, u32, u64);
/// A generic thunk vtable for mutating a present `bytes` or `string` field.
#[doc(hidden)]
#[derive(Debug)]

@ -58,6 +58,7 @@ void SingularScalar::InMsgImpl(Context<FieldDescriptor> field) const {
[&] {
if (!field.desc().is_optional()) return;
if (!field.desc().has_presence()) return;
// TODO(b/285309449): use Optional instead of Option
field.Emit({}, R"rs(
pub fn r#$field$_opt(&self) -> Option<$Scalar$> {
if !unsafe { $hazzer_thunk$(self.inner.msg) } {
@ -70,17 +71,56 @@ void SingularScalar::InMsgImpl(Context<FieldDescriptor> field) const {
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"field_setter",
[&] {
if (field.desc().has_presence()) {
field.Emit({}, R"rs(
pub fn r#$field$_set(&mut self, val: Option<$Scalar$>) {
match val {
Some(val) => unsafe { $setter_thunk$(self.inner.msg, val) },
None => unsafe { $clearer_thunk$(self.inner.msg) },
}
}
)rs");
}
}},
{"field_mutator_getter",
[&] {
if (field.desc().has_presence()) {
// TODO(b/285309449): implement mutator for fields with presence.
return;
} else {
field.Emit({}, R"rs(
pub fn r#$field$_mut(&mut self) -> $pb$::PrimitiveMut<'_, $Scalar$> {
static VTABLE: $pbi$::PrimitiveVTable<$Scalar$> =
$pbi$::PrimitiveVTable::new(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$,
);
$pb$::PrimitiveMut::from_inner(
$pbi$::Private,
unsafe {
$pbi$::RawVTableMutator::new(
$pbi$::Private,
$pbr$::MutatorMessageRef::new(
$pbi$::Private, &mut self.inner
),
&VTABLE,
)
},
)
}
)rs");
}
}},
},
R"rs(
$getter$
$getter_opt$
pub fn $field$_set(&mut self, val: Option<$Scalar$>) {
match val {
Some(val) => unsafe { $setter_thunk$(self.inner.msg, val) },
None => unsafe { $clearer_thunk$(self.inner.msg) },
}
}
$field_setter$
$field_mutator_getter$
)rs");
}

Loading…
Cancel
Save