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 GOOGLE_PROTOBUF_COMPILER_RUST_NAMING_H__ 9 #define GOOGLE_PROTOBUF_COMPILER_RUST_NAMING_H__ 10 11 #include <array> 12 #include <string> 13 14 #include "absl/strings/string_view.h" 15 #include "google/protobuf/compiler/rust/context.h" 16 #include "google/protobuf/descriptor.h" 17 #include "google/protobuf/descriptor.pb.h" 18 19 namespace google { 20 namespace protobuf { 21 namespace compiler { 22 namespace rust { 23 std::string GetCrateName(Context& ctx, const FileDescriptor& dep); 24 25 std::string GetRsFile(Context& ctx, const FileDescriptor& file); 26 std::string GetThunkCcFile(Context& ctx, const FileDescriptor& file); 27 std::string GetHeaderFile(Context& ctx, const FileDescriptor& file); 28 29 std::string ThunkName(Context& ctx, const FieldDescriptor& field, 30 absl::string_view op); 31 std::string ThunkName(Context& ctx, const OneofDescriptor& field, 32 absl::string_view op); 33 34 std::string ThunkName(Context& ctx, const Descriptor& msg, 35 absl::string_view op); 36 std::string RawMapThunk(Context& ctx, const Descriptor& msg, 37 absl::string_view key_t, absl::string_view op); 38 std::string RawMapThunk(Context& ctx, const EnumDescriptor& desc, 39 absl::string_view key_t, absl::string_view op); 40 41 // Returns an absolute path to the Proxied Rust type of the given field. 42 // The absolute path is guaranteed to work in the crate that defines the field. 43 // It may be crate-relative, or directly reference the owning crate of the type. 44 std::string RsTypePath(Context& ctx, const FieldDescriptor& field); 45 46 // Returns the 'simple spelling' of the Rust View type for the provided field. 47 // For example, `i32` for int32 fields and `SomeMsgView<'$lifetime$>` for 48 // message fields, or `SomeMsgView` if an empty lifetime is provided). 49 // 50 // The returned type will always be functionally substitutable for the 51 // corresponding View<'$lifetime$, $sometype$> of the field's Rust type. 52 std::string RsViewType(Context& ctx, const FieldDescriptor& field, 53 absl::string_view lifetime); 54 55 std::string EnumRsName(const EnumDescriptor& desc); 56 std::string EnumValueRsName(const EnumValueDescriptor& value); 57 58 std::string OneofViewEnumRsName(const OneofDescriptor& oneof); 59 std::string OneofCaseEnumRsName(const OneofDescriptor& oneof); 60 std::string OneofCaseRsName(const FieldDescriptor& oneof_field); 61 62 std::string FieldInfoComment(Context& ctx, const FieldDescriptor& field); 63 64 // Return how to name a field with 'collision avoidance'. This adds a suffix 65 // of the field number to the field name if it appears that it will collide with 66 // another field's non-getter accessor. 67 // 68 // For example, for the message: 69 // message M { bool set_x = 1; int32 x = 2; string x_mut = 8; } 70 // All accessors for the field `set_x` will be constructed as though the field 71 // was instead named `set_x_1`, and all accessors for `x_mut` will be as though 72 // the field was instead named `x_mut_8`. 73 // 74 // This is a best-effort heuristic to avoid realistic accidental 75 // collisions. It is still possible to create a message definition that will 76 // have a collision, and it may rename a field even if there's no collision (as 77 // in the case of x_mut in the example). 78 // 79 // Note the returned name may still be a rust keyword: RsSafeName() should 80 // additionally be used if there is no prefix/suffix being appended to the name. 81 std::string FieldNameWithCollisionAvoidance(const FieldDescriptor& field); 82 83 // Returns how to 'spell' the provided name in Rust, which is the provided name 84 // verbatim unless it is a Rust keyword that isn't a legal symbol name. 85 std::string RsSafeName(absl::string_view name); 86 87 // Constructs a string of the Rust modules which will contain the message. 88 // 89 // Example: Given a message 'NestedMessage' which is defined in package 'x.y' 90 // which is inside 'ParentMessage', the message will be placed in the 91 // x::y::ParentMessage_ Rust module, so this function will return the string 92 // "x::y::ParentMessage_::". 93 // 94 // If the message has no package and no containing messages then this returns 95 // empty string. 96 std::string RustModuleForContainingType(Context& ctx, 97 const Descriptor* containing_type); 98 std::string RustModule(Context& ctx, const Descriptor& msg); 99 std::string RustModule(Context& ctx, const EnumDescriptor& enum_); 100 std::string RustModule(Context& ctx, const OneofDescriptor& oneof); 101 std::string RustInternalModuleName(Context& ctx, const FileDescriptor& file); 102 103 std::string GetCrateRelativeQualifiedPath(Context& ctx, const Descriptor& msg); 104 std::string GetCrateRelativeQualifiedPath(Context& ctx, 105 const EnumDescriptor& enum_); 106 std::string GetCrateRelativeQualifiedPath(Context& ctx, 107 const OneofDescriptor& oneof); 108 109 template <typename Desc> 110 std::string GetUnderscoreDelimitedFullName(Context& ctx, const Desc& desc); 111 112 std::string UnderscoreDelimitFullName(Context& ctx, 113 absl::string_view full_name); 114 115 // TODO: Unify these with other case-conversion functions. 116 117 // Converts an UpperCamel or lowerCamel string to a snake_case string. 118 std::string CamelToSnakeCase(absl::string_view input); 119 120 // Converts a snake_case string to an UpperCamelCase string. 121 std::string SnakeToUpperCamelCase(absl::string_view input); 122 123 // Converts a SCREAMING_SNAKE_CASE string to an UpperCamelCase string. 124 std::string ScreamingSnakeToUpperCamelCase(absl::string_view input); 125 126 // Given a fixed prefix, this will repeatedly strip provided 127 // string_views if they start with the prefix, the prefix in UpperCamel, or 128 // the prefix in snake_case. 129 class MultiCasePrefixStripper final { 130 public: 131 explicit MultiCasePrefixStripper(absl::string_view prefix); 132 133 // Strip a prefix from the name in UpperCamel or snake_case, if present. 134 // If there is an underscore after the prefix, that will also be stripped. 135 // The stripping is case-insensitive. 136 absl::string_view StripPrefix(absl::string_view name) const; 137 138 private: 139 std::array<std::string, 3> prefixes_; 140 }; 141 142 // More efficient overload if a stripper is already constructed. 143 std::string EnumValueRsName(const MultiCasePrefixStripper& stripper, 144 absl::string_view value_name); 145 146 // Describes the names and conversions for a supported map key type. 147 struct MapKeyType { 148 // Identifier used in thunk name. 149 absl::string_view thunk_ident; 150 151 // Rust key typename (K in Map<K, V>, so e.g. `[u8]` for bytes). 152 // This field may have an unexpanded `$pb$` variable. 153 absl::string_view rs_key_t; 154 155 // Rust key typename used by thunks for FFI (e.g. `PtrAndLen` for bytes). 156 // This field may have an unexpanded `$pbi$` variable. 157 absl::string_view rs_ffi_key_t; 158 159 // Rust expression converting `key: rs_key_t` into an `rs_ffi_key_t`. 160 absl::string_view rs_to_ffi_key_expr; 161 162 // Rust expression converting `ffi_key: rs_ffi_key_t` into an `rs_key_t`. 163 // This field may have an unexpanded `$pb$` variable. 164 absl::string_view rs_from_ffi_key_expr; 165 166 // C++ key typename (K in Map<K, V>, so e.g. `std::string` for bytes). 167 absl::string_view cc_key_t; 168 169 // C++ key typename used by thunks for FFI (e.g. `PtrAndLen` for bytes). 170 absl::string_view cc_ffi_key_t; 171 172 // C++ expression converting `cc_ffi_key_t key` into a `cc_key_t`. 173 absl::string_view cc_from_ffi_key_expr; 174 175 // C++ expression converting `cc_key_t cpp_key` into a `cc_ffi_key_t`. 176 absl::string_view cc_to_ffi_key_expr; 177 }; 178 179 extern const MapKeyType kMapKeyTypes[6]; 180 181 } // namespace rust 182 } // namespace compiler 183 } // namespace protobuf 184 } // namespace google 185 186 #endif // GOOGLE_PROTOBUF_COMPILER_RUST_NAMING_H__ 187