• 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/default_value.h"
15 #include "google/protobuf/compiler/rust/accessors/generator.h"
16 #include "google/protobuf/compiler/rust/accessors/with_presence.h"
17 #include "google/protobuf/compiler/rust/context.h"
18 #include "google/protobuf/compiler/rust/naming.h"
19 #include "google/protobuf/compiler/rust/upb_helpers.h"
20 #include "google/protobuf/descriptor.h"
21 
22 namespace google {
23 namespace protobuf {
24 namespace compiler {
25 namespace rust {
26 
InMsgImpl(Context & ctx,const FieldDescriptor & field,AccessorCase accessor_case) const27 void SingularString::InMsgImpl(Context& ctx, const FieldDescriptor& field,
28                                AccessorCase accessor_case) const {
29   if (field.has_presence()) {
30     WithPresenceAccessorsInMsgImpl(ctx, field, accessor_case);
31   }
32 
33   std::string field_name = FieldNameWithCollisionAvoidance(field);
34   ctx.Emit(
35       {
36           {"field", RsSafeName(field_name)},
37           {"raw_field_name", field_name},
38           {"default_value", DefaultValue(ctx, field)},
39           {"upb_mt_field_index", UpbMiniTableFieldIndex(field)},
40           {"proxied_type", RsTypePath(ctx, field)},
41           io::Printer::Sub("transform_view",
42                            [&] {
43                              if (field.type() == FieldDescriptor::TYPE_STRING) {
44                                ctx.Emit(R"rs(
45               // SAFETY: The runtime doesn't require ProtoStr to be UTF-8.
46               unsafe { $pb$::ProtoStr::from_utf8_unchecked(str_view.as_ref()) }
47             )rs");
48                              } else {
49                                ctx.Emit("unsafe { str_view.as_ref() }");
50                              }
51                            })
52               .WithSuffix(""),  // This lets `$transform_view$,` work.
53           {"view_lifetime", ViewLifetime(accessor_case)},
54           {"view_self", ViewReceiver(accessor_case)},
55           {"getter",
56            [&] {
57              if (ctx.is_cpp()) {
58                ctx.Emit({{"getter_thunk", ThunkName(ctx, field, "get")}},
59                         R"rs(
60                   pub fn $field$($view_self$) -> $pb$::View<$view_lifetime$, $proxied_type$> {
61                     let str_view = unsafe { $getter_thunk$(self.raw_msg()) };
62                     $transform_view$
63                   })rs");
64              } else {
65                ctx.Emit(R"rs(
66                   pub fn $field$($view_self$) -> $pb$::View<$view_lifetime$, $proxied_type$> {
67                     let str_view = unsafe {
68                       let f = $pbr$::upb_MiniTable_GetFieldByIndex(
69                           <Self as $pbr$::AssociatedMiniTable>::mini_table(),
70                           $upb_mt_field_index$);
71                       $pbr$::upb_Message_GetString(
72                           self.raw_msg(), f, ($default_value$).into())
73                     };
74                     $transform_view$
75                   })rs");
76              }
77            }},
78           {"setter_impl",
79            [&] {
80              if (ctx.is_cpp()) {
81                ctx.Emit({{"setter_thunk", ThunkName(ctx, field, "set")}},
82                         R"rs(
83                 let s = val.into_proxied($pbi$::Private);
84                 unsafe {
85                   $setter_thunk$(
86                     self.as_mutator_message_ref($pbi$::Private).msg(),
87                     s.into_inner($pbi$::Private).into_raw()
88                   );
89                 }
90               )rs");
91              } else {
92                ctx.Emit(R"rs(
93                 let s = val.into_proxied($pbi$::Private);
94                 let (view, arena) =
95                   s.into_inner($pbi$::Private).into_raw_parts();
96 
97                 let mm_ref =
98                   self.as_mutator_message_ref($pbi$::Private);
99                 let parent_arena = mm_ref.arena();
100 
101                 parent_arena.fuse(&arena);
102 
103                 unsafe {
104                   let f = $pbr$::upb_MiniTable_GetFieldByIndex(
105                             <Self as $pbr$::AssociatedMiniTable>::mini_table(),
106                             $upb_mt_field_index$);
107                   $pbr$::upb_Message_SetBaseFieldString(
108                     self.as_mutator_message_ref($pbi$::Private).msg(),
109                     f,
110                     view);
111                 }
112               )rs");
113              }
114            }},
115           {"setter",
116            [&] {
117              if (accessor_case == AccessorCase::VIEW) return;
118              ctx.Emit(R"rs(
119               pub fn set_$raw_field_name$(&mut self, val: impl $pb$::IntoProxied<$proxied_type$>) {
120                 $setter_impl$
121               }
122             )rs");
123            }},
124       },
125       R"rs(
126         $getter$
127         $setter$
128       )rs");
129 }
130 
InExternC(Context & ctx,const FieldDescriptor & field) const131 void SingularString::InExternC(Context& ctx,
132                                const FieldDescriptor& field) const {
133   ABSL_CHECK(ctx.is_cpp());
134 
135   if (field.has_presence()) {
136     WithPresenceAccessorsInExternC(ctx, field);
137   }
138 
139   ctx.Emit(
140       {
141           {"getter_thunk", ThunkName(ctx, field, "get")},
142           {"setter_thunk", ThunkName(ctx, field, "set")},
143           {"setter",
144            [&] {
145              if (ctx.is_cpp()) {
146                ctx.Emit(R"rs(
147                   fn $setter_thunk$(raw_msg: $pbr$::RawMessage, val: $pbr$::CppStdString);
148                 )rs");
149              } else {
150                ctx.Emit(R"rs(
151                   fn $setter_thunk$(raw_msg: $pbr$::RawMessage, val: $pbr$::PtrAndLen);
152                 )rs");
153              }
154            }},
155       },
156       R"rs(
157           fn $getter_thunk$(raw_msg: $pbr$::RawMessage) -> $pbr$::PtrAndLen;
158           $setter$
159         )rs");
160 }
161 
InThunkCc(Context & ctx,const FieldDescriptor & field) const162 void SingularString::InThunkCc(Context& ctx,
163                                const FieldDescriptor& field) const {
164   ABSL_CHECK(ctx.is_cpp());
165 
166   if (field.has_presence()) {
167     WithPresenceAccessorsInThunkCc(ctx, field);
168   }
169 
170   ctx.Emit(
171       {
172           {"field", cpp::FieldName(&field)},
173           {"QualifiedMsg", cpp::QualifiedClassName(field.containing_type())},
174           {"getter_thunk", ThunkName(ctx, field, "get")},
175           {"setter_thunk", ThunkName(ctx, field, "set")},
176       },
177       R"cc(
178         ::google::protobuf::rust::PtrAndLen $getter_thunk$($QualifiedMsg$* msg) {
179           absl::string_view val = msg->$field$();
180           return ::google::protobuf::rust::PtrAndLen{val.data(), val.size()};
181         }
182         void $setter_thunk$($QualifiedMsg$* msg, std::string* s) {
183           msg->set_$field$(std::move(*s));
184           delete s;
185         }
186       )cc");
187 }
188 
189 }  // namespace rust
190 }  // namespace compiler
191 }  // namespace protobuf
192 }  // namespace google
193