blob: 2d84796561885d217e45a055b0be96f8f47a9a82 [file] [log] [blame]
Adam Cozzette501ecec2023-09-26 14:36:20 -07001// Protocol Buffers - Google's data interchange format
2// Copyright 2023 Google LLC. All rights reserved.
Adam Cozzette501ecec2023-09-26 14:36:20 -07003//
Hong Shinb837d172023-11-07 13:24:59 -08004// 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
Adam Cozzette501ecec2023-09-26 14:36:20 -07007
8#include <algorithm>
9#include <cmath>
10#include <cstddef>
11#include <cstdint>
12#include <cstdio>
13#include <cstdlib>
14#include <limits>
15#include <map>
Eric Salo07556212023-12-05 17:40:25 -080016#include <memory>
Adam Cozzette501ecec2023-09-26 14:36:20 -070017#include <string>
18#include <utility>
19#include <vector>
20
Eric Salo07556212023-12-05 17:40:25 -080021#include "absl/container/flat_hash_map.h"
22#include "absl/container/flat_hash_set.h"
Adam Cozzette501ecec2023-09-26 14:36:20 -070023#include "absl/log/absl_check.h"
24#include "absl/log/absl_log.h"
25#include "absl/strings/escaping.h"
26#include "absl/strings/str_replace.h"
27#include "absl/strings/string_view.h"
28#include "absl/strings/substitute.h"
29#include "upb/base/descriptor_constants.h"
30#include "upb/base/string_view.h"
31#include "upb/reflection/def.hpp"
Eric Salo07556212023-12-05 17:40:25 -080032#include "upb/wire/types.h"
Adam Cozzette12c7bb02023-09-28 12:54:11 -070033#include "upb_generator/common.h"
34#include "upb_generator/file_layout.h"
35#include "upb_generator/names.h"
36#include "upb_generator/plugin.h"
Adam Cozzette501ecec2023-09-26 14:36:20 -070037
38// Must be last.
39#include "upb/port/def.inc"
40
Adam Cozzette12c7bb02023-09-28 12:54:11 -070041namespace upb {
42namespace generator {
Adam Cozzette501ecec2023-09-26 14:36:20 -070043namespace {
44
45struct Options {
46 bool bootstrap = false;
47};
48
49std::string SourceFilename(upb::FileDefPtr file) {
50 return StripExtension(file.name()) + ".upb.c";
51}
52
Adam Cozzette501ecec2023-09-26 14:36:20 -070053std::string MessageMiniTableRef(upb::MessageDefPtr descriptor,
54 const Options& options) {
55 if (options.bootstrap) {
56 return absl::StrCat(MessageInitName(descriptor), "()");
57 } else {
58 return absl::StrCat("&", MessageInitName(descriptor));
59 }
60}
61
62std::string EnumInitName(upb::EnumDefPtr descriptor) {
63 return ToCIdent(descriptor.full_name()) + "_enum_init";
64}
65
66std::string EnumMiniTableRef(upb::EnumDefPtr descriptor,
67 const Options& options) {
68 if (options.bootstrap) {
69 return absl::StrCat(EnumInitName(descriptor), "()");
70 } else {
71 return absl::StrCat("&", EnumInitName(descriptor));
72 }
73}
74
75std::string ExtensionIdentBase(upb::FieldDefPtr ext) {
Eric Salo07556212023-12-05 17:40:25 -080076 assert(ext.is_extension());
Adam Cozzette501ecec2023-09-26 14:36:20 -070077 if (ext.extension_scope()) {
78 return MessageName(ext.extension_scope());
79 } else {
80 return ToCIdent(ext.file().package());
81 }
82}
83
84std::string ExtensionLayout(upb::FieldDefPtr ext) {
85 return absl::StrCat(ExtensionIdentBase(ext), "_", ext.name(), "_ext");
86}
87
88std::string EnumValueSymbol(upb::EnumValDefPtr value) {
89 return ToCIdent(value.full_name());
90}
91
92std::string CTypeInternal(upb::FieldDefPtr field, bool is_const) {
93 std::string maybe_const = is_const ? "const " : "";
94 switch (field.ctype()) {
95 case kUpb_CType_Message: {
96 std::string maybe_struct =
97 field.file() != field.message_type().file() ? "struct " : "";
98 return maybe_const + maybe_struct + MessageName(field.message_type()) +
99 "*";
100 }
101 case kUpb_CType_Bool:
102 return "bool";
103 case kUpb_CType_Float:
104 return "float";
105 case kUpb_CType_Int32:
106 case kUpb_CType_Enum:
107 return "int32_t";
108 case kUpb_CType_UInt32:
109 return "uint32_t";
110 case kUpb_CType_Double:
111 return "double";
112 case kUpb_CType_Int64:
113 return "int64_t";
114 case kUpb_CType_UInt64:
115 return "uint64_t";
116 case kUpb_CType_String:
117 case kUpb_CType_Bytes:
118 return "upb_StringView";
119 default:
120 abort();
121 }
122}
123
124std::string FloatToCLiteral(float value) {
125 if (value == std::numeric_limits<float>::infinity()) {
126 return "kUpb_FltInfinity";
127 } else if (value == -std::numeric_limits<float>::infinity()) {
128 return "-kUpb_FltInfinity";
129 } else if (std::isnan(value)) {
130 return "kUpb_NaN";
131 } else {
132 return absl::StrCat(value);
133 }
134}
135
136std::string DoubleToCLiteral(double value) {
137 if (value == std::numeric_limits<double>::infinity()) {
138 return "kUpb_Infinity";
139 } else if (value == -std::numeric_limits<double>::infinity()) {
140 return "-kUpb_Infinity";
141 } else if (std::isnan(value)) {
142 return "kUpb_NaN";
143 } else {
144 return absl::StrCat(value);
145 }
146}
147
148// Escape trigraphs by escaping question marks to \?
149std::string EscapeTrigraphs(absl::string_view to_escape) {
150 return absl::StrReplaceAll(to_escape, {{"?", "\\?"}});
151}
152
153std::string FieldDefault(upb::FieldDefPtr field) {
154 switch (field.ctype()) {
155 case kUpb_CType_Message:
156 return "NULL";
157 case kUpb_CType_Bytes:
158 case kUpb_CType_String: {
159 upb_StringView str = field.default_value().str_val;
160 return absl::Substitute("upb_StringView_FromString(\"$0\")",
161 EscapeTrigraphs(absl::CEscape(
162 absl::string_view(str.data, str.size))));
163 }
164 case kUpb_CType_Int32:
165 return absl::Substitute("(int32_t)$0", field.default_value().int32_val);
166 case kUpb_CType_Int64:
167 if (field.default_value().int64_val == INT64_MIN) {
168 // Special-case to avoid:
169 // integer literal is too large to be represented in a signed integer
170 // type, interpreting as unsigned
171 // [-Werror,-Wimplicitly-unsigned-literal]
172 // int64_t default_val = (int64_t)-9223372036854775808ll;
173 //
174 // More info here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661
175 return "INT64_MIN";
176 } else {
177 return absl::Substitute("(int64_t)$0ll",
178 field.default_value().int64_val);
179 }
180 case kUpb_CType_UInt32:
181 return absl::Substitute("(uint32_t)$0u",
182 field.default_value().uint32_val);
183 case kUpb_CType_UInt64:
184 return absl::Substitute("(uint64_t)$0ull",
185 field.default_value().uint64_val);
186 case kUpb_CType_Float:
187 return FloatToCLiteral(field.default_value().float_val);
188 case kUpb_CType_Double:
189 return DoubleToCLiteral(field.default_value().double_val);
190 case kUpb_CType_Bool:
191 return field.default_value().bool_val ? "true" : "false";
192 case kUpb_CType_Enum:
193 // Use a number instead of a symbolic name so that we don't require
194 // this enum's header to be included.
195 return absl::StrCat(field.default_value().int32_val);
196 }
197 ABSL_ASSERT(false);
198 return "XXX";
199}
200
201std::string CType(upb::FieldDefPtr field) {
202 return CTypeInternal(field, false);
203}
204
205std::string CTypeConst(upb::FieldDefPtr field) {
206 return CTypeInternal(field, true);
207}
208
209std::string MapKeyCType(upb::FieldDefPtr map_field) {
210 return CType(map_field.message_type().map_key());
211}
212
213std::string MapValueCType(upb::FieldDefPtr map_field) {
214 return CType(map_field.message_type().map_value());
215}
216
217std::string MapKeySize(upb::FieldDefPtr map_field, absl::string_view expr) {
218 return map_field.message_type().map_key().ctype() == kUpb_CType_String
219 ? "0"
220 : absl::StrCat("sizeof(", expr, ")");
221}
222
223std::string MapValueSize(upb::FieldDefPtr map_field, absl::string_view expr) {
224 return map_field.message_type().map_value().ctype() == kUpb_CType_String
225 ? "0"
226 : absl::StrCat("sizeof(", expr, ")");
227}
228
229std::string FieldInitializer(const DefPoolPair& pools, upb::FieldDefPtr field,
230 const Options& options);
231
232void DumpEnumValues(upb::EnumDefPtr desc, Output& output) {
233 std::vector<upb::EnumValDefPtr> values;
234 values.reserve(desc.value_count());
235 for (int i = 0; i < desc.value_count(); i++) {
236 values.push_back(desc.value(i));
237 }
238 std::sort(values.begin(), values.end(),
239 [](upb::EnumValDefPtr a, upb::EnumValDefPtr b) {
240 return a.number() < b.number();
241 });
242
243 for (size_t i = 0; i < values.size(); i++) {
244 auto value = values[i];
245 output(" $0 = $1", EnumValueSymbol(value), value.number());
246 if (i != values.size() - 1) {
247 output(",");
248 }
249 output("\n");
250 }
251}
252
253std::string GetFieldRep(const DefPoolPair& pools, upb::FieldDefPtr field) {
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700254 return upb::generator::GetFieldRep(pools.GetField32(field),
255 pools.GetField64(field));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700256}
257
258void GenerateExtensionInHeader(const DefPoolPair& pools, upb::FieldDefPtr ext,
259 Output& output) {
260 output(
261 R"cc(
262 UPB_INLINE bool $0_has_$1(const struct $2* msg) {
263 return _upb_Message_HasExtensionField(msg, &$3);
264 }
265 )cc",
266 ExtensionIdentBase(ext), ext.name(), MessageName(ext.containing_type()),
267 ExtensionLayout(ext));
268
269 output(
270 R"cc(
271 UPB_INLINE void $0_clear_$1(struct $2* msg) {
272 _upb_Message_ClearExtensionField(msg, &$3);
273 }
274 )cc",
275 ExtensionIdentBase(ext), ext.name(), MessageName(ext.containing_type()),
276 ExtensionLayout(ext));
277
278 if (ext.IsSequence()) {
279 // TODO: We need generated accessors for repeated extensions.
280 } else {
281 output(
282 R"cc(
283 UPB_INLINE $0 $1_$2(const struct $3* msg) {
284 const upb_MiniTableExtension* ext = &$4;
Eric Salo19ef3a52023-11-28 19:38:22 -0800285 UPB_ASSUME(upb_MiniTableField_IsScalar(&ext->UPB_PRIVATE(field)));
286 UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(
287 &ext->UPB_PRIVATE(field)) == $5);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700288 $0 default_val = $6;
289 $0 ret;
290 _upb_Message_GetExtensionField(msg, ext, &default_val, &ret);
291 return ret;
292 }
293 )cc",
294 CTypeConst(ext), ExtensionIdentBase(ext), ext.name(),
295 MessageName(ext.containing_type()), ExtensionLayout(ext),
296 GetFieldRep(pools, ext), FieldDefault(ext));
297 output(
298 R"cc(
299 UPB_INLINE void $1_set_$2(struct $3* msg, $0 val, upb_Arena* arena) {
300 const upb_MiniTableExtension* ext = &$4;
Eric Salo19ef3a52023-11-28 19:38:22 -0800301 UPB_ASSUME(upb_MiniTableField_IsScalar(&ext->UPB_PRIVATE(field)));
302 UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(
303 &ext->UPB_PRIVATE(field)) == $5);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700304 bool ok = _upb_Message_SetExtensionField(msg, ext, &val, arena);
305 UPB_ASSERT(ok);
306 }
307 )cc",
308 CTypeConst(ext), ExtensionIdentBase(ext), ext.name(),
309 MessageName(ext.containing_type()), ExtensionLayout(ext),
310 GetFieldRep(pools, ext));
311 }
312}
313
314void GenerateMessageFunctionsInHeader(upb::MessageDefPtr message,
315 const Options& options, Output& output) {
316 // TODO: The generated code here does not check the return values
317 // from upb_Encode(). How can we even fix this without breaking other things?
318 output(
319 R"cc(
320 UPB_INLINE $0* $0_new(upb_Arena* arena) {
Eric Salo07556212023-12-05 17:40:25 -0800321 return ($0*)_upb_Message_New($1, arena);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700322 }
323 UPB_INLINE $0* $0_parse(const char* buf, size_t size, upb_Arena* arena) {
324 $0* ret = $0_new(arena);
325 if (!ret) return NULL;
326 if (upb_Decode(buf, size, ret, $1, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
327 return NULL;
328 }
329 return ret;
330 }
331 UPB_INLINE $0* $0_parse_ex(const char* buf, size_t size,
332 const upb_ExtensionRegistry* extreg,
333 int options, upb_Arena* arena) {
334 $0* ret = $0_new(arena);
335 if (!ret) return NULL;
336 if (upb_Decode(buf, size, ret, $1, extreg, options, arena) !=
337 kUpb_DecodeStatus_Ok) {
338 return NULL;
339 }
340 return ret;
341 }
342 UPB_INLINE char* $0_serialize(const $0* msg, upb_Arena* arena, size_t* len) {
343 char* ptr;
344 (void)upb_Encode(msg, $1, 0, arena, &ptr, len);
345 return ptr;
346 }
347 UPB_INLINE char* $0_serialize_ex(const $0* msg, int options,
348 upb_Arena* arena, size_t* len) {
349 char* ptr;
350 (void)upb_Encode(msg, $1, options, arena, &ptr, len);
351 return ptr;
352 }
353 )cc",
354 MessageName(message), MessageMiniTableRef(message, options));
355}
356
357void GenerateOneofInHeader(upb::OneofDefPtr oneof, const DefPoolPair& pools,
358 absl::string_view msg_name, const Options& options,
359 Output& output) {
360 std::string fullname = ToCIdent(oneof.full_name());
361 output("typedef enum {\n");
362 for (int j = 0; j < oneof.field_count(); j++) {
363 upb::FieldDefPtr field = oneof.field(j);
364 output(" $0_$1 = $2,\n", fullname, field.name(), field.number());
365 }
366 output(
367 " $0_NOT_SET = 0\n"
368 "} $0_oneofcases;\n",
369 fullname);
370 output(
371 R"cc(
372 UPB_INLINE $0_oneofcases $1_$2_case(const $1* msg) {
373 const upb_MiniTableField field = $3;
374 return ($0_oneofcases)upb_Message_WhichOneofFieldNumber(msg, &field);
375 }
376 )cc",
377 fullname, msg_name, oneof.name(),
378 FieldInitializer(pools, oneof.field(0), options));
379}
380
381void GenerateHazzer(upb::FieldDefPtr field, const DefPoolPair& pools,
382 absl::string_view msg_name,
383 const NameToFieldDefMap& field_names,
384 const Options& options, Output& output) {
385 std::string resolved_name = ResolveFieldName(field, field_names);
386 if (field.has_presence()) {
387 output(
388 R"cc(
389 UPB_INLINE bool $0_has_$1(const $0* msg) {
390 const upb_MiniTableField field = $2;
391 return _upb_Message_HasNonExtensionField(msg, &field);
392 }
393 )cc",
394 msg_name, resolved_name, FieldInitializer(pools, field, options));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700395 }
396}
397
398void GenerateClear(upb::FieldDefPtr field, const DefPoolPair& pools,
399 absl::string_view msg_name,
400 const NameToFieldDefMap& field_names, const Options& options,
401 Output& output) {
402 if (field == field.containing_type().map_key() ||
403 field == field.containing_type().map_value()) {
404 // Cannot be cleared.
405 return;
406 }
407 std::string resolved_name = ResolveFieldName(field, field_names);
408 output(
409 R"cc(
410 UPB_INLINE void $0_clear_$1($0* msg) {
411 const upb_MiniTableField field = $2;
412 _upb_Message_ClearNonExtensionField(msg, &field);
413 }
414 )cc",
415 msg_name, resolved_name, FieldInitializer(pools, field, options));
416}
417
418void GenerateMapGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
419 absl::string_view msg_name,
420 const NameToFieldDefMap& field_names,
421 const Options& options, Output& output) {
422 std::string resolved_name = ResolveFieldName(field, field_names);
423 output(
424 R"cc(
425 UPB_INLINE size_t $0_$1_size(const $0* msg) {
426 const upb_MiniTableField field = $2;
427 const upb_Map* map = upb_Message_GetMap(msg, &field);
428 return map ? _upb_Map_Size(map) : 0;
429 }
430 )cc",
431 msg_name, resolved_name, FieldInitializer(pools, field, options));
432 output(
433 R"cc(
434 UPB_INLINE bool $0_$1_get(const $0* msg, $2 key, $3* val) {
435 const upb_MiniTableField field = $4;
436 const upb_Map* map = upb_Message_GetMap(msg, &field);
437 if (!map) return false;
438 return _upb_Map_Get(map, &key, $5, val, $6);
439 }
440 )cc",
441 msg_name, resolved_name, MapKeyCType(field), MapValueCType(field),
442 FieldInitializer(pools, field, options), MapKeySize(field, "key"),
443 MapValueSize(field, "*val"));
444 output(
445 R"cc(
446 UPB_INLINE $0 $1_$2_next(const $1* msg, size_t* iter) {
447 const upb_MiniTableField field = $3;
448 const upb_Map* map = upb_Message_GetMap(msg, &field);
449 if (!map) return NULL;
450 return ($0)_upb_map_next(map, iter);
451 }
452 )cc",
453 CTypeConst(field), msg_name, resolved_name,
454 FieldInitializer(pools, field, options));
Jakob Buchgraberebdd7e32023-10-30 01:02:10 -0700455 // Generate private getter returning a upb_Map or NULL for immutable and
456 // a upb_Map for mutable.
457 //
458 // Example:
459 // UPB_INLINE const upb_Map* _name_immutable_upb_map(Foo* msg)
460 // UPB_INLINE upb_Map* _name_mutable_upb_map(Foo* msg, upb_Arena* a)
461 output(
462 R"cc(
463 UPB_INLINE const upb_Map* _$0_$1_$2($0* msg) {
464 const upb_MiniTableField field = $4;
465 return upb_Message_GetMap(msg, &field);
466 }
467 UPB_INLINE upb_Map* _$0_$1_$3($0* msg, upb_Arena* a) {
468 const upb_MiniTableField field = $4;
469 return _upb_Message_GetOrCreateMutableMap(msg, &field, $5, $6, a);
470 }
471 )cc",
472 msg_name, resolved_name, kMapGetterPostfix, kMutableMapGetterPostfix,
473 FieldInitializer(pools, field, options),
474 MapKeySize(field, MapKeyCType(field)),
475 MapValueSize(field, MapValueCType(field)));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700476}
477
478void GenerateMapEntryGetters(upb::FieldDefPtr field, absl::string_view msg_name,
479 Output& output) {
480 output(
481 R"cc(
482 UPB_INLINE $0 $1_$2(const $1* msg) {
483 $3 ret;
484 _upb_msg_map_$2(msg, &ret, $4);
485 return ret;
486 }
487 )cc",
488 CTypeConst(field), msg_name, field.name(), CType(field),
489 field.ctype() == kUpb_CType_String ? "0" : "sizeof(ret)");
490}
491
492void GenerateRepeatedGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
493 absl::string_view msg_name,
494 const NameToFieldDefMap& field_names,
495 const Options& options, Output& output) {
496 // Generate getter returning first item and size.
497 //
498 // Example:
499 // UPB_INLINE const struct Bar* const* name(const Foo* msg, size_t* size)
500 output(
501 R"cc(
502 UPB_INLINE $0 const* $1_$2(const $1* msg, size_t* size) {
503 const upb_MiniTableField field = $3;
504 const upb_Array* arr = upb_Message_GetArray(msg, &field);
505 if (arr) {
506 if (size) *size = arr->size;
507 return ($0 const*)_upb_array_constptr(arr);
508 } else {
509 if (size) *size = 0;
510 return NULL;
511 }
512 }
513 )cc",
514 CTypeConst(field), // $0
515 msg_name, // $1
516 ResolveFieldName(field, field_names), // $2
517 FieldInitializer(pools, field, options) // #3
518 );
519 // Generate private getter returning array or NULL for immutable and upb_Array
520 // for mutable.
521 //
522 // Example:
523 // UPB_INLINE const upb_Array* _name_upbarray(size_t* size)
524 // UPB_INLINE upb_Array* _name_mutable_upbarray(size_t* size)
525 output(
526 R"cc(
527 UPB_INLINE const upb_Array* _$1_$2_$4(const $1* msg, size_t* size) {
528 const upb_MiniTableField field = $3;
529 const upb_Array* arr = upb_Message_GetArray(msg, &field);
530 if (size) {
531 *size = arr ? arr->size : 0;
532 }
533 return arr;
534 }
535 UPB_INLINE upb_Array* _$1_$2_$5(const $1* msg, size_t* size, upb_Arena* arena) {
536 const upb_MiniTableField field = $3;
537 upb_Array* arr = upb_Message_GetOrCreateMutableArray(
538 (upb_Message*)msg, &field, arena);
539 if (size) {
540 *size = arr ? arr->size : 0;
541 }
542 return arr;
543 }
544 )cc",
545 CTypeConst(field), // $0
546 msg_name, // $1
547 ResolveFieldName(field, field_names), // $2
548 FieldInitializer(pools, field, options), // $3
549 kRepeatedFieldArrayGetterPostfix, // $4
550 kRepeatedFieldMutableArrayGetterPostfix // $5
551 );
552}
553
554void GenerateScalarGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
555 absl::string_view msg_name,
556 const NameToFieldDefMap& field_names,
557 const Options& Options, Output& output) {
558 std::string field_name = ResolveFieldName(field, field_names);
559 output(
560 R"cc(
561 UPB_INLINE $0 $1_$2(const $1* msg) {
562 $0 default_val = $3;
563 $0 ret;
564 const upb_MiniTableField field = $4;
565 _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret);
566 return ret;
567 }
568 )cc",
569 CTypeConst(field), msg_name, field_name, FieldDefault(field),
570 FieldInitializer(pools, field, Options));
571}
572
573void GenerateGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
574 absl::string_view msg_name,
575 const NameToFieldDefMap& field_names,
576 const Options& options, Output& output) {
577 if (field.IsMap()) {
578 GenerateMapGetters(field, pools, msg_name, field_names, options, output);
579 } else if (UPB_DESC(MessageOptions_map_entry)(
580 field.containing_type().options())) {
581 GenerateMapEntryGetters(field, msg_name, output);
582 } else if (field.IsSequence()) {
583 GenerateRepeatedGetters(field, pools, msg_name, field_names, options,
584 output);
585 } else {
586 GenerateScalarGetters(field, pools, msg_name, field_names, options, output);
587 }
588}
589
590void GenerateMapSetters(upb::FieldDefPtr field, const DefPoolPair& pools,
591 absl::string_view msg_name,
592 const NameToFieldDefMap& field_names,
593 const Options& options, Output& output) {
594 std::string resolved_name = ResolveFieldName(field, field_names);
595 output(
596 R"cc(
597 UPB_INLINE void $0_$1_clear($0* msg) {
598 const upb_MiniTableField field = $2;
599 upb_Map* map = (upb_Map*)upb_Message_GetMap(msg, &field);
600 if (!map) return;
601 _upb_Map_Clear(map);
602 }
603 )cc",
604 msg_name, resolved_name, FieldInitializer(pools, field, options));
605 output(
606 R"cc(
607 UPB_INLINE bool $0_$1_set($0* msg, $2 key, $3 val, upb_Arena* a) {
608 const upb_MiniTableField field = $4;
609 upb_Map* map = _upb_Message_GetOrCreateMutableMap(msg, &field, $5, $6, a);
610 return _upb_Map_Insert(map, &key, $5, &val, $6, a) !=
611 kUpb_MapInsertStatus_OutOfMemory;
612 }
613 )cc",
614 msg_name, resolved_name, MapKeyCType(field), MapValueCType(field),
615 FieldInitializer(pools, field, options), MapKeySize(field, "key"),
616 MapValueSize(field, "val"));
617 output(
618 R"cc(
619 UPB_INLINE bool $0_$1_delete($0* msg, $2 key) {
620 const upb_MiniTableField field = $3;
621 upb_Map* map = (upb_Map*)upb_Message_GetMap(msg, &field);
622 if (!map) return false;
623 return _upb_Map_Delete(map, &key, $4, NULL);
624 }
625 )cc",
626 msg_name, resolved_name, MapKeyCType(field),
627 FieldInitializer(pools, field, options), MapKeySize(field, "key"));
628 output(
629 R"cc(
630 UPB_INLINE $0 $1_$2_nextmutable($1* msg, size_t* iter) {
631 const upb_MiniTableField field = $3;
632 upb_Map* map = (upb_Map*)upb_Message_GetMap(msg, &field);
633 if (!map) return NULL;
634 return ($0)_upb_map_next(map, iter);
635 }
636 )cc",
637 CType(field), msg_name, resolved_name,
638 FieldInitializer(pools, field, options));
639}
640
641void GenerateRepeatedSetters(upb::FieldDefPtr field, const DefPoolPair& pools,
642 absl::string_view msg_name,
643 const NameToFieldDefMap& field_names,
644 const Options& options, Output& output) {
645 std::string resolved_name = ResolveFieldName(field, field_names);
646 output(
647 R"cc(
648 UPB_INLINE $0* $1_mutable_$2($1* msg, size_t* size) {
649 upb_MiniTableField field = $3;
650 upb_Array* arr = upb_Message_GetMutableArray(msg, &field);
651 if (arr) {
652 if (size) *size = arr->size;
653 return ($0*)_upb_array_ptr(arr);
654 } else {
655 if (size) *size = 0;
656 return NULL;
657 }
658 }
659 )cc",
660 CType(field), msg_name, resolved_name,
661 FieldInitializer(pools, field, options));
662 output(
663 R"cc(
664 UPB_INLINE $0* $1_resize_$2($1* msg, size_t size, upb_Arena* arena) {
665 upb_MiniTableField field = $3;
666 return ($0*)upb_Message_ResizeArrayUninitialized(msg, &field, size, arena);
667 }
668 )cc",
669 CType(field), msg_name, resolved_name,
670 FieldInitializer(pools, field, options));
671 if (field.ctype() == kUpb_CType_Message) {
672 output(
673 R"cc(
674 UPB_INLINE struct $0* $1_add_$2($1* msg, upb_Arena* arena) {
675 upb_MiniTableField field = $4;
676 upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, &field, arena);
677 if (!arr || !_upb_Array_ResizeUninitialized(arr, arr->size + 1, arena)) {
678 return NULL;
679 }
Eric Salo07556212023-12-05 17:40:25 -0800680 struct $0* sub = (struct $0*)_upb_Message_New($3, arena);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700681 if (!arr || !sub) return NULL;
Eric Salo3ce2c572023-11-27 10:45:25 -0800682 UPB_PRIVATE(_upb_Array_Set)(arr, arr->size - 1, &sub, sizeof(sub));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700683 return sub;
684 }
685 )cc",
686 MessageName(field.message_type()), msg_name, resolved_name,
687 MessageMiniTableRef(field.message_type(), options),
688 FieldInitializer(pools, field, options));
689 } else {
690 output(
691 R"cc(
692 UPB_INLINE bool $1_add_$2($1* msg, $0 val, upb_Arena* arena) {
693 upb_MiniTableField field = $3;
694 upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, &field, arena);
695 if (!arr || !_upb_Array_ResizeUninitialized(arr, arr->size + 1, arena)) {
696 return false;
697 }
Eric Salo3ce2c572023-11-27 10:45:25 -0800698 UPB_PRIVATE(_upb_Array_Set)(arr, arr->size - 1, &val, sizeof(val));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700699 return true;
700 }
701 )cc",
702 CType(field), msg_name, resolved_name,
703 FieldInitializer(pools, field, options));
704 }
705}
706
707void GenerateNonRepeatedSetters(upb::FieldDefPtr field,
708 const DefPoolPair& pools,
709 absl::string_view msg_name,
710 const NameToFieldDefMap& field_names,
711 const Options& options, Output& output) {
712 if (field == field.containing_type().map_key()) {
713 // Key cannot be mutated.
714 return;
715 }
716
717 std::string field_name = ResolveFieldName(field, field_names);
718
719 if (field == field.containing_type().map_value()) {
720 output(R"cc(
721 UPB_INLINE void $0_set_$1($0 *msg, $2 value) {
722 _upb_msg_map_set_value(msg, &value, $3);
723 }
724 )cc",
725 msg_name, field_name, CType(field),
726 field.ctype() == kUpb_CType_String ? "0"
727 : "sizeof(" + CType(field) + ")");
728 } else {
729 output(R"cc(
730 UPB_INLINE void $0_set_$1($0 *msg, $2 value) {
731 const upb_MiniTableField field = $3;
732 _upb_Message_SetNonExtensionField(msg, &field, &value);
733 }
734 )cc",
735 msg_name, field_name, CType(field),
736 FieldInitializer(pools, field, options));
737 }
738
739 // Message fields also have a Msg_mutable_foo() accessor that will create
740 // the sub-message if it doesn't already exist.
741 if (field.ctype() == kUpb_CType_Message &&
742 !UPB_DESC(MessageOptions_map_entry)(field.containing_type().options())) {
743 output(
744 R"cc(
745 UPB_INLINE struct $0* $1_mutable_$2($1* msg, upb_Arena* arena) {
746 struct $0* sub = (struct $0*)$1_$2(msg);
747 if (sub == NULL) {
Eric Salo07556212023-12-05 17:40:25 -0800748 sub = (struct $0*)_upb_Message_New($3, arena);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700749 if (sub) $1_set_$2(msg, sub);
750 }
751 return sub;
752 }
753 )cc",
754 MessageName(field.message_type()), msg_name, field_name,
755 MessageMiniTableRef(field.message_type(), options));
756 }
757}
758
759void GenerateSetters(upb::FieldDefPtr field, const DefPoolPair& pools,
760 absl::string_view msg_name,
761 const NameToFieldDefMap& field_names,
762 const Options& options, Output& output) {
763 if (field.IsMap()) {
764 GenerateMapSetters(field, pools, msg_name, field_names, options, output);
765 } else if (field.IsSequence()) {
766 GenerateRepeatedSetters(field, pools, msg_name, field_names, options,
767 output);
768 } else {
769 GenerateNonRepeatedSetters(field, pools, msg_name, field_names, options,
770 output);
771 }
772}
773
774void GenerateMessageInHeader(upb::MessageDefPtr message,
775 const DefPoolPair& pools, const Options& options,
776 Output& output) {
777 output("/* $0 */\n\n", message.full_name());
778 std::string msg_name = ToCIdent(message.full_name());
779 if (!UPB_DESC(MessageOptions_map_entry)(message.options())) {
780 GenerateMessageFunctionsInHeader(message, options, output);
781 }
782
783 for (int i = 0; i < message.real_oneof_count(); i++) {
784 GenerateOneofInHeader(message.oneof(i), pools, msg_name, options, output);
785 }
786
787 auto field_names = CreateFieldNameMap(message);
788 for (auto field : FieldNumberOrder(message)) {
789 GenerateClear(field, pools, msg_name, field_names, options, output);
790 GenerateGetters(field, pools, msg_name, field_names, options, output);
791 GenerateHazzer(field, pools, msg_name, field_names, options, output);
792 }
793
794 output("\n");
795
796 for (auto field : FieldNumberOrder(message)) {
797 GenerateSetters(field, pools, msg_name, field_names, options, output);
798 }
799
800 output("\n");
801}
802
Adam Cozzette501ecec2023-09-26 14:36:20 -0700803std::vector<upb::MessageDefPtr> SortedForwardMessages(
804 const std::vector<upb::MessageDefPtr>& this_file_messages,
805 const std::vector<upb::FieldDefPtr>& this_file_exts) {
806 std::map<std::string, upb::MessageDefPtr> forward_messages;
807 for (auto message : this_file_messages) {
808 for (int i = 0; i < message.field_count(); i++) {
809 upb::FieldDefPtr field = message.field(i);
810 if (field.ctype() == kUpb_CType_Message &&
811 field.file() != field.message_type().file()) {
812 forward_messages[field.message_type().full_name()] =
813 field.message_type();
814 }
815 }
816 }
817 for (auto ext : this_file_exts) {
818 if (ext.file() != ext.containing_type().file()) {
819 forward_messages[ext.containing_type().full_name()] =
820 ext.containing_type();
821 }
822 }
823 std::vector<upb::MessageDefPtr> ret;
824 ret.reserve(forward_messages.size());
825 for (const auto& pair : forward_messages) {
826 ret.push_back(pair.second);
827 }
828 return ret;
829}
830
831void WriteHeader(const DefPoolPair& pools, upb::FileDefPtr file,
832 const Options& options, Output& output) {
833 const std::vector<upb::MessageDefPtr> this_file_messages =
834 SortedMessages(file);
835 const std::vector<upb::FieldDefPtr> this_file_exts = SortedExtensions(file);
Joshua Habermancf3a6f52023-11-07 12:22:10 -0800836 std::vector<upb::EnumDefPtr> this_file_enums = SortedEnums(file, kAllEnums);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700837 std::vector<upb::MessageDefPtr> forward_messages =
838 SortedForwardMessages(this_file_messages, this_file_exts);
839
840 EmitFileWarning(file.name(), output);
841 output(
842 "#ifndef $0_UPB_H_\n"
843 "#define $0_UPB_H_\n\n"
844 "#include \"upb/generated_code_support.h\"\n\n",
845 ToPreproc(file.name()));
846
847 for (int i = 0; i < file.public_dependency_count(); i++) {
848 if (i == 0) {
849 output("/* Public Imports. */\n");
850 }
851 output("#include \"$0\"\n", CApiHeaderFilename(file.public_dependency(i)));
852 }
853 if (file.public_dependency_count() > 0) {
854 output("\n");
855 }
856
857 if (!options.bootstrap) {
858 output("#include \"$0\"\n\n", MiniTableHeaderFilename(file));
859 for (int i = 0; i < file.dependency_count(); i++) {
860 output("#include \"$0\"\n", MiniTableHeaderFilename(file.dependency(i)));
861 }
862 if (file.dependency_count() > 0) {
863 output("\n");
864 }
865 }
866
867 output(
868 "// Must be last.\n"
869 "#include \"upb/port/def.inc\"\n"
870 "\n"
871 "#ifdef __cplusplus\n"
872 "extern \"C\" {\n"
873 "#endif\n"
874 "\n");
875
876 if (options.bootstrap) {
877 for (auto message : this_file_messages) {
878 output("extern const upb_MiniTable* $0();\n", MessageInitName(message));
879 }
880 for (auto message : forward_messages) {
881 output("extern const upb_MiniTable* $0();\n", MessageInitName(message));
882 }
883 for (auto enumdesc : this_file_enums) {
884 output("extern const upb_MiniTableEnum* $0();\n", EnumInit(enumdesc));
885 }
886 output("\n");
887 }
888
889 // Forward-declare types defined in this file.
890 for (auto message : this_file_messages) {
891 output("typedef struct $0 $0;\n", ToCIdent(message.full_name()));
892 }
893
894 // Forward-declare types not in this file, but used as submessages.
895 // Order by full name for consistent ordering.
896 for (auto msg : forward_messages) {
897 output("struct $0;\n", MessageName(msg));
898 }
899
900 if (!this_file_messages.empty()) {
901 output("\n");
902 }
903
904 for (auto enumdesc : this_file_enums) {
905 output("typedef enum {\n");
906 DumpEnumValues(enumdesc, output);
907 output("} $0;\n\n", ToCIdent(enumdesc.full_name()));
908 }
909
910 output("\n");
911
912 output("\n");
913 for (auto message : this_file_messages) {
914 GenerateMessageInHeader(message, pools, options, output);
915 }
916
917 for (auto ext : this_file_exts) {
918 GenerateExtensionInHeader(pools, ext, output);
919 }
920
921 if (absl::string_view(file.name()) == "google/protobuf/descriptor.proto" ||
922 absl::string_view(file.name()) == "net/proto2/proto/descriptor.proto") {
923 // This is gratuitously inefficient with how many times it rebuilds
924 // MessageLayout objects for the same message. But we only do this for one
925 // proto (descriptor.proto) so we don't worry about it.
926 upb::MessageDefPtr max32_message;
927 upb::MessageDefPtr max64_message;
928 size_t max32 = 0;
929 size_t max64 = 0;
930 for (const auto message : this_file_messages) {
931 if (absl::EndsWith(message.name(), "Options")) {
Eric Salob64c6e12023-12-05 08:57:27 -0800932 size_t size32 = pools.GetMiniTable32(message)->UPB_PRIVATE(size);
933 size_t size64 = pools.GetMiniTable64(message)->UPB_PRIVATE(size);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700934 if (size32 > max32) {
935 max32 = size32;
936 max32_message = message;
937 }
938 if (size64 > max64) {
939 max64 = size64;
940 max64_message = message;
941 }
942 }
943 }
944
945 output("/* Max size 32 is $0 */\n", max32_message.full_name());
946 output("/* Max size 64 is $0 */\n", max64_message.full_name());
947 output("#define _UPB_MAXOPT_SIZE UPB_SIZE($0, $1)\n\n", max32, max64);
948 }
949
950 output(
951 "#ifdef __cplusplus\n"
952 "} /* extern \"C\" */\n"
953 "#endif\n"
954 "\n"
955 "#include \"upb/port/undef.inc\"\n"
956 "\n"
957 "#endif /* $0_UPB_H_ */\n",
958 ToPreproc(file.name()));
959}
960
961std::string FieldInitializer(upb::FieldDefPtr field,
962 const upb_MiniTableField* field64,
963 const upb_MiniTableField* field32,
964 const Options& options) {
965 if (options.bootstrap) {
966 ABSL_CHECK(!field.is_extension());
967 return absl::Substitute(
968 "*upb_MiniTable_FindFieldByNumber($0, $1)",
969 MessageMiniTableRef(field.containing_type(), options), field.number());
970 } else {
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700971 return upb::generator::FieldInitializer(field, field64, field32);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700972 }
973}
974
975std::string FieldInitializer(const DefPoolPair& pools, upb::FieldDefPtr field,
976 const Options& options) {
977 return FieldInitializer(field, pools.GetField64(field),
978 pools.GetField32(field), options);
979}
980
981void WriteMessageMiniDescriptorInitializer(upb::MessageDefPtr msg,
982 const Options& options,
983 Output& output) {
984 Output resolve_calls;
985 for (int i = 0; i < msg.field_count(); i++) {
986 upb::FieldDefPtr field = msg.field(i);
987 if (!field.message_type() && !field.enum_subdef()) continue;
988 if (field.message_type()) {
989 resolve_calls(
990 "upb_MiniTable_SetSubMessage(mini_table, "
991 "(upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, "
992 "$0), $1);\n ",
993 field.number(), MessageMiniTableRef(field.message_type(), options));
994 } else if (field.enum_subdef() && field.enum_subdef().is_closed()) {
995 resolve_calls(
996 "upb_MiniTable_SetSubEnum(mini_table, "
997 "(upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, "
998 "$0), $1);\n ",
999 field.number(), EnumMiniTableRef(field.enum_subdef(), options));
1000 }
1001 }
1002
1003 output(
1004 R"cc(
1005 const upb_MiniTable* $0() {
1006 static upb_MiniTable* mini_table = NULL;
1007 static const char* mini_descriptor = "$1";
1008 if (mini_table) return mini_table;
1009 mini_table =
1010 upb_MiniTable_Build(mini_descriptor, strlen(mini_descriptor),
1011 upb_BootstrapArena(), NULL);
1012 $2return mini_table;
1013 }
1014 )cc",
1015 MessageInitName(msg), msg.MiniDescriptorEncode(), resolve_calls.output());
1016 output("\n");
1017}
1018
1019void WriteEnumMiniDescriptorInitializer(upb::EnumDefPtr enum_def,
1020 const Options& options,
1021 Output& output) {
1022 output(
1023 R"cc(
1024 const upb_MiniTableEnum* $0() {
1025 static const upb_MiniTableEnum* mini_table = NULL;
1026 static const char* mini_descriptor = "$1";
1027 if (mini_table) return mini_table;
1028 mini_table =
1029 upb_MiniTableEnum_Build(mini_descriptor, strlen(mini_descriptor),
1030 upb_BootstrapArena(), NULL);
1031 return mini_table;
1032 }
1033 )cc",
1034 EnumInitName(enum_def), enum_def.MiniDescriptorEncode());
1035 output("\n");
1036}
1037
1038void WriteMiniDescriptorSource(const DefPoolPair& pools, upb::FileDefPtr file,
1039 const Options& options, Output& output) {
1040 output(
1041 "#include <stddef.h>\n"
1042 "#include \"upb/generated_code_support.h\"\n"
1043 "#include \"$0\"\n\n",
1044 CApiHeaderFilename(file));
1045
1046 for (int i = 0; i < file.dependency_count(); i++) {
1047 output("#include \"$0\"\n", CApiHeaderFilename(file.dependency(i)));
1048 }
1049
1050 output(
1051 R"cc(
1052 static upb_Arena* upb_BootstrapArena() {
1053 static upb_Arena* arena = NULL;
1054 if (!arena) arena = upb_Arena_New();
1055 return arena;
1056 }
1057 )cc");
1058
1059 output("\n");
1060
1061 for (const auto msg : SortedMessages(file)) {
1062 WriteMessageMiniDescriptorInitializer(msg, options, output);
1063 }
1064
Joshua Habermancf3a6f52023-11-07 12:22:10 -08001065 for (const auto msg : SortedEnums(file, kClosedEnums)) {
Adam Cozzette501ecec2023-09-26 14:36:20 -07001066 WriteEnumMiniDescriptorInitializer(msg, options, output);
1067 }
1068}
1069
1070void GenerateFile(const DefPoolPair& pools, upb::FileDefPtr file,
1071 const Options& options, Plugin* plugin) {
1072 Output h_output;
1073 WriteHeader(pools, file, options, h_output);
1074 plugin->AddOutputFile(CApiHeaderFilename(file), h_output.output());
1075
1076 if (options.bootstrap) {
1077 Output c_output;
1078 WriteMiniDescriptorSource(pools, file, options, c_output);
1079 plugin->AddOutputFile(SourceFilename(file), c_output.output());
1080 } else {
1081 // TODO: remove once we can figure out how to make both Blaze
1082 // and Bazel happy with header-only libraries.
1083
1084 // begin:github_only
1085 plugin->AddOutputFile(SourceFilename(file), "\n");
1086 // end:github_only
1087 }
1088}
1089
1090bool ParseOptions(Plugin* plugin, Options* options) {
1091 for (const auto& pair : ParseGeneratorParameter(plugin->parameter())) {
1092 if (pair.first == "bootstrap_upb") {
1093 options->bootstrap = true;
1094 } else {
1095 plugin->SetError(absl::Substitute("Unknown parameter: $0", pair.first));
1096 return false;
1097 }
1098 }
1099
1100 return true;
1101}
1102
1103absl::string_view ToStringView(upb_StringView str) {
1104 return absl::string_view(str.data, str.size);
1105}
1106
1107} // namespace
1108
Adam Cozzette12c7bb02023-09-28 12:54:11 -07001109} // namespace generator
1110} // namespace upb
Adam Cozzette501ecec2023-09-26 14:36:20 -07001111
1112int main(int argc, char** argv) {
Adam Cozzette12c7bb02023-09-28 12:54:11 -07001113 upb::generator::DefPoolPair pools;
1114 upb::generator::Plugin plugin;
1115 upb::generator::Options options;
Adam Cozzette501ecec2023-09-26 14:36:20 -07001116 if (!ParseOptions(&plugin, &options)) return 0;
Jakob Buchgraberebdd7e32023-10-30 01:02:10 -07001117 plugin.GenerateFilesRaw(
1118 [&](const UPB_DESC(FileDescriptorProto) * file_proto, bool generate) {
1119 upb::Status status;
1120 upb::FileDefPtr file = pools.AddFile(file_proto, &status);
1121 if (!file) {
1122 absl::string_view name = upb::generator::ToStringView(
1123 UPB_DESC(FileDescriptorProto_name)(file_proto));
1124 ABSL_LOG(FATAL) << "Couldn't add file " << name
1125 << " to DefPool: " << status.error_message();
1126 }
1127 if (generate) GenerateFile(pools, file, options, &plugin);
1128 });
Adam Cozzette501ecec2023-09-26 14:36:20 -07001129 return 0;
1130}