Skip to content

Commit 4c83348

Browse files
ClaytonKnittelcopybara-github
authored andcommitted
Emit proxy repeated field accessors for repeated enum fields when enabled.
Repeated enum fields annotated with `[features.(pb.cpp).repeated_type = PROXY]` will be given proxy-based accessors instead of returning pointers/references to `RepeatedField` directly. This feature is currently only available in edition `UNSTABLE`. PiperOrigin-RevId: 892488797
1 parent f54e9a1 commit 4c83348

5 files changed

Lines changed: 155 additions & 25 deletions

File tree

src/google/protobuf/compiler/cpp/field_generators/enum_field.cc

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ class RepeatedEnum : public FieldGeneratorBase {
221221
opts_(&opts),
222222
has_cached_size_(field_->is_packed() &&
223223
HasGeneratedMethods(field_->file(), opts) &&
224-
!should_split()) {}
224+
!should_split()),
225+
cpp_repeated_type_(CalculateFieldDescriptorRepeatedType(field)) {}
225226
~RepeatedEnum() override = default;
226227

227228
std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); }
@@ -377,6 +378,7 @@ class RepeatedEnum : public FieldGeneratorBase {
377378
private:
378379
const Options* opts_;
379380
bool has_cached_size_;
381+
FieldDescriptor::CppRepeatedType cpp_repeated_type_;
380382
};
381383

