Rust: make generated views implement `std::default::Default`

The immediate motivation for this is that it will facilitate writing a blanket
implementation of `ProxiedInMapValue` for C++-backed messages. The default
instance gives us access to the message vtable in cases where we don't already
have a message to work with.

However, it also seems generally useful just to have an implementation of
`Default`, so I implemented it for both C++ and upb-backed message views.

PiperOrigin-RevId: 677808048
pull/18436/head
Adam Cozzette 6 months ago committed by Copybara-Service
parent 63fc32250a
commit 6f5b35be59
  1. 2
      rust/codegen_traits.rs
  2. 7
      rust/test/shared/serialization_test.rs
  3. 25
      src/google/protobuf/compiler/rust/message.cc

@ -37,7 +37,7 @@ pub trait Message: SealedInternal
pub trait MessageView<'msg>: SealedInternal
+ ViewProxy<'msg, Proxied = Self::Message>
// Read traits:
+ Debug + Serialize
+ Debug + Serialize + Default
// Thread safety:
+ Send + Sync
// Copy/Clone:

@ -7,6 +7,7 @@
use googletest::prelude::*;
use protobuf::prelude::*;
use protobuf::View;
use edition_unittest_rust_proto::TestAllTypes as TestAllTypesEditions;
use paste::paste;
@ -31,6 +32,12 @@ macro_rules! generate_parameterized_serialization_test {
assert_that!(serialized.len(), eq(0));
}
#[gtest]
fn [< serialize_default_view $name_ext>]() {
let default = View::<[< $type >]>::default();
assert_that!(default.serialize().unwrap().len(), eq(0));
}
#[gtest]
fn [< serialize_deserialize_message_ $name_ext>]() {
let mut msg = [< $type >]::new();

@ -195,6 +195,7 @@ void CppMessageExterns(Context& ctx, const Descriptor& msg) {
ABSL_CHECK(ctx.is_cpp());
ctx.Emit(
{{"new_thunk", ThunkName(ctx, msg, "new")},
{"default_instance_thunk", ThunkName(ctx, msg, "default_instance")},
{"repeated_new_thunk", ThunkName(ctx, msg, "repeated_new")},
{"repeated_free_thunk", ThunkName(ctx, msg, "repeated_free")},
{"repeated_len_thunk", ThunkName(ctx, msg, "repeated_len")},
@ -207,6 +208,7 @@ void CppMessageExterns(Context& ctx, const Descriptor& msg) {
{"map_size_info_thunk", ThunkName(ctx, msg, "size_info")}},
R"rs(
fn $new_thunk$() -> $pbr$::RawMessage;
fn $default_instance_thunk$() -> $pbr$::RawMessage;
fn $repeated_new_thunk$() -> $pbr$::RawRepeatedField;
fn $repeated_free_thunk$(raw: $pbr$::RawRepeatedField);
fn $repeated_len_thunk$(raw: $pbr$::RawRepeatedField) -> usize;
@ -733,6 +735,16 @@ void MessageProxiedInMapValue(Context& ctx, const Descriptor& msg) {
}
}
void GenerateDefaultInstanceImpl(Context& ctx, const Descriptor& msg) {
if (ctx.is_upb()) {
ctx.Emit("$pbr$::ScratchSpace::zeroed_block()");
} else {
ctx.Emit(
{{"default_instance_thunk", ThunkName(ctx, msg, "default_instance")}},
"unsafe { $default_instance_thunk$() }");
}
}
} // namespace
void GenerateRs(Context& ctx, const Descriptor& msg) {
@ -749,6 +761,8 @@ void GenerateRs(Context& ctx, const Descriptor& msg) {
{"Msg::drop", [&] { MessageDrop(ctx, msg); }},
{"Msg::debug", [&] { MessageDebug(ctx, msg); }},
{"MsgMut::merge_from", [&] { MessageMutMergeFrom(ctx, msg); }},
{"default_instance_impl",
[&] { GenerateDefaultInstanceImpl(ctx, msg); }},
{"accessor_fns",
[&] {
for (int i = 0; i < msg.field_count(); ++i) {
@ -948,6 +962,12 @@ void GenerateRs(Context& ctx, const Descriptor& msg) {
}
}
impl $std$::default::Default for $Msg$View<'_> {
fn default() -> $Msg$View<'static> {
$Msg$View::new($pbi$::Private, $default_instance_impl$)
}
}
#[allow(dead_code)]
impl<'msg> $Msg$View<'msg> {
#[doc(hidden)]
@ -1367,6 +1387,7 @@ void GenerateThunksCc(Context& ctx, const Descriptor& msg) {
{"Msg", RsSafeName(msg.name())},
{"QualifiedMsg", cpp::QualifiedClassName(&msg)},
{"new_thunk", ThunkName(ctx, msg, "new")},
{"default_instance_thunk", ThunkName(ctx, msg, "default_instance")},
{"repeated_new_thunk", ThunkName(ctx, msg, "repeated_new")},
{"repeated_free_thunk", ThunkName(ctx, msg, "repeated_free")},
{"repeated_len_thunk", ThunkName(ctx, msg, "repeated_len")},
@ -1403,6 +1424,10 @@ void GenerateThunksCc(Context& ctx, const Descriptor& msg) {
extern $abi$ {
void* $new_thunk$() { return new $QualifiedMsg$(); }
const google::protobuf::MessageLite* $default_instance_thunk$() {
return &$QualifiedMsg$::default_instance();
}
void* $repeated_new_thunk$() {
return new google::protobuf::RepeatedPtrField<$QualifiedMsg$>();
}

Loading…
Cancel
Save