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 #ifndef THIRD_PARTY_UPB_UPB_GENERATOR_C_NAMES_H_
9 #define THIRD_PARTY_UPB_UPB_GENERATOR_C_NAMES_H_
10
11 #include <string>
12
13 #include "absl/container/flat_hash_map.h"
14 #include "absl/strings/string_view.h"
15
16 namespace upb {
17 namespace generator {
18
19 // Note: these names are not currently exported, in hopes that no code
20 // generators outside of the protobuf repo will ever use the generated C API.
21
22 // Maps: foo/bar/baz.proto -> foo/bar/baz.upb.h
23 std::string CApiHeaderFilename(absl::string_view proto_filename);
24
25 // The foo.upb.h file defines far more symbols than we currently enumerate here.
26 // We do the bare minimum by by defining the type name for messages and enums,
27 // which also forms the symbol prefix for associated functions.
28 //
29 // typedef struct { /* ... */ } <MessageType>;
30 // typedef enum { <EnumValue> = X, ... } <EnumType>;
31 //
32 // Oneofs and extensions have a base name that forms the prefix for associated
33 // functions.
34
35 std::string CApiMessageType(absl::string_view full_name);
36 std::string CApiEnumType(absl::string_view full_name);
37 std::string CApiEnumValueSymbol(absl::string_view full_name);
38 std::string CApiExtensionIdentBase(absl::string_view full_name);
39 std::string CApiOneofIdentBase(absl::string_view full_name);
40
41 // Name mangling for individual fields. NameMangler maps each field name to a
42 // mangled name, which tries to avoid collisions with other field accessors.
43 //
44 // For example, a field named "clear_foo" might be renamed to "clear_foo_" if
45 // there is a field named "foo" in the same message.
46 //
47 // This API would be more principled if it generated a full symbol name for each
48 // generated API function, eg.
49 // mangler.GetSetter("clear_foo") -> "mypkg_MyMessage_set_clear_foo_"
50 // mangler.GetHazzer("clear_foo") -> "mypkg_MyMessage_has_clear_foo_"
51 //
52 // But that would be a larger and more complicated API. In the long run, we
53 // probably don't want to have other code generators wrapping these APIs, so
54 // it's probably not worth designing a fully principled API.
55
56 enum FieldClass {
57 kStringField = 1 << 0,
58 kContainerField = 1 << 1,
59 kOtherField = 1 << 2,
60 };
61
62 class NameMangler {
63 public:
64 explicit NameMangler(
65 const absl::flat_hash_map<std::string, FieldClass>& fields);
66
ResolveFieldName(absl::string_view name)67 std::string ResolveFieldName(absl::string_view name) const {
68 auto it = names_.find(name);
69 return it == names_.end() ? std::string(name) : it->second;
70 }
71
72 private:
73 // Maps field_name -> mangled_name. If a field name is not in the map, it
74 // is not mangled.
75 absl::flat_hash_map<std::string, std::string> names_;
76 };
77
78 // Here we provide functions for building field lists from both C++ and upb
79 // reflection. They are templated so as to not actually introduce dependencies
80 // on either C++ or upb.
81
82 template <class T>
GetCppFields(const T * descriptor)83 absl::flat_hash_map<std::string, FieldClass> GetCppFields(const T* descriptor) {
84 absl::flat_hash_map<std::string, FieldClass> fields;
85 for (int i = 0; i < descriptor->field_count(); ++i) {
86 const auto* field = descriptor->field(i);
87 if (field->is_repeated() || field->is_map()) {
88 fields.emplace(field->name(), kContainerField);
89 } else if (field->cpp_type() == field->CPPTYPE_STRING) {
90 fields.emplace(field->name(), kStringField);
91 } else {
92 fields.emplace(field->name(), kOtherField);
93 }
94 }
95 return fields;
96 }
97
98 template <class T>
GetUpbFields(const T & msg_def)99 absl::flat_hash_map<std::string, FieldClass> GetUpbFields(const T& msg_def) {
100 absl::flat_hash_map<std::string, FieldClass> fields;
101 for (const auto field : msg_def.fields()) {
102 if (field.IsSequence() || field.IsMap()) {
103 fields.emplace(field.name(), kContainerField);
104 } else if (field.ctype() == decltype(field)::CType::kUpb_CType_String) {
105 fields.emplace(field.name(), kStringField);
106 } else {
107 fields.emplace(field.name(), kOtherField);
108 }
109 }
110 return fields;
111 }
112
113 ABSL_CONST_INIT const absl::string_view kRepeatedFieldArrayGetterPostfix =
114 "upb_array";
115 ABSL_CONST_INIT const absl::string_view
116 kRepeatedFieldMutableArrayGetterPostfix = "mutable_upb_array";
117
118 ABSL_CONST_INIT const absl::string_view kMapGetterPostfix = "upb_map";
119 ABSL_CONST_INIT const absl::string_view kMutableMapGetterPostfix =
120 "mutable_upb_map";
121
122 } // namespace generator
123 } // namespace upb
124
125 #endif // THIRD_PARTY_UPB_UPB_GENERATOR_C_NAMES_H_
126