• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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