From e3d2551c8e7fe3e4698e8c0d679278bc0c575efe Mon Sep 17 00:00:00 2001 From: Alyssa Haroldsen Date: Mon, 8 Jan 2024 19:25:18 -0800 Subject: [PATCH] Move enum value name calculation PiperOrigin-RevId: 596767666 --- src/google/protobuf/compiler/rust/BUILD.bazel | 1 + src/google/protobuf/compiler/rust/enum.cc | 40 +------------- src/google/protobuf/compiler/rust/naming.cc | 54 +++++++++++++++++++ src/google/protobuf/compiler/rust/naming.h | 22 ++++++++ 4 files changed, 79 insertions(+), 38 deletions(-) diff --git a/src/google/protobuf/compiler/rust/BUILD.bazel b/src/google/protobuf/compiler/rust/BUILD.bazel index 52721ad266..ae1f9c46a3 100644 --- a/src/google/protobuf/compiler/rust/BUILD.bazel +++ b/src/google/protobuf/compiler/rust/BUILD.bazel @@ -152,6 +152,7 @@ cc_library( "//src/google/protobuf", "//src/google/protobuf/compiler:code_generator", "//src/google/protobuf/compiler/cpp:names_internal", + "@com_google_absl//absl/log:absl_check", "@com_google_absl//absl/log:absl_log", "@com_google_absl//absl/strings", ], diff --git a/src/google/protobuf/compiler/rust/enum.cc b/src/google/protobuf/compiler/rust/enum.cc index 2f4b08da17..7539dedfc8 100644 --- a/src/google/protobuf/compiler/rust/enum.cc +++ b/src/google/protobuf/compiler/rust/enum.cc @@ -17,12 +17,9 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/log/absl_check.h" -#include "absl/strings/ascii.h" -#include "absl/strings/match.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" #include "absl/strings/string_view.h" -#include "absl/strings/strip.h" #include "absl/types/span.h" #include "google/protobuf/compiler/rust/context.h" #include "google/protobuf/compiler/rust/naming.h" @@ -52,17 +49,7 @@ std::vector> EnumValuesInput( std::vector EnumValues( absl::string_view enum_name, absl::Span> values) { - // Enum values may have a prefix of the name of the enum stripped from the - // value names in the gencode. This prefix is flexible: - // - It can be the original enum name, the name as UpperCamel, or snake_case. - // - The stripped prefix may also end in an underscore. - - // The set of prefixes that will be stripped. - std::initializer_list prefixes = { - std::string(enum_name), - ScreamingSnakeToUpperCamelCase(enum_name), - CamelToSnakeCase(enum_name), - }; + MultiCasePrefixStripper stripper(enum_name); absl::flat_hash_set seen_by_name; absl::flat_hash_map seen_by_number; @@ -74,32 +61,9 @@ std::vector EnumValues( seen_by_number.reserve(values.size()); for (const auto& name_and_number : values) { - absl::string_view base_value_name = name_and_number.first; - for (absl::string_view prefix : prefixes) { - if (absl::StartsWithIgnoreCase(base_value_name, prefix)) { - base_value_name.remove_prefix(prefix.size()); - - // Also strip a joining underscore, if present. - absl::ConsumePrefix(&base_value_name, "_"); - - // Only strip one prefix. - break; - } - } - - if (base_value_name.empty()) { - // The enum value name has a similar name to the enum - don't strip. - base_value_name = name_and_number.first; - } - int32_t number = name_and_number.second; std::string rust_value_name = - ScreamingSnakeToUpperCamelCase(base_value_name); - - // Invalid identifiers are prefixed with `_`. - if (absl::ascii_isdigit(rust_value_name[0])) { - rust_value_name = absl::StrCat("_", rust_value_name); - } + EnumValueRsName(stripper, name_and_number.first); if (seen_by_name.contains(rust_value_name)) { // Don't add an alias with the same normalized name. diff --git a/src/google/protobuf/compiler/rust/naming.cc b/src/google/protobuf/compiler/rust/naming.cc index aef71565c4..0f83320255 100644 --- a/src/google/protobuf/compiler/rust/naming.cc +++ b/src/google/protobuf/compiler/rust/naming.cc @@ -10,13 +10,16 @@ #include #include +#include "absl/log/absl_check.h" #include "absl/log/absl_log.h" #include "absl/strings/ascii.h" +#include "absl/strings/match.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" #include "absl/strings/str_replace.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" +#include "absl/strings/strip.h" #include "absl/strings/substitute.h" #include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/compiler/cpp/helpers.h" @@ -257,6 +260,29 @@ std::string EnumRsName(const EnumDescriptor& desc) { return SnakeToUpperCamelCase(desc.name()); } +std::string EnumValueRsName(const EnumValueDescriptor& value) { + MultiCasePrefixStripper stripper(value.type()->name()); + return EnumValueRsName(stripper, value.name()); +} + +std::string EnumValueRsName(const MultiCasePrefixStripper& stripper, + absl::string_view value_name) { + // Enum values may have a prefix of the name of the enum stripped from the + // value names in the gencode. This prefix is flexible: + // - It can be the original enum name, the name as UpperCamel, or snake_case. + // - The stripped prefix may also end in an underscore. + auto stripped = stripper.StripPrefix(value_name); + + auto name = ScreamingSnakeToUpperCamelCase(stripped); + ABSL_CHECK(!name.empty()); + + // Invalid identifiers are prefixed with `_`. + if (absl::ascii_isdigit(name[0])) { + name = absl::StrCat("_", name); + } + return name; +} + std::string OneofViewEnumRsName(const OneofDescriptor& oneof) { return SnakeToUpperCamelCase(oneof.name()); } @@ -318,6 +344,34 @@ std::string ScreamingSnakeToUpperCamelCase(absl::string_view input) { return result; } +MultiCasePrefixStripper::MultiCasePrefixStripper(absl::string_view prefix) + : prefixes_{ + std::string(prefix), + ScreamingSnakeToUpperCamelCase(prefix), + CamelToSnakeCase(prefix), + } {} + +absl::string_view MultiCasePrefixStripper::StripPrefix( + absl::string_view name) const { + absl::string_view start_name = name; + for (absl::string_view prefix : prefixes_) { + if (absl::StartsWithIgnoreCase(name, prefix)) { + name.remove_prefix(prefix.size()); + + // Also strip a joining underscore, if present. + absl::ConsumePrefix(&name, "_"); + + // Only strip one prefix. + break; + } + } + + if (name.empty()) { + return start_name; + } + return name; +} + } // namespace rust } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/rust/naming.h b/src/google/protobuf/compiler/rust/naming.h index 532863ce31..a5bdeb15c2 100644 --- a/src/google/protobuf/compiler/rust/naming.h +++ b/src/google/protobuf/compiler/rust/naming.h @@ -8,6 +8,7 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_RUST_NAMING_H__ #define GOOGLE_PROTOBUF_COMPILER_RUST_NAMING_H__ +#include #include #include "absl/strings/string_view.h" @@ -39,6 +40,7 @@ std::string ThunkName(Context& ctx, const Descriptor& msg, std::string RsTypePath(Context& ctx, const FieldDescriptor& field); std::string EnumRsName(const EnumDescriptor& desc); +std::string EnumValueRsName(const EnumValueDescriptor& value); std::string OneofViewEnumRsName(const OneofDescriptor& oneof); std::string OneofMutEnumRsName(const OneofDescriptor& oneof); @@ -75,6 +77,26 @@ std::string SnakeToUpperCamelCase(absl::string_view input); // Converts a SCREAMING_SNAKE_CASE string to an UpperCamelCase string. std::string ScreamingSnakeToUpperCamelCase(absl::string_view input); +// Given a fixed prefix, this will repeatedly strip provided +// string_views if they start with the prefix, the prefix in UpperCamel, or +// the prefix in snake_case. +class MultiCasePrefixStripper final { + public: + explicit MultiCasePrefixStripper(absl::string_view prefix); + + // Strip a prefix from the name in UpperCamel or snake_case, if present. + // If there is an underscore after the prefix, that will also be stripped. + // The stripping is case-insensitive. + absl::string_view StripPrefix(absl::string_view name) const; + + private: + std::array prefixes_; +}; + +// More efficient overload if a stripper is already constructed. +std::string EnumValueRsName(const MultiCasePrefixStripper& stripper, + absl::string_view value_name); + } // namespace rust } // namespace compiler } // namespace protobuf