impl SettableValue for MsgView

For the cpp runtime, call the `Message::CopyFrom` method.

For the upb runtime, expose the message `MiniTable` and call `upb_Message_DeepCopy`.

PiperOrigin-RevId: 595166276
pull/15204/head
Kevin King 11 months ago committed by Copybara-Service
parent 569548cd82
commit 8876b1069f
  1. 14
      rust/test/shared/accessors_test.rs
  2. 26
      rust/upb.rs
  3. 1
      rust/upb_kernel/BUILD
  4. 3
      rust/upb_kernel/upb_api.c
  5. 64
      src/google/protobuf/compiler/rust/message.cc

@ -10,7 +10,7 @@
use googletest::prelude::*; use googletest::prelude::*;
use matchers::{is_set, is_unset}; use matchers::{is_set, is_unset};
use protobuf::Optional; use protobuf::Optional;
use unittest_proto::proto2_unittest::{TestAllTypes, TestAllTypes_}; use unittest_proto::proto2_unittest::{NestedTestAllTypes, TestAllTypes, TestAllTypes_};
#[test] #[test]
fn test_default_accessors() { fn test_default_accessors() {
@ -735,3 +735,15 @@ fn test_oneof_mut_accessors() {
msg.oneof_bytes_mut().set(b"123"); msg.oneof_bytes_mut().set(b"123");
assert_that!(msg.oneof_field_mut(), matches_pattern!(OneofBytes(_))); assert_that!(msg.oneof_field_mut(), matches_pattern!(OneofBytes(_)));
} }
#[test]
fn test_set_message_from_view() {
use protobuf::MutProxy;
let mut m1 = NestedTestAllTypes::new();
let mut m2 = NestedTestAllTypes::new();
m2.payload_mut().optional_int32_mut().set(1);
m1.payload_mut().set(m2.payload());
assert_that!(m1.payload().optional_int32(), eq(1));
}

@ -288,6 +288,10 @@ impl<'msg> MutatorMessageRef<'msg> {
pub fn msg(&self) -> RawMessage { pub fn msg(&self) -> RawMessage {
self.msg self.msg
} }
pub fn raw_arena(&self, _private: Private) -> RawArena {
self.arena.raw()
}
} }
pub fn copy_bytes_in_arena_if_needed_by_runtime<'msg>( pub fn copy_bytes_in_arena_if_needed_by_runtime<'msg>(
@ -308,6 +312,28 @@ pub fn copy_bytes_in_arena_if_needed_by_runtime<'msg>(
} }
} }
/// Opaque struct containing a upb_MiniTable.
///
/// This wrapper is a workaround until stabilization of [`extern type`].
/// TODO: convert to extern type once stabilized.
/// [`extern type`]: https://github.com/rust-lang/rust/issues/43467
#[repr(C)]
pub struct OpaqueMiniTable {
// TODO: consider importing a minitable struct declared in
// google3/third_party/upb/bits.
_data: [u8; 0],
_marker: std::marker::PhantomData<(*mut u8, ::std::marker::PhantomPinned)>,
}
extern "C" {
pub fn upb_Message_DeepCopy(
dst: RawMessage,
src: RawMessage,
mini_table: *const OpaqueMiniTable,
arena: RawArena,
);
}
/// The raw type-erased pointer version of `RepeatedMut`. /// The raw type-erased pointer version of `RepeatedMut`.
/// ///
/// Contains a `upb_Array*` as well as `RawArena`, most likely that of the /// Contains a `upb_Array*` as well as `RawArena`, most likely that of the

@ -10,5 +10,6 @@ cc_library(
deps = [ deps = [
"//upb:mem", "//upb:mem",
"//upb:message", "//upb:message",
"//upb:message_copy",
], ],
) )

@ -10,4 +10,5 @@
#include "upb/mem/arena.h" // IWYU pragma: keep #include "upb/mem/arena.h" // IWYU pragma: keep
#include "upb/message/array.h" // IWYU pragma: keep #include "upb/message/array.h" // IWYU pragma: keep
#include "upb/message/map.h" // IWYU pragma: keep #include "upb/message/copy.h" // IWYU pragma: keep
#include "upb/message/map.h" // IWYU pragma: keep

