|  | // Protocol Buffers - Google's data interchange format | 
|  | // Copyright 2023 Google LLC.  All rights reserved. | 
|  | // | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file or at | 
|  | // https://developers.google.com/open-source/licenses/bsd | 
|  |  | 
|  | #include "hpb_generator/gen_utils.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/log/absl_log.h" | 
|  | #include "absl/strings/ascii.h" | 
|  | #include "absl/strings/escaping.h" | 
|  | #include "absl/strings/str_cat.h" | 
|  | #include "absl/strings/str_replace.h" | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "google/protobuf/descriptor.h" | 
|  |  | 
|  | namespace { | 
|  | std::string EscapeTrigraphs(absl::string_view to_escape) { | 
|  | return absl::StrReplaceAll(to_escape, {{"?", "\\?"}}); | 
|  | } | 
|  | }  // namespace | 
|  |  | 
|  | namespace google { | 
|  | namespace protobuf { | 
|  | namespace hpb_generator { | 
|  |  | 
|  | void AddEnums(const google::protobuf::Descriptor* message, | 
|  | std::vector<const google::protobuf::EnumDescriptor*>* enums) { | 
|  | enums->reserve(enums->size() + message->enum_type_count()); | 
|  | for (int i = 0; i < message->enum_type_count(); i++) { | 
|  | enums->push_back(message->enum_type(i)); | 
|  | } | 
|  | for (int i = 0; i < message->nested_type_count(); i++) { | 
|  | AddEnums(message->nested_type(i), enums); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::vector<const google::protobuf::EnumDescriptor*> SortedEnums( | 
|  | const google::protobuf::FileDescriptor* file) { | 
|  | std::vector<const google::protobuf::EnumDescriptor*> enums; | 
|  | enums.reserve(file->enum_type_count()); | 
|  | for (int i = 0; i < file->enum_type_count(); i++) { | 
|  | enums.push_back(file->enum_type(i)); | 
|  | } | 
|  | for (int i = 0; i < file->message_type_count(); i++) { | 
|  | AddEnums(file->message_type(i), &enums); | 
|  | } | 
|  | return enums; | 
|  | } | 
|  |  | 
|  | void AddMessages(const google::protobuf::Descriptor* message, | 
|  | std::vector<const google::protobuf::Descriptor*>* messages) { | 
|  | messages->push_back(message); | 
|  | for (int i = 0; i < message->nested_type_count(); i++) { | 
|  | AddMessages(message->nested_type(i), messages); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::vector<const google::protobuf::Descriptor*> SortedMessages( | 
|  | const google::protobuf::FileDescriptor* file) { | 
|  | std::vector<const google::protobuf::Descriptor*> messages; | 
|  | for (int i = 0; i < file->message_type_count(); i++) { | 
|  | AddMessages(file->message_type(i), &messages); | 
|  | } | 
|  | return messages; | 
|  | } | 
|  |  | 
|  | void AddExtensionsFromMessage( | 
|  | const google::protobuf::Descriptor* message, | 
|  | std::vector<const google::protobuf::FieldDescriptor*>* exts) { | 
|  | for (int i = 0; i < message->extension_count(); i++) { | 
|  | exts->push_back(message->extension(i)); | 
|  | } | 
|  | for (int i = 0; i < message->nested_type_count(); i++) { | 
|  | AddExtensionsFromMessage(message->nested_type(i), exts); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::vector<const google::protobuf::FieldDescriptor*> SortedExtensions( | 
|  | const google::protobuf::FileDescriptor* file) { | 
|  | const int extension_count = file->extension_count(); | 
|  | const int message_type_count = file->message_type_count(); | 
|  |  | 
|  | std::vector<const google::protobuf::FieldDescriptor*> ret; | 
|  | ret.reserve(extension_count + message_type_count); | 
|  |  | 
|  | for (int i = 0; i < extension_count; i++) { | 
|  | ret.push_back(file->extension(i)); | 
|  | } | 
|  | for (int i = 0; i < message_type_count; i++) { | 
|  | AddExtensionsFromMessage(file->message_type(i), &ret); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | std::vector<const google::protobuf::FieldDescriptor*> FieldNumberOrder( | 
|  | const google::protobuf::Descriptor* message) { | 
|  | std::vector<const google::protobuf::FieldDescriptor*> fields; | 
|  | fields.reserve(message->field_count()); | 
|  | for (int i = 0; i < message->field_count(); i++) { | 
|  | fields.push_back(message->field(i)); | 
|  | } | 
|  | std::sort( | 
|  | fields.begin(), fields.end(), | 
|  | [](const google::protobuf::FieldDescriptor* a, const google::protobuf::FieldDescriptor* b) { | 
|  | return a->number() < b->number(); | 
|  | }); | 
|  | return fields; | 
|  | } | 
|  |  | 
|  | std::string ToCamelCase(const absl::string_view input, bool lower_first) { | 
|  | bool capitalize_next = !lower_first; | 
|  | std::string result; | 
|  | result.reserve(input.size()); | 
|  |  | 
|  | for (char character : input) { | 
|  | if (character == '_') { | 
|  | capitalize_next = true; | 
|  | } else if (capitalize_next) { | 
|  | result.push_back(absl::ascii_toupper(character)); | 
|  | capitalize_next = false; | 
|  | } else { | 
|  | result.push_back(character); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Lower-case the first letter. | 
|  | if (lower_first && !result.empty()) { | 
|  | result[0] = absl::ascii_tolower(result[0]); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | std::string DefaultValue(const FieldDescriptor* field) { | 
|  | if (field->is_repeated()) { | 
|  | return "::std::false_type()"; | 
|  | } | 
|  | switch (field->cpp_type()) { | 
|  | case FieldDescriptor::CPPTYPE_INT32: | 
|  | return absl::StrCat(field->default_value_int32()); | 
|  | case FieldDescriptor::CPPTYPE_INT64: | 
|  | return absl::StrCat(field->default_value_int64()); | 
|  | case FieldDescriptor::CPPTYPE_UINT32: | 
|  | return absl::StrCat(field->default_value_uint32()); | 
|  | case FieldDescriptor::CPPTYPE_UINT64: | 
|  | return absl::StrCat(field->default_value_uint64()); | 
|  | case FieldDescriptor::CPPTYPE_FLOAT: | 
|  | return absl::StrCat(field->default_value_float()); | 
|  | case FieldDescriptor::CPPTYPE_DOUBLE: | 
|  | return absl::StrCat(field->default_value_double()); | 
|  | case FieldDescriptor::CPPTYPE_BOOL: | 
|  | return field->default_value_bool() ? "true" : "false"; | 
|  | case FieldDescriptor::CPPTYPE_MESSAGE: | 
|  | return "::std::false_type()"; | 
|  | case FieldDescriptor::CPPTYPE_STRING: | 
|  | return absl::StrCat( | 
|  | "\"", EscapeTrigraphs(absl::CEscape(field->default_value_string())), | 
|  | "\""); | 
|  | default: | 
|  | // TODO: b/375460289 - implement rest of scalars | 
|  | ABSL_LOG(WARNING) << "Unsupported default value type (in-progress): <" | 
|  | << field->cpp_type_name() | 
|  | << "> For field: " << field->full_name(); | 
|  | return "::std::false_type()"; | 
|  | } | 
|  | } | 
|  | }  // namespace hpb_generator | 
|  | }  // namespace protobuf | 
|  | }  // namespace google |