| // 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 |