1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 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 <string>
9
10 #include "absl/log/absl_check.h"
11 #include "absl/strings/string_view.h"
12 #include "google/protobuf/compiler/cpp/helpers.h"
13 #include "google/protobuf/compiler/rust/accessors/accessor_case.h"
14 #include "google/protobuf/compiler/rust/accessors/generator.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
InMsgImpl(Context & ctx,const FieldDescriptor & field,AccessorCase accessor_case) const25 void RepeatedField::InMsgImpl(Context& ctx, const FieldDescriptor& field,
26 AccessorCase accessor_case) const {
27 std::string field_name = FieldNameWithCollisionAvoidance(field);
28 ctx.Emit(
29 {
30 {"field", RsSafeName(field_name)},
31 {"raw_field_name", field_name}, // Never r# prefixed
32 {"RsType", RsTypePath(ctx, field)},
33 {"view_lifetime", ViewLifetime(accessor_case)},
34 {"view_self", ViewReceiver(accessor_case)},
35 {"upb_mt_field_index", UpbMiniTableFieldIndex(field)},
36 {"getter",
37 [&] {
38 if (ctx.is_upb()) {
39 ctx.Emit(R"rs(
40 pub fn $field$($view_self$) -> $pb$::RepeatedView<$view_lifetime$, $RsType$> {
41 unsafe {
42 let f = $pbr$::upb_MiniTable_GetFieldByIndex(
43 <Self as $pbr$::AssociatedMiniTable>::mini_table(),
44 $upb_mt_field_index$);
45 $pbr$::upb_Message_GetArray(
46 self.raw_msg(), f)
47 }.map_or_else(
48 $pbr$::empty_array::<$RsType$>,
49 |raw| unsafe {
50 $pb$::RepeatedView::from_raw($pbi$::Private, raw)
51 }
52 )
53 }
54 )rs");
55 } else {
56 ctx.Emit({{"getter_thunk", ThunkName(ctx, field, "get")}}, R"rs(
57 pub fn $field$($view_self$) -> $pb$::RepeatedView<$view_lifetime$, $RsType$> {
58 unsafe {
59 $pb$::RepeatedView::from_raw(
60 $pbi$::Private,
61 $getter_thunk$(self.raw_msg()),
62 )
63 }
64 }
65 )rs");
66 }
67 }},
68 {"getter_mut",
69 [&] {
70 if (accessor_case == AccessorCase::VIEW) {
71 return;
72 }
73 if (ctx.is_upb()) {
74 ctx.Emit({}, R"rs(
75 pub fn $field$_mut(&mut self) -> $pb$::RepeatedMut<'_, $RsType$> {
76 unsafe {
77 let f = $pbr$::upb_MiniTable_GetFieldByIndex(
78 <Self as $pbr$::AssociatedMiniTable>::mini_table(),
79 $upb_mt_field_index$);
80 let raw_array = $pbr$::upb_Message_GetOrCreateMutableArray(
81 self.raw_msg(),
82 f,
83 self.arena().raw(),
84 ).unwrap();
85 $pb$::RepeatedMut::from_inner(
86 $pbi$::Private,
87 $pbr$::InnerRepeatedMut::new(
88 raw_array, self.arena(),
89 ),
90 )
91 }
92 }
93 )rs");
94 } else {
95 ctx.Emit(
96 {{"getter_mut_thunk", ThunkName(ctx, field, "get_mut")}},
97 R"rs(
98 pub fn $field$_mut(&mut self) -> $pb$::RepeatedMut<'_, $RsType$> {
99 unsafe {
100 $pb$::RepeatedMut::from_inner(
101 $pbi$::Private,
102 $pbr$::InnerRepeatedMut::new(
103 $getter_mut_thunk$(self.raw_msg()),
104 ),
105 )
106 }
107 }
108 )rs");
109 }
110 }},
111 {"setter",
112 [&] {
113 if (accessor_case == AccessorCase::VIEW) {
114 return;
115 }
116 if (ctx.is_upb()) {
117 ctx.Emit(R"rs(
118 pub fn set_$raw_field_name$(&mut self, src: impl $pb$::IntoProxied<$pb$::Repeated<$RsType$>>) {
119 let minitable_field = unsafe {
120 $pbr$::upb_MiniTable_GetFieldByIndex(
121 <Self as $pbr$::AssociatedMiniTable>::mini_table(),
122 $upb_mt_field_index$
123 )
124 };
125 let val = src.into_proxied($pbi$::Private);
126 let inner = val.inner($pbi$::Private);
127
128 self.arena().fuse(inner.arena());
129 unsafe {
130 let value_ptr: *const *const std::ffi::c_void =
131 &(inner.raw().as_ptr() as *const std::ffi::c_void);
132 $pbr$::upb_Message_SetBaseField(self.raw_msg(),
133 minitable_field,
134 value_ptr as *const std::ffi::c_void);
135 }
136 }
137 )rs");
138 } else {
139 ctx.Emit(
140 {{"move_setter_thunk", ThunkName(ctx, field, "move_set")}},
141 R"rs(
142 pub fn set_$raw_field_name$(&mut self, src: impl $pb$::IntoProxied<$pb$::Repeated<$RsType$>>) {
143 // Prevent the memory from being deallocated. The setter
144 // transfers ownership of the memory to the parent message.
145 let val = std::mem::ManuallyDrop::new(src.into_proxied($pbi$::Private));
146 unsafe {
147 $move_setter_thunk$(self.raw_msg(),
148 val.inner($pbi$::Private).raw());
149 }
150 }
151 )rs");
152 }
153 }},
154 },
155 R"rs(
156 $getter$
157 $getter_mut$
158 $setter$
159 )rs");
160 }
161
InExternC(Context & ctx,const FieldDescriptor & field) const162 void RepeatedField::InExternC(Context& ctx,
163 const FieldDescriptor& field) const {
164 ABSL_CHECK(ctx.is_cpp());
165
166 ctx.Emit({{"getter_thunk", ThunkName(ctx, field, "get")},
167 {"getter_mut_thunk", ThunkName(ctx, field, "get_mut")},
168 {"move_setter_thunk", ThunkName(ctx, field, "move_set")},
169 {"getter",
170 [&] {
171 if (ctx.is_upb()) {
172 ctx.Emit(R"rs(
173 fn $getter_mut_thunk$(
174 raw_msg: $pbr$::RawMessage,
175 size: *const usize,
176 arena: $pbr$::RawArena,
177 ) -> $pbr$::RawRepeatedField;
178 // Returns `None` when returned array pointer is NULL.
179 fn $getter_thunk$(
180 raw_msg: $pbr$::RawMessage,
181 size: *const usize,
182 ) -> $Option$<$pbr$::RawRepeatedField>;
183 )rs");
184 } else {
185 ctx.Emit(R"rs(
186 fn $getter_mut_thunk$(raw_msg: $pbr$::RawMessage) -> $pbr$::RawRepeatedField;
187 fn $getter_thunk$(raw_msg: $pbr$::RawMessage) -> $pbr$::RawRepeatedField;
188 fn $move_setter_thunk$(raw_msg: $pbr$::RawMessage, value: $pbr$::RawRepeatedField);
189 )rs");
190 }
191 }}},
192 R"rs(
193 $getter$
194 )rs");
195 }
196
IsRepeatedPrimitive(const FieldDescriptor & field)197 bool IsRepeatedPrimitive(const FieldDescriptor& field) {
198 return field.cpp_type() == FieldDescriptor::CPPTYPE_ENUM ||
199 field.cpp_type() == FieldDescriptor::CPPTYPE_BOOL ||
200 field.cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE ||
201 field.cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
202 field.cpp_type() == FieldDescriptor::CPPTYPE_INT32 ||
203 field.cpp_type() == FieldDescriptor::CPPTYPE_INT64 ||
204 field.cpp_type() == FieldDescriptor::CPPTYPE_UINT32 ||
205 field.cpp_type() == FieldDescriptor::CPPTYPE_UINT64;
206 }
207
IsRepeatedPtrPrimitive(const FieldDescriptor & field)208 bool IsRepeatedPtrPrimitive(const FieldDescriptor& field) {
209 return field.cpp_type() == FieldDescriptor::CPPTYPE_STRING;
210 }
211
CppElementType(const FieldDescriptor & field)212 std::string CppElementType(const FieldDescriptor& field) {
213 if (IsRepeatedPrimitive(field) || IsRepeatedPtrPrimitive(field)) {
214 return cpp::PrimitiveTypeName(field.cpp_type());
215 } else {
216 return cpp::QualifiedClassName(field.message_type());
217 }
218 }
219
CppRepeatedContainerType(const FieldDescriptor & field)220 const char* CppRepeatedContainerType(const FieldDescriptor& field) {
221 if (IsRepeatedPrimitive(field)) {
222 return "google::protobuf::RepeatedField";
223 } else {
224 return "google::protobuf::RepeatedPtrField";
225 }
226 }
227
InThunkCc(Context & ctx,const FieldDescriptor & field) const228 void RepeatedField::InThunkCc(Context& ctx,
229 const FieldDescriptor& field) const {
230 ABSL_CHECK(ctx.is_cpp());
231
232 ctx.Emit({{"field", cpp::FieldName(&field)},
233 {"ElementType", CppElementType(field)},
234 {"ContainerType", CppRepeatedContainerType(field)},
235 {"QualifiedMsg", cpp::QualifiedClassName(field.containing_type())},
236 {"getter_thunk", ThunkName(ctx, field, "get")},
237 {"getter_mut_thunk", ThunkName(ctx, field, "get_mut")},
238 {"repeated_copy_from_thunk",
239 ThunkName(ctx, field, "repeated_copy_from")},
240 {"move_setter_thunk", ThunkName(ctx, field, "move_set")},
241 {"impls",
242 [&] {
243 ctx.Emit(
244 R"cc(
245 $ContainerType$<$ElementType$>* $getter_mut_thunk$(
246 $QualifiedMsg$* msg) {
247 return msg->mutable_$field$();
248 }
249 const $ContainerType$<$ElementType$>* $getter_thunk$(
250 const $QualifiedMsg$* msg) {
251 return &msg->$field$();
252 }
253 void $move_setter_thunk$(
254 $QualifiedMsg$* msg,
255 $ContainerType$<$ElementType$>* value) {
256 *msg->mutable_$field$() = std::move(*value);
257 delete value;
258 }
259 )cc");
260 }}},
261 "$impls$");
262 }
263
264 } // namespace rust
265 } // namespace compiler
266 } // namespace protobuf
267 } // namespace google
268