1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2024 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "google/protobuf/compiler/rust/accessors/with_presence.h"
9
10 #include <string>
11
12 #include "absl/log/absl_check.h"
13 #include "google/protobuf/compiler/cpp/helpers.h"
14 #include "google/protobuf/compiler/rust/accessors/accessor_case.h"
15 #include "google/protobuf/compiler/rust/context.h"
16 #include "google/protobuf/compiler/rust/naming.h"
17 #include "google/protobuf/compiler/rust/upb_helpers.h"
18 #include "google/protobuf/descriptor.h"
19
20 namespace google {
21 namespace protobuf {
22 namespace compiler {
23 namespace rust {
24
WithPresenceAccessorsInMsgImpl(Context & ctx,const FieldDescriptor & field,AccessorCase accessor_case)25 void WithPresenceAccessorsInMsgImpl(Context& ctx, const FieldDescriptor& field,
26 AccessorCase accessor_case) {
27 ABSL_CHECK(field.has_presence());
28
29 std::string field_name = FieldNameWithCollisionAvoidance(field);
30
31 ctx.Emit(
32 {{"field", RsSafeName(field_name)},
33 {"raw_field_name", field_name}, // Never r# prefixed
34 {"view_type", RsViewType(ctx, field, ViewLifetime(accessor_case))},
35 {"view_self", ViewReceiver(accessor_case)},
36 {"hazzer",
37 [&] {
38 if (ctx.is_cpp()) {
39 ctx.Emit({{"hazzer_thunk", ThunkName(ctx, field, "has")}},
40 R"rs(
41 pub fn has_$raw_field_name$($view_self$) -> bool {
42 unsafe {
43 $hazzer_thunk$(self.raw_msg())
44 }
45 }
46 )rs");
47 } else {
48 ctx.Emit({{"upb_mt_field_index", UpbMiniTableFieldIndex(field)}},
49 R"rs(
50 pub fn has_$raw_field_name$($view_self$) -> bool {
51 unsafe {
52 let f = $pbr$::upb_MiniTable_GetFieldByIndex(
53 <Self as $pbr$::AssociatedMiniTable>::mini_table(),
54 $upb_mt_field_index$);
55 $pbr$::upb_Message_HasBaseField(self.raw_msg(), f)
56 }
57 }
58 )rs");
59 }
60 }},
61 {"clearer",
62 [&] {
63 if (accessor_case == AccessorCase::VIEW) return;
64 if (ctx.is_cpp()) {
65 ctx.Emit({{"clearer_thunk", ThunkName(ctx, field, "clear")}},
66 R"rs(
67 pub fn clear_$raw_field_name$(&mut self) {
68 unsafe { $clearer_thunk$(self.raw_msg()) }
69 })rs");
70 } else {
71 ctx.Emit({{"upb_mt_field_index", UpbMiniTableFieldIndex(field)}},
72 R"rs(
73 pub fn clear_$raw_field_name$(&mut self) {
74 unsafe {
75 let mt = <Self as $pbr$::AssociatedMiniTable>::mini_table();
76 let f = $pbr$::upb_MiniTable_GetFieldByIndex(
77 mt, $upb_mt_field_index$);
78 $pbr$::upb_Message_ClearBaseField(self.raw_msg(), f);
79 }
80 })rs");
81 }
82 }},
83 {"opt_getter",
84 [&] {
85 // Cord fields don't support the _opt getter.
86 if (field.options().ctype() == FieldOptions::CORD) return;
87 ctx.Emit(
88 R"rs(
89 pub fn $raw_field_name$_opt($view_self$) -> $pb$::Optional<$view_type$> {
90 $pb$::Optional::new(self.$field$(), self.has_$raw_field_name$())
91 }
92 )rs");
93 }}},
94 R"rs(
95 $hazzer$
96 $clearer$
97 $opt_getter$
98 )rs");
99 }
100
WithPresenceAccessorsInExternC(Context & ctx,const FieldDescriptor & field)101 void WithPresenceAccessorsInExternC(Context& ctx,
102 const FieldDescriptor& field) {
103 ABSL_CHECK(ctx.is_cpp());
104 ABSL_CHECK(field.has_presence());
105
106 ctx.Emit(
107 {
108 {"hazzer_thunk", ThunkName(ctx, field, "has")},
109 {"clearer_thunk", ThunkName(ctx, field, "clear")},
110 },
111 R"rs(
112 fn $hazzer_thunk$(raw_msg: $pbr$::RawMessage) -> bool;
113 fn $clearer_thunk$(raw_msg: $pbr$::RawMessage);
114 )rs");
115 }
116
WithPresenceAccessorsInThunkCc(Context & ctx,const FieldDescriptor & field)117 void WithPresenceAccessorsInThunkCc(Context& ctx,
118 const FieldDescriptor& field) {
119 ABSL_CHECK(ctx.is_cpp());
120 ABSL_CHECK(field.has_presence());
121
122 ctx.Emit(
123 {
124 {"field", cpp::FieldName(&field)},
125 {"QualifiedMsg", cpp::QualifiedClassName(field.containing_type())},
126 {"hazzer_thunk", ThunkName(ctx, field, "has")},
127 {"clearer_thunk", ThunkName(ctx, field, "clear")},
128 },
129 R"rs(
130 bool $hazzer_thunk$($QualifiedMsg$* msg) {
131 return msg->has_$field$();
132 }
133 void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
134 )rs");
135 }
136
137 } // namespace rust
138 } // namespace compiler
139 } // namespace protobuf
140 } // namespace google
141