382384
void RepeatedEnum::GenerateAccessorDeclarations(io::Printer* p) const {
@@ -387,13 +389,31 @@ void RepeatedEnum::GenerateAccessorDeclarations(io::Printer* p) const {
387389
auto vm =
388390
p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
389391

390-
p->Emit(R"cc(
392+
auto decl_field_accessors = [&] {
393+
switch (cpp_repeated_type_) {
394+
case FieldDescriptor::CppRepeatedType::kRepeated:
395+
p->Emit(R"cc(
396+
[[nodiscard]] $DEPRECATED$ const $pb$::RepeatedField<int>& $name$()
397+
const;
398+
[[nodiscard]] $DEPRECATED$ $pb$::RepeatedField<int>* $nonnull$ $mutable_name$();
399+
)cc");
400+
break;
401+
case FieldDescriptor::CppRepeatedType::kProxy:
402+
p->Emit(R"cc(
403+
[[nodiscard]] $DEPRECATED$ $pb$::RepeatedFieldProxy<const int>
404+
$name$() const;
405+
[[nodiscard]] $DEPRECATED$ $pb$::RepeatedFieldProxy<int> $mutable_name$();
406+
)cc");
407+
break;
408+
}
409+
};
410+
411+
p->Emit({{"decl_field_accessors", decl_field_accessors}}, R"cc(
391412
public:
392413
[[nodiscard]] $DEPRECATED$ $Enum$ $name$(int index) const;
393414
$DEPRECATED$ void $set_name$(int index, $Enum$ value);
394415
$DEPRECATED$ void $add_name$($Enum$ value);
395-
[[nodiscard]] $DEPRECATED$ const $pb$::RepeatedField<int>& $name$() const;
396-
[[nodiscard]] $DEPRECATED$ $pb$::RepeatedField<int>* $nonnull$ $mutable_name$();
416+
$decl_field_accessors$;
397417
398418
private:
399419
const $pb$::RepeatedField<int>& $_internal_name$() const;
@@ -437,26 +457,55 @@ void RepeatedEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
437457
// @@protoc_insertion_point(field_add:$pkg.Msg.field$)
438458
}
439459
)cc");
440-
p->Emit(R"cc(
441-
inline const $pb$::RepeatedField<int>& $Msg$::$name$() const
442-
ABSL_ATTRIBUTE_LIFETIME_BOUND {
443-
$WeakDescriptorSelfPin$;
444-
$annotate_list$;
445-
// @@protoc_insertion_point(field_list:$pkg.Msg.field$)
446-
return _internal_$name_internal$();
447-
}
448-
)cc");
449-
p->Emit(R"cc(
450-
inline $pb$::RepeatedField<int>* $nonnull$ $Msg$::mutable_$name$()
451-
ABSL_ATTRIBUTE_LIFETIME_BOUND {
452-
$WeakDescriptorSelfPin$;
453-
$set_hasbit$;
454-
$annotate_mutable_list$;
455-
// @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$)
456-
$TsanDetectConcurrentMutation$;
457-
return _internal_mutable_$name_internal$();
458-
}
459-
)cc");
460+
switch (cpp_repeated_type_) {
461+
case FieldDescriptor::CppRepeatedType::kRepeated:
462+
p->Emit(R"cc(
463+
inline const $pb$::RepeatedField<int>& $Msg$::$name$() const
464+
ABSL_ATTRIBUTE_LIFETIME_BOUND {
465+
$WeakDescriptorSelfPin$;
466+
$annotate_list$;
467+
// @@protoc_insertion_point(field_list:$pkg.Msg.field$)
468+
return _internal_$name_internal$();
469+
}
470+
)cc");
471+
p->Emit(R"cc(
472+
inline $pb$::RepeatedField<int>* $nonnull$ $Msg$::mutable_$name$()
473+
ABSL_ATTRIBUTE_LIFETIME_BOUND {
474+
$WeakDescriptorSelfPin$;
475+
$set_hasbit$;
476+
$annotate_mutable_list$;
477+
// @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$)
478+
$TsanDetectConcurrentMutation$;
479+
return _internal_mutable_$name_internal$();
480+
}
481+
)cc");
482+
break;
483+
case FieldDescriptor::CppRepeatedType::kProxy:
484+
p->Emit(R"cc(
485+
inline $pb$::RepeatedFieldProxy<const int> $Msg$::$name$() const
486+
ABSL_ATTRIBUTE_LIFETIME_BOUND {
487+
$WeakDescriptorSelfPin$;
488+
$annotate_list$;
489+
// @@protoc_insertion_point(field_list:$pkg.Msg.field$)
490+
return $pbi$::RepeatedFieldProxyInternalPrivateAccessHelper<
491+
const int>::Construct(_internal_$name_internal$());
492+
}
493+
)cc");
494+
p->Emit(R"cc(
495+
inline $pb$::RepeatedFieldProxy<int> $Msg$::mutable_$name$()
496+
ABSL_ATTRIBUTE_LIFETIME_BOUND {
497+
$WeakDescriptorSelfPin$;
498+
$set_hasbit$;
499+
$annotate_mutable_list$;
500+
// @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$)
501+
$TsanDetectConcurrentMutation$;
502+
return $pbi$::RepeatedFieldProxyInternalPrivateAccessHelper<
503+
int>::Construct(*_internal_mutable_$name_internal$(), GetArena());
504+
}
505+
)cc");
506+
break;
507+
}
508+
460509
if (should_split()) {
461510
p->Emit(R"cc(
462511
inline const $pb$::RepeatedField<int>& $Msg$::_internal_$name_internal$()

src/google/protobuf/descriptor.pb.h

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/google/protobuf/repeated_field_proxy_test.cc

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ namespace protobuf {
3333
namespace internal {
3434
namespace {
3535

36+
using ::proto2_unittest::RepeatedFieldProxyTestImportEnum;
3637
using ::proto2_unittest::RepeatedFieldProxyTestSimpleMessage;
38+
using ::proto2_unittest::TestRepeatedEnumProxy;
39+
using ::proto2_unittest::TestRepeatedImportEnumProxy;
3740
using ::proto2_unittest::TestRepeatedImportMessageProxy;
3841
using ::proto2_unittest::TestRepeatedIntProxy;
3942
using ::proto2_unittest::TestRepeatedMessageProxy;
@@ -2323,6 +2326,21 @@ static_assert(std::is_same_v<decltype(std::declval<TestRepeatedIntProxy>()
23232326
.mutable_ints_proxy()),
23242327
RepeatedFieldProxy<int32_t>>);
23252328

2329+
// Repeated enums:
2330+
static_assert(
2331+
std::is_same_v<decltype(std::declval<TestRepeatedEnumProxy>().enums()),
2332+
const RepeatedField<int>&>);
2333+
static_assert(std::is_same_v<
2334+
decltype(std::declval<TestRepeatedEnumProxy>().mutable_enums()),
2335+
RepeatedField<int>*>);
2336+
2337+
static_assert(std::is_same_v<
2338+
decltype(std::declval<TestRepeatedEnumProxy>().enums_proxy()),
2339+
RepeatedFieldProxy<const int>>);
2340+
static_assert(std::is_same_v<decltype(std::declval<TestRepeatedEnumProxy>()
2341+
.mutable_enums_proxy()),
2342+
RepeatedFieldProxy<int>>);
2343+
23262344
TEST(RepeatedFieldProxyInterfaceTest, RepeatedMessageProxy) {
23272345
TestRepeatedMessageProxy msg;
23282346
{
@@ -2366,6 +2384,42 @@ TEST(RepeatedFieldProxyInterfaceTest, RepeatedIntProxy) {
23662384
EXPECT_THAT(proxy, ElementsAre(1, 2, 3));
23672385
}
23682386

2387+
TEST(RepeatedFieldProxyInterfaceTest, RepeatedEnumProxy) {
2388+
TestRepeatedEnumProxy msg;
2389+
{
2390+
auto proxy = msg.mutable_enums_proxy();
2391+
proxy.push_back(TestRepeatedEnumProxy::FOO);
2392+
proxy.push_back(TestRepeatedEnumProxy::BAR);
2393+
proxy.push_back(TestRepeatedEnumProxy::BAZ);
2394+
}
2395+
2396+
auto proxy = msg.enums_proxy();
2397+
EXPECT_THAT(
2398+
proxy, ElementsAre(TestRepeatedEnumProxy::FOO, TestRepeatedEnumProxy::BAR,
2399+
TestRepeatedEnumProxy::BAZ));
2400+
}
2401+
2402+
TEST(RepeatedFieldProxyInterfaceTest, RepeatedImportEnumProxy) {
2403+
TestRepeatedImportEnumProxy msg;
2404+
{
2405+
auto proxy = msg.mutable_enums_proxy();
2406+
proxy.push_back(
2407+
RepeatedFieldProxyTestImportEnum::REPEATED_FIELD_PROXY_TEST_IMPORT_FOO);
2408+
proxy.push_back(
2409+
RepeatedFieldProxyTestImportEnum::REPEATED_FIELD_PROXY_TEST_IMPORT_BAR);
2410+
proxy.push_back(
2411+
RepeatedFieldProxyTestImportEnum::REPEATED_FIELD_PROXY_TEST_IMPORT_BAZ);
2412+
}
2413+
2414+
auto proxy = msg.enums_proxy();
2415+
EXPECT_THAT(proxy, ElementsAre(RepeatedFieldProxyTestImportEnum::
2416+
REPEATED_FIELD_PROXY_TEST_IMPORT_FOO,
2417+
RepeatedFieldProxyTestImportEnum::
2418+
REPEATED_FIELD_PROXY_TEST_IMPORT_BAR,
2419+
RepeatedFieldProxyTestImportEnum::
2420+
REPEATED_FIELD_PROXY_TEST_IMPORT_BAZ));
2421+
}
2422+
23692423
} // namespace
23702424
} // namespace internal
23712425
} // namespace protobuf

src/google/protobuf/test_protos/repeated_field_proxy_import_message.proto

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,10 @@ package proto2_unittest;
55
message RepeatedFieldProxyTestImportMessage {
66
int32 value = 1;
77
}
8+
9+
enum RepeatedFieldProxyTestImportEnum {
10+
REPEATED_FIELD_PROXY_TEST_IMPORT_ENUM_UNKNOWN = 0;
11+
REPEATED_FIELD_PROXY_TEST_IMPORT_FOO = 1;
12+
REPEATED_FIELD_PROXY_TEST_IMPORT_BAR = 2;
13+
REPEATED_FIELD_PROXY_TEST_IMPORT_BAZ = 3;
14+
}

src/google/protobuf/test_protos/repeated_field_proxy_test.proto

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,22 @@ message TestRepeatedIntProxy {
3333

3434
repeated int32 ints_proxy = 2 [features.(pb.cpp).repeated_type = PROXY];
3535
}
36+
37+
message TestRepeatedEnumProxy {
38+
enum Enum {
39+
UNKNOWN = 0;
40+
FOO = 1;
41+
BAR = 2;
42+
BAZ = 3;
43+
}
44+
45+
repeated Enum enums = 1 [features.(pb.cpp).repeated_type = LEGACY];
46+
47+
repeated Enum enums_proxy = 2 [features.(pb.cpp).repeated_type = PROXY];
48+
}
49+
50+
// Exercises having an incomplete enum type in the generated .proto.h.
51+
message TestRepeatedImportEnumProxy {
52+
repeated proto2_unittest.RepeatedFieldProxyTestImportEnum enums_proxy = 1
53+
[features.(pb.cpp).repeated_type = PROXY];
54+
}

0 commit comments

Comments
 (0)