Also emit the oneof accessors into $Msg$Mut and $Msg$View

PiperOrigin-RevId: 599199864
pull/15460/head
Protobuf Team Bot 1 year ago committed by Copybara-Service
parent 50d0421170
commit 4773c091d2
  1. 62
      rust/test/shared/accessors_test.rs
  2. 1
      src/google/protobuf/compiler/rust/BUILD.bazel
  3. 144
      src/google/protobuf/compiler/rust/message.cc
  4. 49
      src/google/protobuf/compiler/rust/oneof.cc
  5. 4
      src/google/protobuf/compiler/rust/oneof.h

@ -820,9 +820,10 @@ fn test_default_import_enum_accessors() {
#[test]
fn test_oneof_accessors() {
use unittest_proto::proto2_unittest::TestOneof2;
use unittest_proto::proto2_unittest::TestOneof2_::{Foo::*, NestedEnum};
let mut msg = unittest_proto::proto2_unittest::TestOneof2::new();
let mut msg = TestOneof2::new();
assert_that!(msg.foo(), matches_pattern!(not_set(_)));
msg.foo_int_mut().set(7);
@ -842,7 +843,20 @@ fn test_oneof_accessors() {
msg.foo_enum_mut().set(NestedEnum::Foo);
assert_that!(msg.foo(), matches_pattern!(FooEnum(eq(NestedEnum::Foo))));
// TODO: Add oneof message tests
// Test the accessors or $Msg$Mut
let mut msg_mut = msg.as_mut();
assert_that!(msg_mut.foo(), matches_pattern!(FooEnum(eq(NestedEnum::Foo))));
msg_mut.foo_int_mut().set(7);
msg_mut.foo_bytes_mut().set(b"123");
assert_that!(msg_mut.foo(), matches_pattern!(FooBytes(eq(b"123"))));
assert_that!(msg_mut.foo_int_opt(), eq(Optional::Unset(0)));
// Test the accessors on $Msg$View
let msg_view = msg.as_view();
assert_that!(msg_view.foo(), matches_pattern!(FooBytes(eq(b"123"))));
assert_that!(msg_view.foo_int_opt(), eq(Optional::Unset(0)));
// TODO: Add tests covering a message-type field in a oneof.
}
#[test]
@ -878,11 +892,23 @@ fn test_oneof_mut_accessors() {
msg.foo_enum_mut().set(NestedEnum::Baz);
assert_that!(msg.foo_mut(), matches_pattern!(FooEnum(_)));
// TODO: Add oneof message tests
// Test the mut accessors or $Msg$Mut
let mut msg_mut = msg.as_mut();
match msg_mut.foo_mut() {
FooEnum(mut v) => {
assert_that!(v.get(), eq(NestedEnum::Baz));
v.set(NestedEnum::Bar);
assert_that!(v.get(), eq(NestedEnum::Bar));
}
f => panic!("unexpected field_mut type! {:?}", f),
}
assert_that!(msg.foo_enum(), eq(NestedEnum::Bar));
// TODO: Add tests covering a message-type field in a oneof.
}
#[test]
fn test_oneof_default_accessors() {
fn test_msg_oneof_default_accessors() {
use unittest_proto::proto2_unittest::TestOneof2_::{Bar::*, NestedEnum};
let mut msg = unittest_proto::proto2_unittest::TestOneof2::new();
@ -906,12 +932,12 @@ fn test_oneof_default_accessors() {
assert_that!(msg.bar(), matches_pattern!(BarEnum(eq(NestedEnum::Baz))));
assert_that!(msg.bar_int_opt(), eq(Optional::Unset(5)));
// TODO: Add oneof message tests
// TODO: Add tests covering a message-type field in a oneof.
}
#[test]
fn test_oneof_default_mut_accessors() {
use unittest_proto::proto2_unittest::TestOneof2_::{Bar, BarMut::*, NestedEnum};
use unittest_proto::proto2_unittest::TestOneof2_::{Bar, BarMut, BarMut::*, NestedEnum};
let mut msg = unittest_proto::proto2_unittest::TestOneof2::new();
assert_that!(msg.bar_mut(), matches_pattern!(not_set(_)));
@ -927,11 +953,29 @@ fn test_oneof_default_mut_accessors() {
f => panic!("unexpected field_mut type! {:?}", f),
}
// Confirm that the mut write above applies to both the field accessor and the
// oneof view accessor.
// Confirm that the mut write above applies to all three of:
// - The field accessor
// - The oneof mut accessor
// - The oneof view accessor
// And then each of the applicable cases on:
// - The owned msg directly
// - The msg as a $Msg$Mut
// - The msg as a $Msg$View
assert_that!(msg.bar_int_opt(), eq(Optional::Set(8)));
assert_that!(msg.bar_mut(), matches_pattern!(BarMut::BarInt(_)));
assert_that!(msg.bar(), matches_pattern!(Bar::BarInt(_)));
let mut msg_mut = msg.as_mut();
assert_that!(msg_mut.bar_int_opt(), eq(Optional::Set(8)));
assert_that!(msg_mut.bar_mut(), matches_pattern!(BarMut::BarInt(_)));
assert_that!(msg_mut.bar(), matches_pattern!(Bar::BarInt(_)));
let msg_view = msg.as_view();
assert_that!(msg_view.bar_int_opt(), eq(Optional::Set(8)));
// This test correctly fails to compile if this line is uncommented:
// assert_that!(msg_view.bar_mut(), matches_pattern!(BarMut::BarInt(_)));
assert_that!(msg_view.bar(), matches_pattern!(Bar::BarInt(_)));
msg.bar_int_mut().clear();
assert_that!(msg.bar_mut(), matches_pattern!(not_set(_)));
@ -942,7 +986,7 @@ fn test_oneof_default_mut_accessors() {
msg.bar_enum_mut().set(NestedEnum::Baz);
assert_that!(msg.bar_mut(), matches_pattern!(BarEnum(_)));
// TODO: Add oneof message tests
// TODO: Add tests covering a message-type field in a oneof.
}
#[test]

@ -211,6 +211,7 @@ cc_library(
copts = COPTS,
strip_include_prefix = "/src",
deps = [
":accessors",
":context",
":naming",
"//src/google/protobuf",

@ -220,47 +220,44 @@ void GenerateRs(Context& ctx, const Descriptor& msg) {
ABSL_LOG(WARNING) << "unsupported map field: " << msg.full_name();
return;
}
ctx.Emit({{"Msg", RsSafeName(msg.name())},
{"Msg::new", [&] { MessageNew(ctx, msg); }},
{"Msg::serialize", [&] { MessageSerialize(ctx, msg); }},
{"Msg::deserialize", [&] { MessageDeserialize(ctx, msg); }},
{"Msg::drop", [&] { MessageDrop(ctx, msg); }},
{"Msg_externs", [&] { MessageExterns(ctx, msg); }},
{"accessor_fns",
[&] {
for (int i = 0; i < msg.field_count(); ++i) {
GenerateAccessorMsgImpl(ctx, *msg.field(i),
AccessorCase::OWNED);
}
}},
{"oneof_accessor_fns",
[&] {
for (int i = 0; i < msg.real_oneof_decl_count(); ++i) {
GenerateOneofAccessors(ctx, *msg.real_oneof_decl(i));
}
}},
{"accessor_externs",
[&] {
for (int i = 0; i < msg.field_count(); ++i) {
GenerateAccessorExternC(ctx, *msg.field(i));
}
}},
{"oneof_externs",
[&] {
for (int i = 0; i < msg.real_oneof_decl_count(); ++i) {
GenerateOneofExternC(ctx, *msg.real_oneof_decl(i));
}
}},
{"nested_in_msg",
[&] {
// If we have no nested types, enums, or oneofs, bail out without
// emitting an empty mod SomeMsg_.
if (msg.nested_type_count() == 0 && msg.enum_type_count() == 0 &&
msg.real_oneof_decl_count() == 0) {
return;
}
ctx.Emit(
{{"Msg", RsSafeName(msg.name())},
ctx.Emit(
{{"Msg", RsSafeName(msg.name())},
{"Msg::new", [&] { MessageNew(ctx, msg); }},
{"Msg::serialize", [&] { MessageSerialize(ctx, msg); }},
{"Msg::deserialize", [&] { MessageDeserialize(ctx, msg); }},
{"Msg::drop", [&] { MessageDrop(ctx, msg); }},
{"Msg_externs", [&] { MessageExterns(ctx, msg); }},
{"accessor_fns",
[&] {
for (int i = 0; i < msg.field_count(); ++i) {
GenerateAccessorMsgImpl(ctx, *msg.field(i), AccessorCase::OWNED);
}
for (int i = 0; i < msg.real_oneof_decl_count(); ++i) {
GenerateOneofAccessors(ctx, *msg.real_oneof_decl(i),
AccessorCase::OWNED);
}
}},
{"accessor_externs",
[&] {
for (int i = 0; i < msg.field_count(); ++i) {
GenerateAccessorExternC(ctx, *msg.field(i));
}
}},
{"oneof_externs",
[&] {
for (int i = 0; i < msg.real_oneof_decl_count(); ++i) {
GenerateOneofExternC(ctx, *msg.real_oneof_decl(i));
}
}},
{"nested_in_msg",
[&] {
// If we have no nested types, enums, or oneofs, bail out without
// emitting an empty mod SomeMsg_.
if (msg.nested_type_count() == 0 && msg.enum_type_count() == 0 &&
msg.real_oneof_decl_count() == 0) {
return;
}
ctx.Emit({{"Msg", RsSafeName(msg.name())},
{"nested_msgs",
[&] {
for (int i = 0; i < msg.nested_type_count(); ++i) {
@ -288,42 +285,49 @@ void GenerateRs(Context& ctx, const Descriptor& msg) {
$oneofs$
} // mod $Msg$_
)rs");
}},
{"raw_arena_getter_for_message",
[&] {
if (ctx.is_upb()) {
ctx.Emit({}, R"rs(
}},
{"raw_arena_getter_for_message",
[&] {
if (ctx.is_upb()) {
ctx.Emit({}, R"rs(
fn arena(&self) -> &$pbr$::Arena {
&self.inner.arena
}
)rs");
}
}},
{"raw_arena_getter_for_msgmut",
[&] {
if (ctx.is_upb()) {
ctx.Emit({}, R"rs(
}
}},
{"raw_arena_getter_for_msgmut",
[&] {
if (ctx.is_upb()) {
ctx.Emit({}, R"rs(
fn arena(&self) -> &$pbr$::Arena {
self.inner.arena($pbi$::Private)
}
)rs");
}
}},
{"accessor_fns_for_views",
[&] {
for (int i = 0; i < msg.field_count(); ++i) {
GenerateAccessorMsgImpl(ctx, *msg.field(i),
AccessorCase::VIEW);
}
}},
{"accessor_fns_for_muts",
[&] {
for (int i = 0; i < msg.field_count(); ++i) {
GenerateAccessorMsgImpl(ctx, *msg.field(i), AccessorCase::MUT);
}
}},
{"settable_impl", [&] { MessageSettableValue(ctx, msg); }}},
R"rs(
}
}},
{"accessor_fns_for_views",
[&] {
for (int i = 0; i < msg.field_count(); ++i) {
GenerateAccessorMsgImpl(ctx, *msg.field(i), AccessorCase::VIEW);
}
for (int i = 0; i < msg.real_oneof_decl_count(); ++i) {
GenerateOneofAccessors(ctx, *msg.real_oneof_decl(i),
AccessorCase::VIEW);
}
}},
{"accessor_fns_for_muts",
[&] {
for (int i = 0; i < msg.field_count(); ++i) {
GenerateAccessorMsgImpl(ctx, *msg.field(i), AccessorCase::MUT);
}
for (int i = 0; i < msg.real_oneof_decl_count(); ++i) {
GenerateOneofAccessors(ctx, *msg.real_oneof_decl(i),
AccessorCase::MUT);
}
}},
{"settable_impl", [&] { MessageSettableValue(ctx, msg); }}},
R"rs(
#[allow(non_camel_case_types)]
//~ TODO: Implement support for debug redaction
#[derive(Debug)]
@ -480,8 +484,6 @@ void GenerateRs(Context& ctx, const Descriptor& msg) {
}
$accessor_fns$
$oneof_accessor_fns$
} // impl $Msg$
//~ We implement drop unconditionally, so that `$Msg$: Drop` regardless

@ -13,6 +13,7 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/descriptor.h"
@ -58,9 +59,15 @@ namespace rust {
// }
// }
// impl SomeMsg {
// pub fn some_oneof() -> SomeOneof {...}
// pub fn some_oneof_mut() -> SomeOneofMut {...}
// pub fn some_oneof(&self) -> SomeOneof {...}
// pub fn some_oneof_mut(&mut self) -> SomeOneofMut {...}
// }
// impl SomeMsgMut {
// pub fn some_oneof(&self) -> SomeOneof {...}
// pub fn some_oneof_mut(&mut self) -> SomeOneofMut {...}
// }
// impl SomeMsgView {
// pub fn some_oneof(&self) -> SomeOneof {...}
// }
//
// An additional "Case" enum which just reflects the corresponding slot numbers
@ -255,7 +262,8 @@ void GenerateOneofDefinition(Context& ctx, const OneofDescriptor& oneof) {
)rs");
}
void GenerateOneofAccessors(Context& ctx, const OneofDescriptor& oneof) {
void GenerateOneofAccessors(Context& ctx, const OneofDescriptor& oneof,
AccessorCase accessor_case) {
ctx.Emit(
{{"oneof_name", RsSafeName(oneof.name())},
{"view_enum_name", OneofViewEnumRsName(oneof)},
@ -319,22 +327,35 @@ void GenerateOneofAccessors(Context& ctx, const OneofDescriptor& oneof) {
)rs");
}
}},
{"case_thunk", ThunkName(ctx, oneof, "case")}},
R"rs(
pub fn $oneof_name$(&self) -> $Msg$_::$view_enum_name$ {
match unsafe { $case_thunk$(self.raw_msg()) } {
$view_cases$
_ => $Msg$_::$view_enum_name$::not_set(std::marker::PhantomData)
{"case_thunk", ThunkName(ctx, oneof, "case")},
{"getter",
[&] {
ctx.Emit({}, R"rs(
pub fn $oneof_name$(&self) -> $Msg$_::$view_enum_name$ {
match unsafe { $case_thunk$(self.raw_msg()) } {
$view_cases$
_ => $Msg$_::$view_enum_name$::not_set(std::marker::PhantomData)
}
}
}
pub fn $oneof_name$_mut(&mut self) -> $Msg$_::$mut_enum_name$ {
)rs");
}},
{"getter_mut",
[&] {
if (accessor_case == AccessorCase::VIEW) {
return;
}
ctx.Emit({}, R"rs(
pub fn $oneof_name$_mut(&mut self) -> $Msg$_::$mut_enum_name$ {
match unsafe { $case_thunk$(self.raw_msg()) } {
$mut_cases$
_ => $Msg$_::$mut_enum_name$::not_set(std::marker::PhantomData)
}
}
)rs");
}}},
R"rs(
$getter$
$getter_mut$
)rs");
}

@ -8,6 +8,7 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_RUST_ONEOF_H__
#define GOOGLE_PROTOBUF_COMPILER_RUST_ONEOF_H__
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/descriptor.h"
@ -17,7 +18,8 @@ namespace compiler {
namespace rust {
void GenerateOneofDefinition(Context& ctx, const OneofDescriptor& oneof);
void GenerateOneofAccessors(Context& ctx, const OneofDescriptor& oneof);
void GenerateOneofAccessors(Context& ctx, const OneofDescriptor& oneof,
AccessorCase accessor_case);
void GenerateOneofExternC(Context& ctx, const OneofDescriptor& oneof);
void GenerateOneofThunkCc(Context& ctx, const OneofDescriptor& oneof);

Loading…
Cancel
Save