• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/accessors/with_presence.h"
16 #include "google/protobuf/compiler/rust/context.h"
17 #include "google/protobuf/compiler/rust/naming.h"
18 #include "google/protobuf/compiler/rust/upb_helpers.h"
19 #include "google/protobuf/descriptor.h"
20 
21 namespace google {
22 namespace protobuf {
23 namespace compiler {
24 namespace rust {
25 
InMsgImpl(Context & ctx,const FieldDescriptor & field,AccessorCase accessor_case) const26 void SingularMessage::InMsgImpl(Context& ctx, const FieldDescriptor& field,
27                                 AccessorCase accessor_case) const {
28   if (field.has_presence()) {
29     WithPresenceAccessorsInMsgImpl(ctx, field, accessor_case);
30   }
31 
32   // fully qualified message name with modules prefixed
33   std::string msg_type = RsTypePath(ctx, field);
34   std::string field_name = FieldNameWithCollisionAvoidance(field);
35   ctx.Emit(
36       {
37           {"msg_type", msg_type},
38           {"field", RsSafeName(field_name)},
39           {"raw_field_name", field_name},
40           {"view_lifetime", ViewLifetime(accessor_case)},
41           {"view_self", ViewReceiver(accessor_case)},
42           {"upb_mt_field_index", UpbMiniTableFieldIndex(field)},
43           {
44               "getter_body",
45               [&] {
46                 if (ctx.is_upb()) {
47                   ctx.Emit(R"rs(
48               let submsg = unsafe {
49                 let f = $pbr$::upb_MiniTable_GetFieldByIndex(
50                             <Self as $pbr$::AssociatedMiniTable>::mini_table(),
51                             $upb_mt_field_index$);
52                 $pbr$::upb_Message_GetMessage(self.raw_msg(), f)
53               };
54               //~ For upb, getters return null if the field is unset, so we need
55               //~ to check for null and return the default instance manually.
56               //~ Note that a nullptr received from upb manifests as Option::None
57               match submsg {
58                 //~ TODO:(b/304357029)
59                 None => $msg_type$View::new($pbi$::Private, $pbr$::ScratchSpace::zeroed_block()),
60                 Some(sub_raw_msg) => $msg_type$View::new($pbi$::Private, sub_raw_msg),
61               }
62         )rs");
63                 } else {
64                   ctx.Emit({{"getter_thunk", ThunkName(ctx, field, "get")}},
65                            R"rs(
66               //~ For C++ kernel, getters automatically return the
67               //~ default_instance if the field is unset.
68               let submsg = unsafe { $getter_thunk$(self.raw_msg()) };
69               $msg_type$View::new($pbi$::Private, submsg)
70         )rs");
71                 }
72               },
73           },
74           {"getter",
75            [&] {
76              ctx.Emit(R"rs(
77                 pub fn $field$($view_self$) -> $msg_type$View<$view_lifetime$> {
78                   $getter_body$
79                 }
80               )rs");
81            }},
82           {"getter_mut_body",
83            [&] {
84              if (ctx.is_cpp()) {
85                ctx.Emit(
86                    {{"getter_mut_thunk", ThunkName(ctx, field, "get_mut")}},
87                    R"rs(
88                   let raw_msg = unsafe { $getter_mut_thunk$(self.raw_msg()) };
89                   $msg_type$Mut::from_parent($pbi$::Private,
90                   self.as_mutator_message_ref($pbi$::Private), raw_msg)
91                  )rs");
92              } else {
93                ctx.Emit({}, R"rs(
94                   let raw_msg = unsafe {
95                     let mt = <Self as $pbr$::AssociatedMiniTable>::mini_table();
96                     let f = $pbr$::upb_MiniTable_GetFieldByIndex(mt, $upb_mt_field_index$);
97                     $pbr$::upb_Message_GetOrCreateMutableMessage(
98                         self.raw_msg(), mt, f, self.arena().raw()).unwrap()
99                   };
100                   $msg_type$Mut::from_parent($pbi$::Private,
101                     self.as_mutator_message_ref($pbi$::Private), raw_msg)
102                 )rs");
103              }
104            }},
105           {"getter_mut",
106            [&] {
107              if (accessor_case == AccessorCase::VIEW) {
108                return;
109              }
110 
111              ctx.Emit({}, R"rs(
112                  pub fn $raw_field_name$_mut(&mut self) -> $msg_type$Mut<'_> {
113                     $getter_mut_body$
114                })rs");
115            }},
116           {"setter_body",
117            [&] {
118              if (accessor_case == AccessorCase::VIEW) return;
119              if (ctx.is_upb()) {
120                ctx.Emit(R"rs(
121                   // The message and arena are dropped after the setter. The
122                   // memory remains allocated as we fuse the arena with the
123                   // parent message's arena.
124                   let mut msg = val.into_proxied($pbi$::Private);
125                   self.as_mutator_message_ref($pbi$::Private)
126                     .arena()
127                     .fuse(msg.as_mutator_message_ref($pbi$::Private).arena());
128 
129                   unsafe {
130                     let f = $pbr$::upb_MiniTable_GetFieldByIndex(
131                               <Self as $pbr$::AssociatedMiniTable>::mini_table(),
132                               $upb_mt_field_index$);
133                     $pbr$::upb_Message_SetBaseFieldMessage(
134                       self.as_mutator_message_ref($pbi$::Private).msg(),
135                       f,
136                       msg.as_mutator_message_ref($pbi$::Private).msg());
137                   }
138                 )rs");
139              } else {
140                ctx.Emit({{"set_allocated_thunk", ThunkName(ctx, field, "set")}},
141                         R"rs(
142                   // Prevent the memory from being deallocated. The setter
143                   // transfers ownership of the memory to the parent message.
144                   let mut msg = std::mem::ManuallyDrop::new(val.into_proxied($pbi$::Private));
145                   unsafe {
146                     $set_allocated_thunk$(self.as_mutator_message_ref($pbi$::Private).msg(),
147                       msg.as_mutator_message_ref($pbi$::Private).msg());
148                   }
149                 )rs");
150              }
151            }},
152           {"setter",
153            [&] {
154              if (accessor_case == AccessorCase::VIEW) return;
155              ctx.Emit(R"rs(
156                 pub fn set_$raw_field_name$(&mut self,
157                   val: impl $pb$::IntoProxied<$msg_type$>) {
158 
159                   $setter_body$
160                 }
161               )rs");
162            }},
163       },
164       R"rs(
165             $getter$
166             $getter_mut$
167             $setter$
168         )rs");
169 }
170 
InExternC(Context & ctx,const FieldDescriptor & field) const171 void SingularMessage::InExternC(Context& ctx,
172                                 const FieldDescriptor& field) const {
173   ABSL_CHECK(ctx.is_cpp());
174 
175   if (field.has_presence()) {
176     WithPresenceAccessorsInExternC(ctx, field);
177   }
178 
179   ctx.Emit(
180       {
181           {"getter_thunk", ThunkName(ctx, field, "get")},
182           {"getter_mut_thunk", ThunkName(ctx, field, "get_mut")},
183           {"set_allocated_thunk", ThunkName(ctx, field, "set")},
184           {"getter_mut",
185            [&] {
186              if (ctx.is_cpp()) {
187                ctx.Emit(
188                    R"rs(
189                     fn $getter_mut_thunk$(raw_msg: $pbr$::RawMessage)
190                        -> $pbr$::RawMessage;)rs");
191              } else {
192                ctx.Emit(
193                    R"rs(fn $getter_mut_thunk$(raw_msg: $pbr$::RawMessage,
194                                                arena: $pbr$::RawArena)
195                             -> $pbr$::RawMessage;)rs");
196              }
197            }},
198           {"ReturnType",
199            [&] {
200              if (ctx.is_cpp()) {
201                // guaranteed to have a nonnull submsg for the cpp kernel
202                ctx.Emit({}, "$pbr$::RawMessage;");
203              } else {
204                // upb kernel may return NULL for a submsg, we can detect this
205                // in terra rust if the option returned is None
206                ctx.Emit({}, "$Option$<$pbr$::RawMessage>;");
207              }
208            }},
209       },
210       R"rs(
211                   fn $getter_thunk$(raw_msg: $pbr$::RawMessage) -> $ReturnType$;
212                   $getter_mut$
213                   fn $set_allocated_thunk$(raw_msg: $pbr$::RawMessage,
214                                     field_msg: $pbr$::RawMessage);
215                )rs");
216 }
217 
InThunkCc(Context & ctx,const FieldDescriptor & field) const218 void SingularMessage::InThunkCc(Context& ctx,
219                                 const FieldDescriptor& field) const {
220   ABSL_CHECK(ctx.is_cpp());
221   if (field.has_presence()) {
222     WithPresenceAccessorsInThunkCc(ctx, field);
223   }
224 
225   ctx.Emit({{"QualifiedMsg", cpp::QualifiedClassName(field.containing_type())},
226             {"FieldMsg", cpp::QualifiedClassName(field.message_type())},
227             {"set_allocated_thunk", ThunkName(ctx, field, "set")},
228             {"getter_thunk", ThunkName(ctx, field, "get")},
229             {"getter_mut_thunk", ThunkName(ctx, field, "get_mut")},
230             {"field", cpp::FieldName(&field)}},
231            R"cc(
232              const void* $getter_thunk$($QualifiedMsg$* msg) {
233                return static_cast<const void*>(&msg->$field$());
234              }
235              void* $getter_mut_thunk$($QualifiedMsg$* msg) {
236                return static_cast<void*>(msg->mutable_$field$());
237              }
238              void $set_allocated_thunk$($QualifiedMsg$* msg, $FieldMsg$* sub_msg) {
239                msg->set_allocated_$field$(sub_msg);
240              }
241            )cc");
242 }
243 
244 }  // namespace rust
245 }  // namespace compiler
246 }  // namespace protobuf
247 }  // namespace google
248