@ -7,6 +7,8 @@
#include "google/protobuf/compiler/rust/message.h" #include "google/protobuf/compiler/rust/message.h"
#include <string>
#include "absl/log/absl_check.h" #include "absl/log/absl_check.h"
#include "absl/log/absl_log.h" #include "absl/log/absl_log.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
@ -19,6 +21,7 @@
#include "google/protobuf/compiler/rust/naming.h" #include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/compiler/rust/oneof.h" #include "google/protobuf/compiler/rust/oneof.h"
#include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.h"
#include "upb_generator/mangle.h"
namespace google { namespace google {
namespace protobuf { namespace protobuf {
@ -26,6 +29,10 @@ namespace compiler {
namespace rust { namespace rust {
namespace { namespace {
std::string UpbMinitableName(const Descriptor& msg) {
return upb::generator::MessageInit(msg.full_name());
}
void MessageNew(Context& ctx, const Descriptor& msg) { void MessageNew(Context& ctx, const Descriptor& msg) {
switch (ctx.opts().kernel) { switch (ctx.opts().kernel) {
case Kernel::kCpp: case Kernel::kCpp:
@ -126,12 +133,14 @@ void MessageExterns(Context& ctx, const Descriptor& msg) {
{"delete_thunk", ThunkName(ctx, msg, "delete")}, {"delete_thunk", ThunkName(ctx, msg, "delete")},
{"serialize_thunk", ThunkName(ctx, msg, "serialize")}, {"serialize_thunk", ThunkName(ctx, msg, "serialize")},
{"deserialize_thunk", ThunkName(ctx, msg, "deserialize")}, {"deserialize_thunk", ThunkName(ctx, msg, "deserialize")},
{"copy_from_thunk", ThunkName(ctx, msg, "copy_from")},
}, },
R"rs( R"rs(
fn $new_thunk$() -> $pbi$::RawMessage; fn $new_thunk$() -> $pbi$::RawMessage;
fn $delete_thunk$(raw_msg: $pbi$::RawMessage); fn $delete_thunk$(raw_msg: $pbi$::RawMessage);
fn $serialize_thunk$(raw_msg: $pbi$::RawMessage) -> $pbr$::SerializedData; fn $serialize_thunk$(raw_msg: $pbi$::RawMessage) -> $pbr$::SerializedData;
fn $deserialize_thunk$(raw_msg: $pbi$::RawMessage, data: $pbr$::SerializedData) -> bool; fn $deserialize_thunk$(raw_msg: $pbi$::RawMessage, data: $pbr$::SerializedData) -> bool;
fn $copy_from_thunk$(dst: $pbi$::RawMessage, src: $pbi$::RawMessage);
)rs"); )rs");
return; return;
@ -141,11 +150,15 @@ void MessageExterns(Context& ctx, const Descriptor& msg) {
{"new_thunk", ThunkName(ctx, msg, "new")}, {"new_thunk", ThunkName(ctx, msg, "new")},
{"serialize_thunk", ThunkName(ctx, msg, "serialize")}, {"serialize_thunk", ThunkName(ctx, msg, "serialize")},
{"deserialize_thunk", ThunkName(ctx, msg, "parse")}, {"deserialize_thunk", ThunkName(ctx, msg, "parse")},
{"minitable", UpbMinitableName(msg)},
}, },
R"rs( R"rs(
fn $new_thunk$(arena: $pbi$::RawArena) -> $pbi$::RawMessage; fn $new_thunk$(arena: $pbi$::RawArena) -> $pbi$::RawMessage;
fn $serialize_thunk$(msg: $pbi$::RawMessage, arena: $pbi$::RawArena, len: &mut usize) -> $NonNull$<u8>; fn $serialize_thunk$(msg: $pbi$::RawMessage, arena: $pbi$::RawArena, len: &mut usize) -> $NonNull$<u8>;
fn $deserialize_thunk$(data: *const u8, size: usize, arena: $pbi$::RawArena) -> Option<$pbi$::RawMessage>; fn $deserialize_thunk$(data: *const u8, size: usize, arena: $pbi$::RawArena) -> Option<$pbi$::RawMessage>;
/// Opaque wrapper for this message's MiniTable. The only valid way to
/// reference this static is with `std::ptr::addr_of!(..)`.
static $minitable$: $pbr$::OpaqueMiniTable;
)rs"); )rs");
return; return;
} }
@ -169,6 +182,41 @@ bool IsStringOrBytes(FieldDescriptor::Type t) {
return t == FieldDescriptor::TYPE_STRING || t == FieldDescriptor::TYPE_BYTES; return t == FieldDescriptor::TYPE_STRING || t == FieldDescriptor::TYPE_BYTES;
} }
void MessageSettableValue(Context& ctx, const Descriptor& msg) {
switch (ctx.opts().kernel) {
case Kernel::kCpp:
ctx.Emit({{"copy_from_thunk", ThunkName(ctx, msg, "copy_from")}}, R"rs(
impl<'msg> $pb$::SettableValue<$Msg$> for $Msg$View<'msg> {
fn set_on<'dst>(
self, _private: $pbi$::Private, mutator: $pb$::Mut<'dst, $Msg$>)
where $Msg$: 'dst {
unsafe { $copy_from_thunk$(mutator.inner.msg(), self.msg) };
}
}
)rs");
return;
case Kernel::kUpb:
ctx.Emit({{"minitable", UpbMinitableName(msg)}}, R"rs(
impl<'msg> $pb$::SettableValue<$Msg$> for $Msg$View<'msg> {
fn set_on<'dst>(
self, _private: $pbi$::Private, mutator: $pb$::Mut<'dst, $Msg$>)
where $Msg$: 'dst {
unsafe { $pbr$::upb_Message_DeepCopy(
mutator.inner.msg(),
self.msg,
$std$::ptr::addr_of!($minitable$),
mutator.inner.raw_arena($pbi$::Private),
) };
}
}
)rs");
return;
}
ABSL_LOG(FATAL) << "unreachable";
}
void GetterForViewOrMut(Context& ctx, const FieldDescriptor& field, void GetterForViewOrMut(Context& ctx, const FieldDescriptor& field,
bool is_mut) { bool is_mut) {
auto fieldName = field.name(); auto fieldName = field.name();
@ -381,7 +429,8 @@ void GenerateRs(Context& ctx, const Descriptor& msg) {
{"accessor_fns_for_views", {"accessor_fns_for_views",
[&] { AccessorsForViewOrMut(ctx, msg, false); }}, [&] { AccessorsForViewOrMut(ctx, msg, false); }},
{"accessor_fns_for_muts", {"accessor_fns_for_muts",
[&] { AccessorsForViewOrMut(ctx, msg, true); }}}, [&] { AccessorsForViewOrMut(ctx, msg, true); }},
{"settable_impl", [&] { MessageSettableValue(ctx, msg); }}},
R"rs( R"rs(
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
// TODO: Implement support for debug redaction // TODO: Implement support for debug redaction
@ -437,13 +486,7 @@ void GenerateRs(Context& ctx, const Descriptor& msg) {
} }
} }
impl<'a> $pb$::SettableValue<$Msg$> for $Msg$View<'a> { $settable_impl$
fn set_on<'b>(self, _private: $pb$::__internal::Private, _mutator: $pb$::Mut<'b, $Msg$>)
where
$Msg$: 'b {
todo!()
}
}
#[derive(Debug)] #[derive(Debug)]
#[allow(dead_code)] #[allow(dead_code)]
@ -556,6 +599,7 @@ void GenerateThunksCc(Context& ctx, const Descriptor& msg) {
{"delete_thunk", ThunkName(ctx, msg, "delete")}, {"delete_thunk", ThunkName(ctx, msg, "delete")},
{"serialize_thunk", ThunkName(ctx, msg, "serialize")}, {"serialize_thunk", ThunkName(ctx, msg, "serialize")},
{"deserialize_thunk", ThunkName(ctx, msg, "deserialize")}, {"deserialize_thunk", ThunkName(ctx, msg, "deserialize")},
{"copy_from_thunk", ThunkName(ctx, msg, "copy_from")},
{"nested_msg_thunks", {"nested_msg_thunks",
[&] { [&] {
for (int i = 0; i < msg.nested_type_count(); ++i) { for (int i = 0; i < msg.nested_type_count(); ++i) {
@ -590,6 +634,10 @@ void GenerateThunksCc(Context& ctx, const Descriptor& msg) {
return msg->ParseFromArray(data.data, data.len); return msg->ParseFromArray(data.data, data.len);
} }
void $copy_from_thunk$($QualifiedMsg$* dst, const $QualifiedMsg$* src) {
dst->CopyFrom(*src);
}
$accessor_thunks$ $accessor_thunks$
$oneof_thunks$ $oneof_thunks$

Loading…
Cancel
Save