diff --git a/BUILD b/BUILD index b8253a37ff..cd515ba430 100644 --- a/BUILD +++ b/BUILD @@ -168,6 +168,7 @@ cc_library( hdrs = [ "upb/msg_internal.h", ], + visibility = ["//:__subpackages__"], deps = [ ":extension_registry", ":port", @@ -333,9 +334,7 @@ cc_library( copts = UPB_DEFAULT_COPTS, visibility = ["//visibility:public"], deps = [ - ":descriptor_upb_proto", ":reflection", - ":table_internal", ], ) @@ -372,22 +371,49 @@ cc_library( ], ) +# TODO(b/232091617): Once we can delete the deprecated forwarding headers +# (= everything in upb/) we can move this build target down into reflection/ cc_library( name = "reflection", srcs = [ - "upb/def.c", - "upb/internal/mini_descriptor.c", - "upb/internal/mini_descriptor.h", - "upb/mini_descriptor.c", - "upb/msg.h", - "upb/reflection.c", + "upb/reflection/common.h", + "upb/reflection/def_builder.c", + "upb/reflection/def_builder.h", + "upb/reflection/def_pool.c", + "upb/reflection/def_pool.h", + "upb/reflection/def_type.c", + "upb/reflection/def_type.h", + "upb/reflection/enum_def.c", + "upb/reflection/enum_def.h", + "upb/reflection/enum_value_def.c", + "upb/reflection/enum_value_def.h", + "upb/reflection/extension_range.c", + "upb/reflection/extension_range.h", + "upb/reflection/field_def.c", + "upb/reflection/field_def.h", + "upb/reflection/file_def.c", + "upb/reflection/file_def.h", + "upb/reflection/message.c", + "upb/reflection/message_def.c", + "upb/reflection/message_def.h", + "upb/reflection/method_def.c", + "upb/reflection/method_def.h", + "upb/reflection/mini_descriptor_encode.c", + "upb/reflection/oneof_def.c", + "upb/reflection/oneof_def.h", + "upb/reflection/service_def.c", + "upb/reflection/service_def.h", ], hdrs = [ "upb/def.h", "upb/def.hpp", - "upb/mini_descriptor.h", "upb/reflection.h", "upb/reflection.hpp", + "upb/reflection/def.h", + "upb/reflection/def.hpp", + "upb/reflection/message.h", + "upb/reflection/message.hpp", + "upb/reflection/mini_descriptor_encode.h", ], copts = UPB_DEFAULT_COPTS, visibility = ["//visibility:public"], @@ -395,6 +421,7 @@ cc_library( ":collections", ":descriptor_upb_proto", ":mini_table", + ":mini_table_internal", ":port", ":table_internal", ":upb", @@ -444,6 +471,25 @@ cc_library( # Tests ######################################################################## +cc_test( + name = "def_builder_test", + srcs = [ + "upb/reflection/common.h", + "upb/reflection/def_builder.h", + "upb/reflection/def_builder_test.cc", + "upb/reflection/def_pool.h", + "upb/reflection/def_type.h", + ], + deps = [ + ":descriptor_upb_proto", + ":port", + ":reflection", + ":table_internal", + ":upb", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "test_generated_code", srcs = ["upb/test_generated_code.cc"], @@ -621,14 +667,14 @@ cc_test( srcs = ["upb/test_cpp.cc"], copts = UPB_DEFAULT_CPPOPTS, deps = [ + ":json", + ":port", + ":reflection", ":test_cpp_upb_proto", ":test_cpp_upb_proto_reflection", ":timestamp_upb_proto", ":timestamp_upb_proto_reflection", - "//:json", - "//:port", - "//:reflection", - "//:upb", + ":upb", "@com_google_googletest//:gtest_main", ], ) @@ -638,9 +684,9 @@ cc_test( srcs = ["upb/test_table.cc"], copts = UPB_DEFAULT_CPPOPTS, deps = [ - "//:port", - "//:table_internal", - "//:upb", + ":port", + ":table_internal", + ":upb", "@com_google_googletest//:gtest_main", ], ) @@ -678,13 +724,13 @@ cc_binary( deps = [ ":conformance_proto_upb", ":conformance_proto_upbdefs", + ":json", + ":port", + ":reflection", ":test_messages_proto2_upbdefs", ":test_messages_proto3_upbdefs", - "//:json", - "//:port", - "//:reflection", - "//:textformat", - "//:upb", + ":textformat", + ":upb", ], ) @@ -719,13 +765,13 @@ cc_binary( deps = [ ":conformance_proto_upb", ":conformance_proto_upbdefs", + ":json", + ":port", + ":reflection", ":test_messages_proto2_upbdefs", ":test_messages_proto3_upbdefs", - "//:json", - "//:port", - "//:reflection", - "//:textformat", - "//:upb", + ":textformat", + ":upb", ], ) diff --git a/upb/def.c b/upb/def.c deleted file mode 100644 index 86616f127f..0000000000 --- a/upb/def.c +++ /dev/null @@ -1,3323 +0,0 @@ -/* - * Copyright (c) 2009-2021, Google LLC - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google LLC nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "upb/def.h" - -#include -#include -#include -#include - -#include "upb/internal/mini_descriptor.h" -#include "upb/mini_table.h" -#include "upb/reflection.h" - -// Must be last. -#include "upb/port_def.inc" - -typedef struct { - size_t len; - char str[1]; /* Null-terminated string data follows. */ -} str_t; - -/* The upb core does not generally have a concept of default instances. However - * for descriptor options we make an exception since the max size is known and - * modest (<200 bytes). All types can share a default instance since it is - * initialized to zeroes. - * - * We have to allocate an extra pointer for upb's internal metadata. */ -static const char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; -static const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; - -struct upb_FieldDef { - const google_protobuf_FieldOptions* opts; - const upb_FileDef* file; - const upb_MessageDef* msgdef; - const char* full_name; - const char* json_name; - union { - int64_t sint; - uint64_t uint; - double dbl; - float flt; - bool boolean; - str_t* str; - } defaultval; - union { - const upb_OneofDef* oneof; - const upb_MessageDef* extension_scope; - } scope; - union { - const upb_MessageDef* msgdef; - const upb_EnumDef* enumdef; - const google_protobuf_FieldDescriptorProto* unresolved; - } sub; - uint32_t number_; - uint16_t index_; - uint16_t layout_index; /* Index into msgdef->layout->fields or file->exts */ - bool has_default; - bool is_extension_; - bool packed_; - bool proto3_optional_; - bool has_json_name_; - upb_FieldType type_; - upb_Label label_; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; - -struct upb_ExtensionRange { - const google_protobuf_ExtensionRangeOptions* opts; - int32_t start; - int32_t end; -}; - -struct upb_MessageDef { - const google_protobuf_MessageOptions* opts; - const upb_MiniTable* layout; - const upb_FileDef* file; - const upb_MessageDef* containing_type; - const char* full_name; - - /* Tables for looking up fields by number and name. */ - upb_inttable itof; - upb_strtable ntof; - - /* All nested defs. - * MEM: We could save some space here by putting nested defs in a contiguous - * region and calculating counts from offsets or vice-versa. */ - const upb_FieldDef* fields; - const upb_OneofDef* oneofs; - const upb_ExtensionRange* ext_ranges; - const upb_MessageDef* nested_msgs; - const upb_EnumDef* nested_enums; - const upb_FieldDef* nested_exts; - int field_count; - int real_oneof_count; - int oneof_count; - int ext_range_count; - int nested_msg_count; - int nested_enum_count; - int nested_ext_count; - bool in_message_set; - upb_WellKnown well_known_type; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; - -struct upb_EnumDef { - const google_protobuf_EnumOptions* opts; - const upb_MiniTable_Enum* layout; // Only for proto2. - const upb_FileDef* file; - const upb_MessageDef* containing_type; // Could be merged with "file". - const char* full_name; - upb_strtable ntoi; - upb_inttable iton; - const upb_EnumValueDef* values; - int value_count; - int32_t defaultval; - bool is_sorted; // Are all of the values defined in ascending order? -}; - -struct upb_EnumValueDef { - const google_protobuf_EnumValueOptions* opts; - const upb_EnumDef* parent; - const char* full_name; - int32_t number; -}; - -struct upb_OneofDef { - const google_protobuf_OneofOptions* opts; - const upb_MessageDef* parent; - const char* full_name; - int field_count; - bool synthetic; - const upb_FieldDef** fields; - upb_strtable ntof; - upb_inttable itof; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; - -struct upb_FileDef { - const google_protobuf_FileOptions* opts; - const char* name; - const char* package; - - const upb_FileDef** deps; - const int32_t* public_deps; - const int32_t* weak_deps; - const upb_MessageDef* top_lvl_msgs; - const upb_EnumDef* top_lvl_enums; - const upb_FieldDef* top_lvl_exts; - const upb_ServiceDef* services; - const upb_MiniTable_Extension** ext_layouts; - const upb_DefPool* symtab; - - int dep_count; - int public_dep_count; - int weak_dep_count; - int top_lvl_msg_count; - int top_lvl_enum_count; - int top_lvl_ext_count; - int service_count; - int ext_count; /* All exts in the file. */ - upb_Syntax syntax; -}; - -struct upb_MethodDef { - const google_protobuf_MethodOptions* opts; - upb_ServiceDef* service; - const char* full_name; - const upb_MessageDef* input_type; - const upb_MessageDef* output_type; - int index; - bool client_streaming; - bool server_streaming; -}; - -struct upb_ServiceDef { - const google_protobuf_ServiceOptions* opts; - const upb_FileDef* file; - const char* full_name; - upb_MethodDef* methods; - int method_count; - int index; -}; - -struct upb_DefPool { - upb_Arena* arena; - upb_strtable syms; /* full_name -> packed def ptr */ - upb_strtable files; /* file_name -> upb_FileDef* */ - upb_inttable exts; /* upb_MiniTable_Extension* -> upb_FieldDef* */ - upb_ExtensionRegistry* extreg; - size_t bytes_loaded; -}; - -/* Inside a symtab we store tagged pointers to specific def types. */ -typedef enum { - UPB_DEFTYPE_MASK = 7, - - /* Only inside symtab table. */ - UPB_DEFTYPE_EXT = 0, - UPB_DEFTYPE_MSG = 1, - UPB_DEFTYPE_ENUM = 2, - UPB_DEFTYPE_ENUMVAL = 3, - UPB_DEFTYPE_SERVICE = 4, - - /* Only inside message table. */ - UPB_DEFTYPE_FIELD = 0, - UPB_DEFTYPE_ONEOF = 1, - UPB_DEFTYPE_FIELD_JSONNAME = 2, -} upb_deftype_t; - -#define FIELD_TYPE_UNSPECIFIED 0 - -static upb_deftype_t deftype(upb_value v) { - uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return num & UPB_DEFTYPE_MASK; -} - -static const void* _upb_DefUtil_Unpack(upb_value v, upb_deftype_t type) { - uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return (num & UPB_DEFTYPE_MASK) == type - ? (const void*)(num & ~UPB_DEFTYPE_MASK) - : NULL; -} - -static upb_value _upb_DefUtil_Pack(const void* ptr, upb_deftype_t type, - size_t size) { - // Our 3-bit pointer tagging requires all pointers to be multiples of 8. - // The arena will always yield 8-byte-aligned addresses, however we put - // the defs into arrays. For each element in the array to be 8-byte-aligned, - // the sizes of each def type must also be a multiple of 8. - // - // If any of these asserts fail, we need to add or remove padding on 32-bit - // machines (64-bit machines will have 8-byte alignment already due to - // pointers, which all of these structs have). - UPB_ASSERT((size & UPB_DEFTYPE_MASK) == 0); - uintptr_t num = (uintptr_t)ptr; - UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); - num |= type; - return upb_value_constptr((const void*)num); -} - -/* isalpha() etc. from are locale-dependent, which we don't want. */ -static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { - return c >= low && c <= high; -} - -static char upb_ascii_lower(char ch) { - // Per ASCII this will lower-case a letter. If the result is a letter, the - // input was definitely a letter. If the output is not a letter, this may - // have transformed the character unpredictably. - return ch | 0x20; -} - -static bool upb_isletter(char c) { - char lower = upb_ascii_lower(c); - return upb_isbetween(lower, 'a', 'z') || c == '_'; -} - -static bool upb_isalphanum(char c) { - return upb_isletter(c) || upb_isbetween(c, '0', '9'); -} - -static const char* _upb_DefUtil_FullToShort(const char* fullname) { - const char* p; - - if (fullname == NULL) { - return NULL; - } else if ((p = strrchr(fullname, '.')) == NULL) { - /* No '.' in the name, return the full string. */ - return fullname; - } else { - /* Return one past the last '.'. */ - return p + 1; - } -} - -/* All submessage fields are lower than all other fields. - * Secondly, fields are increasing in order. */ -uint32_t field_rank(const upb_FieldDef* f) { - uint32_t ret = upb_FieldDef_Number(f); - const uint32_t high_bit = 1 << 30; - UPB_ASSERT(ret < high_bit); - if (!upb_FieldDef_IsSubMessage(f)) ret |= high_bit; - return ret; -} - -static int cmp_values(const void* a, const void* b) { - const uint32_t A = upb_EnumValueDef_Number(*(const upb_EnumValueDef**)a); - const uint32_t B = upb_EnumValueDef_Number(*(const upb_EnumValueDef**)b); - return (A < B) ? -1 : (A > B); -} - -static void assign_msg_wellknowntype(upb_MessageDef* m) { - const char* name = upb_MessageDef_FullName(m); - if (name == NULL) { - m->well_known_type = kUpb_WellKnown_Unspecified; - return; - } - if (!strcmp(name, "google.protobuf.Any")) { - m->well_known_type = kUpb_WellKnown_Any; - } else if (!strcmp(name, "google.protobuf.FieldMask")) { - m->well_known_type = kUpb_WellKnown_FieldMask; - } else if (!strcmp(name, "google.protobuf.Duration")) { - m->well_known_type = kUpb_WellKnown_Duration; - } else if (!strcmp(name, "google.protobuf.Timestamp")) { - m->well_known_type = kUpb_WellKnown_Timestamp; - } else if (!strcmp(name, "google.protobuf.DoubleValue")) { - m->well_known_type = kUpb_WellKnown_DoubleValue; - } else if (!strcmp(name, "google.protobuf.FloatValue")) { - m->well_known_type = kUpb_WellKnown_FloatValue; - } else if (!strcmp(name, "google.protobuf.Int64Value")) { - m->well_known_type = kUpb_WellKnown_Int64Value; - } else if (!strcmp(name, "google.protobuf.UInt64Value")) { - m->well_known_type = kUpb_WellKnown_UInt64Value; - } else if (!strcmp(name, "google.protobuf.Int32Value")) { - m->well_known_type = kUpb_WellKnown_Int32Value; - } else if (!strcmp(name, "google.protobuf.UInt32Value")) { - m->well_known_type = kUpb_WellKnown_UInt32Value; - } else if (!strcmp(name, "google.protobuf.BoolValue")) { - m->well_known_type = kUpb_WellKnown_BoolValue; - } else if (!strcmp(name, "google.protobuf.StringValue")) { - m->well_known_type = kUpb_WellKnown_StringValue; - } else if (!strcmp(name, "google.protobuf.BytesValue")) { - m->well_known_type = kUpb_WellKnown_BytesValue; - } else if (!strcmp(name, "google.protobuf.Value")) { - m->well_known_type = kUpb_WellKnown_Value; - } else if (!strcmp(name, "google.protobuf.ListValue")) { - m->well_known_type = kUpb_WellKnown_ListValue; - } else if (!strcmp(name, "google.protobuf.Struct")) { - m->well_known_type = kUpb_WellKnown_Struct; - } else { - m->well_known_type = kUpb_WellKnown_Unspecified; - } -} - -typedef struct { - upb_DefPool* symtab; - upb_FileDef* file; /* File we are building. */ - upb_Arena* arena; /* Allocate defs here. */ - upb_Arena* tmp_arena; /* For temporary allocations. */ - upb_Status* status; /* Record errors here. */ - const upb_MiniTable_File* layout; /* NULL if we should build layouts. */ - int enum_count; /* Count of enums built so far. */ - int msg_count; /* Count of messages built so far. */ - int ext_count; /* Count of extensions built so far. */ - jmp_buf err; /* longjmp() on error. */ -} upb_DefBuilder; - -UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3) static void _upb_DefBuilder_Errf( - upb_DefBuilder* ctx, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(ctx->status, fmt, argp); - va_end(argp); - UPB_LONGJMP(ctx->err, 1); -} - -UPB_NORETURN UPB_NOINLINE static void _upb_DefBuilder_OomErr( - upb_DefBuilder* ctx) { - upb_Status_SetErrorMessage(ctx->status, "out of memory"); - UPB_LONGJMP(ctx->err, 1); -} - -void* _upb_DefBuilder_Alloc(upb_DefBuilder* ctx, size_t bytes) { - if (bytes == 0) return NULL; - void* ret = upb_Arena_Malloc(ctx->arena, bytes); - if (!ret) _upb_DefBuilder_OomErr(ctx); - return ret; -} - -/* upb_EnumDef ****************************************************************/ - -const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { - return e->opts; -} - -bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { - return e->opts != (void*)kUpbDefOptDefault; -} - -const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } - -const char* upb_EnumDef_Name(const upb_EnumDef* e) { - return _upb_DefUtil_FullToShort(e->full_name); -} - -const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } - -const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { - return e->containing_type; -} - -int32_t upb_EnumDef_Default(const upb_EnumDef* e) { - UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); - return e->defaultval; -} - -int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } - -const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( - const upb_EnumDef* def, const char* name, size_t len) { - upb_value v; - return upb_strtable_lookup2(&def->ntoi, name, len, &v) - ? upb_value_getconstptr(v) - : NULL; -} - -const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* def, - int32_t num) { - upb_value v; - return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getconstptr(v) - : NULL; -} - -bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { - // We could use upb_EnumDef_FindValueByNumber(e, num) != NULL, but we expect - // this to be faster (especially for small numbers). - return upb_MiniTable_Enum_CheckValue(e->layout, num); -} - -const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { - UPB_ASSERT(0 <= i && i < e->value_count); - return &e->values[i]; -} - -const char* _upb_EnumDef_MiniDescriptor(const upb_EnumDef* e, upb_Arena* a) { - if (e->is_sorted) return _upb_MiniDescriptor_EncodeEnum(e, NULL, a); - - const upb_EnumValueDef** sorted = (const upb_EnumValueDef**)upb_Arena_Malloc( - a, e->value_count * sizeof(void*)); - if (!sorted) return NULL; - - for (size_t i = 0; i < e->value_count; i++) { - sorted[i] = upb_EnumDef_Value(e, i); - } - qsort(sorted, e->value_count, sizeof(void*), cmp_values); - - return _upb_MiniDescriptor_EncodeEnum(e, sorted, a); -} - -/* upb_EnumValueDef ***********************************************************/ - -const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( - const upb_EnumValueDef* e) { - return e->opts; -} - -bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* e) { - return e->opts != (void*)kUpbDefOptDefault; -} - -const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* ev) { - return ev->parent; -} - -const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* ev) { - return ev->full_name; -} - -const char* upb_EnumValueDef_Name(const upb_EnumValueDef* ev) { - return _upb_DefUtil_FullToShort(ev->full_name); -} - -int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* ev) { - return ev->number; -} - -uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* ev) { - // Compute index in our parent's array. - return ev - ev->parent->values; -} - -/* upb_ExtensionRange *********************************************************/ - -const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( - const upb_ExtensionRange* r) { - return r->opts; -} - -bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { - return r->opts != (void*)kUpbDefOptDefault; -} - -int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* e) { - return e->start; -} - -int32_t upb_ExtensionRange_End(const upb_ExtensionRange* e) { return e->end; } - -// Allocate sufficient storage to contain an array of |n| extension ranges. -static upb_ExtensionRange* _upb_ExtensionRange_Alloc(upb_DefBuilder* ctx, - int n) { - return _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); -} - -/* upb_FieldDef ***************************************************************/ - -const google_protobuf_FieldOptions* upb_FieldDef_Options( - const upb_FieldDef* f) { - return f->opts; -} - -bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { - return f->opts != (void*)kUpbDefOptDefault; -} - -const char* upb_FieldDef_FullName(const upb_FieldDef* f) { - return f->full_name; -} - -upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { - switch (f->type_) { - case kUpb_FieldType_Double: - return kUpb_CType_Double; - case kUpb_FieldType_Float: - return kUpb_CType_Float; - case kUpb_FieldType_Int64: - case kUpb_FieldType_SInt64: - case kUpb_FieldType_SFixed64: - return kUpb_CType_Int64; - case kUpb_FieldType_Int32: - case kUpb_FieldType_SFixed32: - case kUpb_FieldType_SInt32: - return kUpb_CType_Int32; - case kUpb_FieldType_UInt64: - case kUpb_FieldType_Fixed64: - return kUpb_CType_UInt64; - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Fixed32: - return kUpb_CType_UInt32; - case kUpb_FieldType_Enum: - return kUpb_CType_Enum; - case kUpb_FieldType_Bool: - return kUpb_CType_Bool; - case kUpb_FieldType_String: - return kUpb_CType_String; - case kUpb_FieldType_Bytes: - return kUpb_CType_Bytes; - case kUpb_FieldType_Group: - case kUpb_FieldType_Message: - return kUpb_CType_Message; - } - UPB_UNREACHABLE(); -} - -upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } - -uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } - -upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } - -uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } - -bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { - return f->is_extension_; -} - -bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->packed_; } - -const char* upb_FieldDef_Name(const upb_FieldDef* f) { - return _upb_DefUtil_FullToShort(f->full_name); -} - -const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { - return f->json_name; -} - -bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { - return f->has_json_name_; -} - -const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } - -const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { - return f->msgdef; -} - -const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { - return f->is_extension_ ? f->scope.extension_scope : NULL; -} - -const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { - return f->is_extension_ ? NULL : f->scope.oneof; -} - -const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { - const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); - if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; - return oneof; -} - -upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsSubMessage(f)); - upb_MessageValue ret; - - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - return (upb_MessageValue){.bool_val = f->defaultval.boolean}; - case kUpb_CType_Int64: - return (upb_MessageValue){.int64_val = f->defaultval.sint}; - case kUpb_CType_UInt64: - return (upb_MessageValue){.uint64_val = f->defaultval.uint}; - case kUpb_CType_Enum: - case kUpb_CType_Int32: - return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; - case kUpb_CType_UInt32: - return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; - case kUpb_CType_Float: - return (upb_MessageValue){.float_val = f->defaultval.flt}; - case kUpb_CType_Double: - return (upb_MessageValue){.double_val = f->defaultval.dbl}; - case kUpb_CType_String: - case kUpb_CType_Bytes: { - str_t* str = f->defaultval.str; - if (str) { - return (upb_MessageValue){ - .str_val = (upb_StringView){.data = str->str, .size = str->len}}; - } else { - return (upb_MessageValue){ - .str_val = (upb_StringView){.data = NULL, .size = 0}}; - } - } - default: - UPB_UNREACHABLE(); - } - - return ret; -} - -const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; -} - -const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; -} - -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsExtension(f)); - const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); - return &layout->fields[f->layout_index]; -} - -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( - const upb_FieldDef* f) { - UPB_ASSERT(upb_FieldDef_IsExtension(f)); - const upb_FileDef* file = upb_FieldDef_File(f); - return file->ext_layouts[f->layout_index]; -} - -bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { - return f->proto3_optional_; -} - -bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message; -} - -bool upb_FieldDef_IsString(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_String || - upb_FieldDef_CType(f) == kUpb_CType_Bytes; -} - -bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Optional; -} - -bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Required; -} - -bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Repeated; -} - -bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { - return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); -} - -bool upb_FieldDef_IsMap(const upb_FieldDef* f) { - return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && - upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); -} - -bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } - -bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { - return upb_FieldDef_IsSubMessage(f) || - upb_FieldDef_CType(f) == kUpb_CType_Enum; -} - -bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { - if (upb_FieldDef_IsRepeated(f)) return false; - const upb_FileDef* file = upb_FieldDef_File(f); - return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || - upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; -} - -static bool between(int32_t x, int32_t low, int32_t high) { - return x >= low && x <= high; -} - -bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } -bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } -bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } - -bool upb_FieldDef_checkdescriptortype(int32_t type) { - return between(type, 1, 18); -} - -// Allocate sufficient storage to contain an array of |n| field defs. -static upb_FieldDef* _upb_FieldDef_Alloc(upb_DefBuilder* ctx, int n) { - return _upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); -} - -/* upb_MessageDef *************************************************************/ - -const google_protobuf_MessageOptions* upb_MessageDef_Options( - const upb_MessageDef* m) { - return m->opts; -} - -bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { - return m->opts != (void*)kUpbDefOptDefault; -} - -const char* upb_MessageDef_FullName(const upb_MessageDef* m) { - return m->full_name; -} - -const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { - return m->file; -} - -const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { - return m->containing_type; -} - -const char* upb_MessageDef_Name(const upb_MessageDef* m) { - return _upb_DefUtil_FullToShort(m->full_name); -} - -upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { - return upb_FileDef_Syntax(m->file); -} - -const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, - uint32_t i) { - upb_value val; - return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) - : NULL; -} - -const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; - } - - return _upb_DefUtil_Unpack(val, UPB_DEFTYPE_FIELD); -} - -const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; - } - - return _upb_DefUtil_Unpack(val, UPB_DEFTYPE_ONEOF); -} - -bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, - const char* name, size_t len, - const upb_FieldDef** out_f, - const upb_OneofDef** out_o) { - upb_value val; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return false; - } - - const upb_FieldDef* f = _upb_DefUtil_Unpack(val, UPB_DEFTYPE_FIELD); - const upb_OneofDef* o = _upb_DefUtil_Unpack(val, UPB_DEFTYPE_ONEOF); - if (out_f) *out_f = f; - if (out_o) *out_o = o; - return f || o; /* False if this was a JSON name. */ -} - -const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; - const upb_FieldDef* f; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; - } - - f = _upb_DefUtil_Unpack(val, UPB_DEFTYPE_FIELD); - if (!f) f = _upb_DefUtil_Unpack(val, UPB_DEFTYPE_FIELD_JSONNAME); - - return f; -} - -int upb_MessageDef_numfields(const upb_MessageDef* m) { return m->field_count; } - -int upb_MessageDef_numoneofs(const upb_MessageDef* m) { return m->oneof_count; } - -int upb_MessageDef_numrealoneofs(const upb_MessageDef* m) { - return m->real_oneof_count; -} - -int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { - return m->ext_range_count; -} - -int upb_MessageDef_FieldCount(const upb_MessageDef* m) { - return m->field_count; -} - -int upb_MessageDef_OneofCount(const upb_MessageDef* m) { - return m->oneof_count; -} - -int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { - return m->nested_msg_count; -} - -int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { - return m->nested_enum_count; -} - -int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { - return m->nested_ext_count; -} - -int upb_MessageDef_realoneofcount(const upb_MessageDef* m) { - return m->real_oneof_count; -} - -const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { - return m->layout; -} - -const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->ext_range_count); - return &m->ext_ranges[i]; -} - -const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->field_count); - return &m->fields[i]; -} - -const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->oneof_count); - return &m->oneofs[i]; -} - -const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_msg_count); - return &m->nested_msgs[i]; -} - -const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->nested_enum_count); - return &m->nested_enums[i]; -} - -const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_ext_count); - return &m->nested_exts[i]; -} - -upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { - return m->well_known_type; -} - -/* upb_OneofDef ***************************************************************/ - -const google_protobuf_OneofOptions* upb_OneofDef_Options( - const upb_OneofDef* o) { - return o->opts; -} - -bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { - return o->opts != (void*)kUpbDefOptDefault; -} - -const char* upb_OneofDef_Name(const upb_OneofDef* o) { - return _upb_DefUtil_FullToShort(o->full_name); -} - -const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { - return o->parent; -} - -int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } - -const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { - UPB_ASSERT(i < o->field_count); - return o->fields[i]; -} - -int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } - -uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { - // Compute index in our parent's array. - return o - o->parent->oneofs; -} - -bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } - -const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, - const char* name, - size_t length) { - upb_value val; - return upb_strtable_lookup2(&o->ntof, name, length, &val) - ? upb_value_getptr(val) - : NULL; -} - -const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, - uint32_t num) { - upb_value val; - return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) - : NULL; -} - -/* upb_FileDef ****************************************************************/ - -const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { - return f->opts; -} - -bool upb_FileDef_HasOptions(const upb_FileDef* f) { - return f->opts != (void*)kUpbDefOptDefault; -} - -const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } - -const char* upb_FileDef_Package(const upb_FileDef* f) { - return f->package ? f->package : ""; -} - -upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } - -int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { - return f->top_lvl_msg_count; -} - -int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } - -int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { - return f->public_dep_count; -} - -int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { - return f->weak_dep_count; -} - -const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { - return f->public_deps; -} - -const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { - return f->weak_deps; -} - -int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { - return f->top_lvl_enum_count; -} - -int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { - return f->top_lvl_ext_count; -} - -int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } - -const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->dep_count); - return f->deps[i]; -} - -const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->public_dep_count); - return f->deps[f->public_deps[i]]; -} - -const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->public_dep_count); - return f->deps[f->weak_deps[i]]; -} - -const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); - return &f->top_lvl_msgs[i]; -} - -const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); - return &f->top_lvl_enums[i]; -} - -const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); - return &f->top_lvl_exts[i]; -} - -const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->service_count); - return &f->services[i]; -} - -const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } - -/* upb_MethodDef **************************************************************/ - -const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m) { - return m->opts; -} - -bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { - return m->opts != (void*)kUpbDefOptDefault; -} - -const char* upb_MethodDef_FullName(const upb_MethodDef* m) { - return m->full_name; -} - -int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } - -const char* upb_MethodDef_Name(const upb_MethodDef* m) { - return _upb_DefUtil_FullToShort(m->full_name); -} - -const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { - return m->service; -} - -const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { - return m->input_type; -} - -const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { - return m->output_type; -} - -bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { - return m->client_streaming; -} - -bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { - return m->server_streaming; -} - -/* upb_ServiceDef *************************************************************/ - -const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s) { - return s->opts; -} - -bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { - return s->opts != (void*)kUpbDefOptDefault; -} - -const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { - return s->full_name; -} - -const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { - return _upb_DefUtil_FullToShort(s->full_name); -} - -int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } - -const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { - return s->file; -} - -int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { - return s->method_count; -} - -const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { - return (i < 0 || i >= s->method_count) ? NULL : &s->methods[i]; -} - -const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, - const char* name) { - for (int i = 0; i < s->method_count; i++) { - if (strcmp(name, upb_MethodDef_Name(&s->methods[i])) == 0) { - return &s->methods[i]; - } - } - return NULL; -} - -/* upb_DefPool ****************************************************************/ - -void upb_DefPool_Free(upb_DefPool* s) { - upb_Arena_Free(s->arena); - upb_gfree(s); -} - -upb_DefPool* upb_DefPool_New(void) { - upb_DefPool* s = upb_gmalloc(sizeof(*s)); - if (!s) return NULL; - - s->arena = upb_Arena_New(); - s->bytes_loaded = 0; - - if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; - if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; - if (!upb_inttable_init(&s->exts, s->arena)) goto err; - - s->extreg = upb_ExtensionRegistry_New(s->arena); - if (!s->extreg) goto err; - - return s; - -err: - upb_Arena_Free(s->arena); - upb_gfree(s); - return NULL; -} - -static const void* symtab_lookup(const upb_DefPool* s, const char* sym, - upb_deftype_t type) { - upb_value v; - return upb_strtable_lookup(&s->syms, sym, &v) ? _upb_DefUtil_Unpack(v, type) - : NULL; -} - -static const void* symtab_lookup2(const upb_DefPool* s, const char* sym, - size_t size, upb_deftype_t type) { - upb_value v; - return upb_strtable_lookup2(&s->syms, sym, size, &v) - ? _upb_DefUtil_Unpack(v, type) - : NULL; -} - -const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_MSG); -} - -const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len) { - return symtab_lookup2(s, sym, len, UPB_DEFTYPE_MSG); -} - -const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_ENUM); -} - -const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_ENUMVAL); -} - -const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, - const char* name) { - upb_value v; - return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) - : NULL; -} - -const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, - const char* name, - size_t len) { - upb_value v; - return upb_strtable_lookup2(&s->files, name, len, &v) - ? upb_value_getconstptr(v) - : NULL; -} - -const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - upb_value v; - if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; - - switch (deftype(v)) { - case UPB_DEFTYPE_FIELD: - return _upb_DefUtil_Unpack(v, UPB_DEFTYPE_FIELD); - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = _upb_DefUtil_Unpack(v, UPB_DEFTYPE_MSG); - return m->in_message_set ? &m->nested_exts[0] : NULL; - } - default: - break; - } - - return NULL; -} - -const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, - const char* sym) { - return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); -} - -const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, - const char* name) { - return symtab_lookup(s, name, UPB_DEFTYPE_SERVICE); -} - -const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - return symtab_lookup2(s, name, size, UPB_DEFTYPE_SERVICE); -} - -const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, - const char* name) { - upb_value v; - // TODO(haberman): non-extension fields and oneofs. - if (upb_strtable_lookup(&s->syms, name, &v)) { - switch (deftype(v)) { - case UPB_DEFTYPE_EXT: { - const upb_FieldDef* f = _upb_DefUtil_Unpack(v, UPB_DEFTYPE_EXT); - return upb_FieldDef_File(f); - } - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = _upb_DefUtil_Unpack(v, UPB_DEFTYPE_MSG); - return upb_MessageDef_File(m); - } - case UPB_DEFTYPE_ENUM: { - const upb_EnumDef* e = _upb_DefUtil_Unpack(v, UPB_DEFTYPE_ENUM); - return upb_EnumDef_File(e); - } - case UPB_DEFTYPE_ENUMVAL: { - const upb_EnumValueDef* ev = - _upb_DefUtil_Unpack(v, UPB_DEFTYPE_ENUMVAL); - return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); - } - case UPB_DEFTYPE_SERVICE: { - const upb_ServiceDef* service = - _upb_DefUtil_Unpack(v, UPB_DEFTYPE_SERVICE); - return upb_ServiceDef_File(service); - } - default: - UPB_UNREACHABLE(); - } - } - - const char* last_dot = strrchr(name, '.'); - if (last_dot) { - const upb_MessageDef* parent = - upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); - if (parent) { - const char* shortname = last_dot + 1; - if (upb_MessageDef_FindByNameWithSize(parent, shortname, - strlen(shortname), NULL, NULL)) { - return upb_MessageDef_File(parent); - } - } - } - - return NULL; -} - -/* Code to build defs from descriptor protos. *********************************/ - -/* There is a question of how much validation to do here. It will be difficult - * to perfectly match the amount of validation performed by proto2. But since - * this code is used to directly build defs from Ruby (for example) we do need - * to validate important constraints like uniqueness of names and numbers. */ - -// We want to copy the options verbatim into the destination options proto. -// We use serialize+parse as our deep copy. -#define SET_OPTIONS(target, desc_type, options_type, proto) \ - if (google_protobuf_##desc_type##_has_options(proto)) { \ - size_t size; \ - char* pb = google_protobuf_##options_type##_serialize( \ - google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ - if (!pb) _upb_DefBuilder_OomErr(ctx); \ - target = google_protobuf_##options_type##_parse(pb, size, ctx->arena); \ - if (!target) _upb_DefBuilder_OomErr(ctx); \ - } else { \ - target = (const google_protobuf_##options_type*)kUpbDefOptDefault; \ - } - -static void _upb_DefBuilder_CheckIdent(upb_DefBuilder* ctx, upb_StringView name, - bool full) { - const char* str = name.data; - size_t len = name.size; - bool start = true; - size_t i; - for (i = 0; i < len; i++) { - char c = str[i]; - if (c == '.') { - if (start || !full) { - _upb_DefBuilder_Errf(ctx, "invalid name: unexpected '.' (%.*s)", - (int)len, str); - } - start = true; - } else if (start) { - if (!upb_isletter(c)) { - _upb_DefBuilder_Errf( - ctx, - "invalid name: path components must start with a letter (%.*s)", - (int)len, str); - } - start = false; - } else { - if (!upb_isalphanum(c)) { - _upb_DefBuilder_Errf(ctx, - "invalid name: non-alphanumeric character (%.*s)", - (int)len, str); - } - } - } - if (start) { - _upb_DefBuilder_Errf(ctx, "invalid name: empty part (%.*s)", (int)len, str); - } -} - -static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; } - -static size_t upb_MessageValue_sizeof(upb_CType type) { - switch (type) { - case kUpb_CType_Double: - case kUpb_CType_Int64: - case kUpb_CType_UInt64: - return 8; - case kUpb_CType_Enum: - case kUpb_CType_Int32: - case kUpb_CType_UInt32: - case kUpb_CType_Float: - return 4; - case kUpb_CType_Bool: - return 1; - case kUpb_CType_Message: - return sizeof(void*); - case kUpb_CType_Bytes: - case kUpb_CType_String: - return sizeof(upb_StringView); - } - UPB_UNREACHABLE(); -} - -static uint8_t upb_msg_fielddefsize(const upb_FieldDef* f) { - if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { - upb_MapEntry ent; - UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); - return sizeof(ent.k); - } else if (upb_FieldDef_IsRepeated(f)) { - return sizeof(void*); - } else { - return upb_MessageValue_sizeof(upb_FieldDef_CType(f)); - } -} - -static uint32_t upb_MiniTable_place(upb_DefBuilder* ctx, upb_MiniTable* l, - size_t size, const upb_MessageDef* m) { - size_t ofs = UPB_ALIGN_UP(l->size, size); - size_t next = ofs + size; - - if (next > UINT16_MAX) { - _upb_DefBuilder_Errf(ctx, - "size of message %s exceeded max size of %zu bytes", - upb_MessageDef_FullName(m), (size_t)UINT16_MAX); - } - - l->size = next; - return ofs; -} - -static int field_number_cmp(const void* p1, const void* p2) { - const upb_MiniTable_Field* f1 = p1; - const upb_MiniTable_Field* f2 = p2; - return f1->number - f2->number; -} - -static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l, - upb_MiniTable_Field* fields) { - int i; - int n = upb_MessageDef_numfields(m); - int dense_below = 0; - for (i = 0; i < n; i++) { - upb_FieldDef* f = - (upb_FieldDef*)upb_MessageDef_FindFieldByNumber(m, fields[i].number); - UPB_ASSERT(f); - f->layout_index = i; - if (i < UINT8_MAX && fields[i].number == i + 1 && - (i == 0 || fields[i - 1].number == i)) { - dense_below = i + 1; - } - } - l->dense_below = dense_below; -} - -static uint8_t map_descriptortype(const upb_FieldDef* f) { - uint8_t type = upb_FieldDef_Type(f); - /* See TableDescriptorType() in upbc/generator.cc for details and - * rationale of these exceptions. */ - if (type == kUpb_FieldType_String) { - const upb_FileDef* file = upb_FieldDef_File(f); - const upb_Syntax syntax = upb_FileDef_Syntax(file); - - if (syntax == kUpb_Syntax_Proto2) return kUpb_FieldType_Bytes; - } else if (type == kUpb_FieldType_Enum) { - const upb_FileDef* file = upb_EnumDef_File(f->sub.enumdef); - const upb_Syntax syntax = upb_FileDef_Syntax(file); - - if (syntax == kUpb_Syntax_Proto3 || UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 || - // TODO(https://github.com/protocolbuffers/upb/issues/541): - // fix map enum values to check for unknown enum values and put - // them in the unknown field set. - upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { - return kUpb_FieldType_Int32; - } - } - return type; -} - -static void fill_fieldlayout(upb_MiniTable_Field* field, - const upb_FieldDef* f) { - field->number = upb_FieldDef_Number(f); - field->descriptortype = map_descriptortype(f); - - if (upb_FieldDef_IsMap(f)) { - field->mode = - kUpb_FieldMode_Map | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); - } else if (upb_FieldDef_IsRepeated(f)) { - field->mode = - kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); - } else { - /* Maps descriptor type -> elem_size_lg2. */ - static const uint8_t sizes[] = { - -1, /* invalid descriptor type */ - kUpb_FieldRep_8Byte, /* DOUBLE */ - kUpb_FieldRep_4Byte, /* FLOAT */ - kUpb_FieldRep_8Byte, /* INT64 */ - kUpb_FieldRep_8Byte, /* UINT64 */ - kUpb_FieldRep_4Byte, /* INT32 */ - kUpb_FieldRep_8Byte, /* FIXED64 */ - kUpb_FieldRep_4Byte, /* FIXED32 */ - kUpb_FieldRep_1Byte, /* BOOL */ - kUpb_FieldRep_StringView, /* STRING */ - kUpb_FieldRep_Pointer, /* GROUP */ - kUpb_FieldRep_Pointer, /* MESSAGE */ - kUpb_FieldRep_StringView, /* BYTES */ - kUpb_FieldRep_4Byte, /* UINT32 */ - kUpb_FieldRep_4Byte, /* ENUM */ - kUpb_FieldRep_4Byte, /* SFIXED32 */ - kUpb_FieldRep_8Byte, /* SFIXED64 */ - kUpb_FieldRep_4Byte, /* SINT32 */ - kUpb_FieldRep_8Byte, /* SINT64 */ - }; - field->mode = kUpb_FieldMode_Scalar | - (sizes[field->descriptortype] << kUpb_FieldRep_Shift); - } - - if (upb_FieldDef_IsPacked(f)) { - field->mode |= kUpb_LabelFlags_IsPacked; - } - - if (upb_FieldDef_IsExtension(f)) { - field->mode |= kUpb_LabelFlags_IsExtension; - } -} - -/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. - * It computes a dynamic layout for all of the fields in |m|. */ -static void make_layout(upb_DefBuilder* ctx, const upb_MessageDef* m) { - upb_MiniTable* l = (upb_MiniTable*)upb_MessageDef_MiniTable(m); - size_t field_count = upb_MessageDef_numfields(m); - size_t sublayout_count = 0; - upb_MiniTable_Sub* subs; - upb_MiniTable_Field* fields; - - memset(l, 0, sizeof(*l) + sizeof(_upb_FastTable_Entry)); - - /* Count sub-messages. */ - for (size_t i = 0; i < field_count; i++) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - if (upb_FieldDef_IsSubMessage(f)) { - sublayout_count++; - } - if (upb_FieldDef_CType(f) == kUpb_CType_Enum && - upb_FileDef_Syntax(f->sub.enumdef->file) == kUpb_Syntax_Proto2) { - sublayout_count++; - } - } - - fields = _upb_DefBuilder_Alloc(ctx, field_count * sizeof(*fields)); - subs = _upb_DefBuilder_Alloc(ctx, sublayout_count * sizeof(*subs)); - - l->field_count = upb_MessageDef_numfields(m); - l->fields = fields; - l->subs = subs; - l->table_mask = 0; - l->required_count = 0; - - if (upb_MessageDef_ExtensionRangeCount(m) > 0) { - if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { - l->ext = kUpb_ExtMode_IsMessageSet; - } else { - l->ext = kUpb_ExtMode_Extendable; - } - } else { - l->ext = kUpb_ExtMode_NonExtendable; - } - - /* TODO(haberman): initialize fast tables so that reflection-based parsing - * can get the same speeds as linked-in types. */ - l->fasttable[0].field_parser = &_upb_FastDecoder_DecodeGeneric; - l->fasttable[0].field_data = 0; - - if (upb_MessageDef_IsMapEntry(m)) { - /* TODO(haberman): refactor this method so this special case is more - * elegant. */ - const upb_FieldDef* key = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* val = upb_MessageDef_FindFieldByNumber(m, 2); - fields[0].number = 1; - fields[1].number = 2; - fields[0].mode = kUpb_FieldMode_Scalar; - fields[1].mode = kUpb_FieldMode_Scalar; - fields[0].presence = 0; - fields[1].presence = 0; - fields[0].descriptortype = map_descriptortype(key); - fields[1].descriptortype = map_descriptortype(val); - fields[0].offset = 0; - fields[1].offset = sizeof(upb_StringView); - fields[1].submsg_index = 0; - - if (upb_FieldDef_CType(val) == kUpb_CType_Message) { - subs[0].submsg = upb_FieldDef_MessageSubDef(val)->layout; - } - - upb_FieldDef* fielddefs = (upb_FieldDef*)&m->fields[0]; - UPB_ASSERT(fielddefs[0].number_ == 1); - UPB_ASSERT(fielddefs[1].number_ == 2); - fielddefs[0].layout_index = 0; - fielddefs[1].layout_index = 1; - - l->field_count = 2; - l->size = 2 * sizeof(upb_StringView); - l->size = UPB_ALIGN_UP(l->size, 8); - l->dense_below = 2; - return; - } - - /* Allocate data offsets in three stages: - * - * 1. hasbits. - * 2. regular fields. - * 3. oneof fields. - * - * OPT: There is a lot of room for optimization here to minimize the size. - */ - - /* Assign hasbits for required fields first. */ - size_t hasbit = 0; - - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; - if (upb_FieldDef_Label(f) == kUpb_Label_Required) { - field->presence = ++hasbit; - if (hasbit >= 63) { - _upb_DefBuilder_Errf(ctx, "Message with >=63 required fields: %s", - upb_MessageDef_FullName(m)); - } - l->required_count++; - } - } - - /* Allocate hasbits and set basic field attributes. */ - sublayout_count = 0; - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; - - fill_fieldlayout(field, f); - - if (field->descriptortype == kUpb_FieldType_Message || - field->descriptortype == kUpb_FieldType_Group) { - field->submsg_index = sublayout_count++; - subs[field->submsg_index].submsg = upb_FieldDef_MessageSubDef(f)->layout; - } else if (field->descriptortype == kUpb_FieldType_Enum) { - field->submsg_index = sublayout_count++; - subs[field->submsg_index].subenum = upb_FieldDef_EnumSubDef(f)->layout; - UPB_ASSERT(subs[field->submsg_index].subenum); - } - - if (upb_FieldDef_Label(f) == kUpb_Label_Required) { - /* Hasbit was already assigned. */ - } else if (upb_FieldDef_HasPresence(f) && - !upb_FieldDef_RealContainingOneof(f)) { - /* We don't use hasbit 0, so that 0 can indicate "no presence" in the - * table. This wastes one hasbit, but we don't worry about it for now. */ - field->presence = ++hasbit; - } else { - field->presence = 0; - } - } - - /* Account for space used by hasbits. */ - l->size = hasbit ? div_round_up(hasbit + 1, 8) : 0; - - /* Allocate non-oneof fields. */ - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - size_t field_size = upb_msg_fielddefsize(f); - size_t index = upb_FieldDef_Index(f); - - if (upb_FieldDef_RealContainingOneof(f)) { - /* Oneofs are handled separately below. */ - continue; - } - - fields[index].offset = upb_MiniTable_place(ctx, l, field_size, m); - } - - /* Allocate oneof fields. Each oneof field consists of a uint32 for the case - * and space for the actual data. */ - for (int i = 0; i < m->oneof_count; i++) { - const upb_OneofDef* o = &m->oneofs[i]; - size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ - size_t field_size = 0; - uint32_t case_offset; - uint32_t data_offset; - - if (upb_OneofDef_IsSynthetic(o)) continue; - - if (o->field_count == 0) { - _upb_DefBuilder_Errf(ctx, "Oneof must have at least one field (%s)", - o->full_name); - } - - /* Calculate field size: the max of all field sizes. */ - for (int j = 0; j < o->field_count; j++) { - const upb_FieldDef* f = o->fields[j]; - field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); - } - - /* Align and allocate case offset. */ - case_offset = upb_MiniTable_place(ctx, l, case_size, m); - data_offset = upb_MiniTable_place(ctx, l, field_size, m); - - for (int i = 0; i < o->field_count; i++) { - const upb_FieldDef* f = o->fields[i]; - fields[upb_FieldDef_Index(f)].offset = data_offset; - fields[upb_FieldDef_Index(f)].presence = ~case_offset; - } - } - - /* Size of the entire structure should be a multiple of its greatest - * alignment. TODO: track overall alignment for real? */ - l->size = UPB_ALIGN_UP(l->size, 8); - - /* Sort fields by number. */ - if (fields) { - qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), - field_number_cmp); - } - assign_layout_indices(m, l, fields); -} - -static char* strviewdup(upb_DefBuilder* ctx, upb_StringView view) { - char* ret = upb_strdup2(view.data, view.size, ctx->arena); - if (!ret) _upb_DefBuilder_OomErr(ctx); - return ret; -} - -static bool streql2(const char* a, size_t n, const char* b) { - return n == strlen(b) && memcmp(a, b, n) == 0; -} - -static bool streql_view(upb_StringView view, const char* b) { - return streql2(view.data, view.size, b); -} - -static const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, - const char* prefix, - upb_StringView name) { - if (prefix) { - /* ret = prefix + '.' + name; */ - size_t n = strlen(prefix); - char* ret = _upb_DefBuilder_Alloc(ctx, n + name.size + 2); - strcpy(ret, prefix); - ret[n] = '.'; - memcpy(&ret[n + 1], name.data, name.size); - ret[n + 1 + name.size] = '\0'; - return ret; - } else { - return strviewdup(ctx, name); - } -} - -static void finalize_oneofs(upb_DefBuilder* ctx, upb_MessageDef* m) { - int i; - int synthetic_count = 0; - upb_OneofDef* mutable_oneofs = (upb_OneofDef*)m->oneofs; - - for (i = 0; i < m->oneof_count; i++) { - upb_OneofDef* o = &mutable_oneofs[i]; - - if (o->synthetic && o->field_count != 1) { - _upb_DefBuilder_Errf(ctx, - "Synthetic oneofs must have one field, not %d: %s", - o->field_count, upb_OneofDef_Name(o)); - } - - if (o->synthetic) { - synthetic_count++; - } else if (synthetic_count != 0) { - _upb_DefBuilder_Errf( - ctx, "Synthetic oneofs must be after all other oneofs: %s", - upb_OneofDef_Name(o)); - } - - o->fields = - _upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); - o->field_count = 0; - } - - for (i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); - if (o) { - o->fields[o->field_count++] = f; - } - } - - m->real_oneof_count = m->oneof_count - synthetic_count; -} - -size_t getjsonname(const char* name, char* buf, size_t len) { - size_t src, dst = 0; - bool ucase_next = false; - -#define WRITE(byte) \ - ++dst; \ - if (dst < len) \ - buf[dst - 1] = byte; \ - else if (dst == len) \ - buf[dst - 1] = '\0' - - if (!name) { - WRITE('\0'); - return 0; - } - - /* Implement the transformation as described in the spec: - * 1. upper case all letters after an underscore. - * 2. remove all underscores. - */ - for (src = 0; name[src]; src++) { - if (name[src] == '_') { - ucase_next = true; - continue; - } - - if (ucase_next) { - WRITE(toupper(name[src])); - ucase_next = false; - } else { - WRITE(name[src]); - } - } - - WRITE('\0'); - return dst; - -#undef WRITE -} - -static char* makejsonname(upb_DefBuilder* ctx, const char* name) { - size_t size = getjsonname(name, NULL, 0); - char* json_name = _upb_DefBuilder_Alloc(ctx, size); - getjsonname(name, json_name, size); - return json_name; -} - -/* Adds a symbol |v| to the symtab, which must be a def pointer previously - * packed with pack_def(). The def's pointer to upb_FileDef* must be set before - * adding, so we know which entries to remove if building this file fails. */ -static void _upb_DefBuilder_Add(upb_DefBuilder* ctx, const char* name, - upb_value v) { - // TODO: table should support an operation "tryinsert" to avoid the double - // lookup. - if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) { - _upb_DefBuilder_Errf(ctx, "duplicate symbol '%s'", name); - } - size_t len = strlen(name); - bool ok = - upb_strtable_insert(&ctx->symtab->syms, name, len, v, ctx->symtab->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); -} - -static bool remove_component(char* base, size_t* len) { - if (*len == 0) return false; - - for (size_t i = *len - 1; i > 0; i--) { - if (base[i] == '.') { - *len = i; - return true; - } - } - - *len = 0; - return true; -} - -/* Given a symbol and the base symbol inside which it is defined, find the - * symbol's definition in t. */ -static const void* symtab_resolveany(upb_DefBuilder* ctx, - const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t* type) { - const upb_strtable* t = &ctx->symtab->syms; - if (sym.size == 0) goto notfound; - upb_value v; - if (sym.data[0] == '.') { - /* Symbols starting with '.' are absolute, so we do a single lookup. - * Slice to omit the leading '.' */ - if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) { - goto notfound; - } - } else { - /* Remove components from base until we find an entry or run out. */ - size_t baselen = base ? strlen(base) : 0; - char* tmp = malloc(sym.size + baselen + 1); - while (1) { - char* p = tmp; - if (baselen) { - memcpy(p, base, baselen); - p[baselen] = '.'; - p += baselen + 1; - } - memcpy(p, sym.data, sym.size); - p += sym.size; - if (upb_strtable_lookup2(t, tmp, p - tmp, &v)) { - break; - } - if (!remove_component(tmp, &baselen)) { - free(tmp); - goto notfound; - } - } - free(tmp); - } - - *type = deftype(v); - return _upb_DefUtil_Unpack(v, *type); - -notfound: - _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(sym)); -} - -static const void* symtab_resolve(upb_DefBuilder* ctx, - const char* from_name_dbg, const char* base, - upb_StringView sym, upb_deftype_t type) { - upb_deftype_t found_type; - const void* ret = - symtab_resolveany(ctx, from_name_dbg, base, sym, &found_type); - if (ret && found_type != type) { - _upb_DefBuilder_Errf(ctx, - "type mismatch when resolving %s: couldn't find " - "name " UPB_STRINGVIEW_FORMAT " with type=%d", - from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); - } - return ret; -} - -static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, - const google_protobuf_OneofDescriptorProto* oneof_proto, - const upb_OneofDef* _o) { - upb_OneofDef* o = (upb_OneofDef*)_o; - upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); - upb_value v; - - o->parent = m; - o->full_name = _upb_DefBuilder_MakeFullName(ctx, m->full_name, name); - o->field_count = 0; - o->synthetic = false; - - SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); - - upb_value existing_v; - if (upb_strtable_lookup2(&m->ntof, name.data, name.size, &existing_v)) { - _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); - } - - v = _upb_DefUtil_Pack(o, UPB_DEFTYPE_ONEOF, sizeof(upb_OneofDef)); - - bool ok = upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - - ok = upb_inttable_init(&o->itof, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - - ok = upb_strtable_init(&o->ntof, 4, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); -} - -// Allocate and initialize an array of |n| oneof defs. -static upb_OneofDef* _upb_OneofDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m) { - upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); - for (int i = 0; i < n; i++) { - create_oneofdef(ctx, m, protos[i], &o[i]); - } - return o; -} - -static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { - str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); - if (!ret) _upb_DefBuilder_OomErr(ctx); - ret->len = len; - if (len) memcpy(ret->str, data, len); - ret->str[len] = '\0'; - return ret; -} - -static bool upb_DefPool_TryGetChar(const char** src, const char* end, - char* ch) { - if (*src == end) return false; - *ch = **src; - *src += 1; - return true; -} - -static char upb_DefPool_TryGetHexDigit(const upb_FieldDef* f, const char** src, - const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; - if ('0' <= ch && ch <= '9') { - return ch - '0'; - } - ch = upb_ascii_lower(ch); - if ('a' <= ch && ch <= 'f') { - return ch - 'a' + 0xa; - } - *src -= 1; // Char wasn't actually a hex digit. - return -1; -} - -static char upb_DefPool_ParseHexEscape(upb_DefBuilder* ctx, - const upb_FieldDef* f, const char** src, - const char* end) { - char hex_digit = upb_DefPool_TryGetHexDigit(f, src, end); - if (hex_digit < 0) { - _upb_DefBuilder_Errf( - ctx, "\\x cannot be followed by non-hex digit in field '%s' default", - upb_FieldDef_FullName(f)); - return 0; - } - unsigned int ret = hex_digit; - while ((hex_digit = upb_DefPool_TryGetHexDigit(f, src, end)) >= 0) { - ret = (ret << 4) | hex_digit; - } - if (ret > 0xff) { - _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", - upb_FieldDef_FullName(f)); - return 0; - } - return ret; -} - -char upb_DefPool_TryGetOctalDigit(const char** src, const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; - if ('0' <= ch && ch <= '7') { - return ch - '0'; - } - *src -= 1; // Char wasn't actually an octal digit. - return -1; -} - -static char upb_DefPool_ParseOctalEscape(upb_DefBuilder* ctx, - const upb_FieldDef* f, - const char** src, const char* end) { - char ch = 0; - for (int i = 0; i < 3; i++) { - char digit; - if ((digit = upb_DefPool_TryGetOctalDigit(src, end)) >= 0) { - ch = (ch << 3) | digit; - } - } - return ch; -} - -static char upb_DefPool_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, - const char** src, const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) { - _upb_DefBuilder_Errf(ctx, "unterminated escape sequence in field %s", - upb_FieldDef_FullName(f)); - return 0; - } - switch (ch) { - case 'a': - return '\a'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - case 'v': - return '\v'; - case '\\': - return '\\'; - case '\'': - return '\''; - case '\"': - return '\"'; - case '?': - return '\?'; - case 'x': - case 'X': - return upb_DefPool_ParseHexEscape(ctx, f, src, end); - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - *src -= 1; - return upb_DefPool_ParseOctalEscape(ctx, f, src, end); - } - _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); -} - -static str_t* unescape(upb_DefBuilder* ctx, const upb_FieldDef* f, - const char* data, size_t len) { - // Size here is an upper bound; escape sequences could ultimately shrink it. - str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); - char* dst = &ret->str[0]; - const char* src = data; - const char* end = data + len; - - while (src < end) { - if (*src == '\\') { - src++; - *dst++ = upb_DefPool_ParseEscape(ctx, f, &src, end); - } else { - *dst++ = *src++; - } - } - - ret->len = dst - &ret->str[0]; - return ret; -} - -static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, - upb_FieldDef* f) { - char* end; - char nullz[64]; - errno = 0; - - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: - case kUpb_CType_Int64: - case kUpb_CType_UInt32: - case kUpb_CType_UInt64: - case kUpb_CType_Double: - case kUpb_CType_Float: - /* Standard C number parsing functions expect null-terminated strings. */ - if (len >= sizeof(nullz) - 1) { - _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); - } - memcpy(nullz, str, len); - nullz[len] = '\0'; - str = nullz; - break; - default: - break; - } - - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: { - long val = strtol(str, &end, 0); - if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.sint = val; - break; - } - case kUpb_CType_Enum: { - const upb_EnumDef* e = f->sub.enumdef; - const upb_EnumValueDef* ev = - upb_EnumDef_FindValueByNameWithSize(e, str, len); - if (!ev) { - goto invalid; - } - f->defaultval.sint = ev->number; - break; - } - case kUpb_CType_Int64: { - long long val = strtoll(str, &end, 0); - if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.sint = val; - break; - } - case kUpb_CType_UInt32: { - unsigned long val = strtoul(str, &end, 0); - if (val > UINT32_MAX || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.uint = val; - break; - } - case kUpb_CType_UInt64: { - unsigned long long val = strtoull(str, &end, 0); - if (val > UINT64_MAX || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.uint = val; - break; - } - case kUpb_CType_Double: { - double val = strtod(str, &end); - if (errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.dbl = val; - break; - } - case kUpb_CType_Float: { - float val = strtof(str, &end); - if (errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.flt = val; - break; - } - case kUpb_CType_Bool: { - if (streql2(str, len, "false")) { - f->defaultval.boolean = false; - } else if (streql2(str, len, "true")) { - f->defaultval.boolean = true; - } else { - goto invalid; - } - break; - } - case kUpb_CType_String: - f->defaultval.str = newstr(ctx, str, len); - break; - case kUpb_CType_Bytes: - f->defaultval.str = unescape(ctx, f, str, len); - break; - case kUpb_CType_Message: - /* Should not have a default value. */ - _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", - upb_FieldDef_FullName(f)); - } - - return; - -invalid: - _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", - (int)len, str, upb_FieldDef_FullName(f), - (int)upb_FieldDef_Type(f)); -} - -static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: - case kUpb_CType_Int64: - f->defaultval.sint = 0; - break; - case kUpb_CType_UInt64: - case kUpb_CType_UInt32: - f->defaultval.uint = 0; - break; - case kUpb_CType_Double: - case kUpb_CType_Float: - f->defaultval.dbl = 0; - break; - case kUpb_CType_String: - case kUpb_CType_Bytes: - f->defaultval.str = newstr(ctx, NULL, 0); - break; - case kUpb_CType_Bool: - f->defaultval.boolean = false; - break; - case kUpb_CType_Enum: { - const upb_EnumValueDef* v = upb_EnumDef_Value(f->sub.enumdef, 0); - f->defaultval.sint = upb_EnumValueDef_Number(v); - } - case kUpb_CType_Message: - break; - } -} - -static void create_fielddef(upb_DefBuilder* ctx, const char* prefix, - upb_MessageDef* m, - const google_protobuf_FieldDescriptorProto* field_proto, - const upb_FieldDef* _f, bool is_extension) { - upb_FieldDef* f = (upb_FieldDef*)_f; - upb_StringView name; - const char* full_name; - const char* json_name; - const char* shortname; - int32_t field_number; - - f->file = ctx->file; // Must happen prior to _upb_DefBuilder_Add() - - if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { - _upb_DefBuilder_Errf(ctx, "field has no name"); - } - - name = google_protobuf_FieldDescriptorProto_name(field_proto); - _upb_DefBuilder_CheckIdent(ctx, name, false); - full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - shortname = _upb_DefUtil_FullToShort(full_name); - - if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) { - json_name = strviewdup( - ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto)); - f->has_json_name_ = true; - } else { - json_name = makejsonname(ctx, shortname); - f->has_json_name_ = false; - } - - field_number = google_protobuf_FieldDescriptorProto_number(field_proto); - - f->full_name = full_name; - f->json_name = json_name; - f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); - f->number_ = field_number; - f->scope.oneof = NULL; - f->proto3_optional_ = - google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); - - bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); - bool has_type_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); - - f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); - - if (has_type) { - switch (f->type_) { - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - case kUpb_FieldType_Enum: - if (!has_type_name) { - _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", - (int)f->type_, full_name); - } - break; - default: - if (has_type_name) { - _upb_DefBuilder_Errf( - ctx, "invalid type for field with type_name set (%s, %d)", - full_name, (int)f->type_); - } - } - } else if (has_type_name) { - f->type_ = - FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef(). - } - - if (!is_extension) { - /* direct message field. */ - upb_value v, field_v, json_v, existing_v; - size_t json_size; - - if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { - _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); - } - - f->index_ = f - m->fields; - f->msgdef = m; - f->is_extension_ = false; - - field_v = _upb_DefUtil_Pack(f, UPB_DEFTYPE_FIELD, sizeof(upb_FieldDef)); - json_v = - _upb_DefUtil_Pack(f, UPB_DEFTYPE_FIELD_JSONNAME, sizeof(upb_FieldDef)); - v = upb_value_constptr(f); - json_size = strlen(json_name); - - if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { - _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); - } - - bool ok = upb_strtable_insert(&m->ntof, name.data, name.size, field_v, - ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - - if (strcmp(shortname, json_name) != 0) { - if (upb_strtable_lookup(&m->ntof, json_name, &v)) { - _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); - } else { - ok = upb_strtable_insert(&m->ntof, json_name, json_size, json_v, - ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - } - } - - if (upb_inttable_lookup(&m->itof, field_number, NULL)) { - _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); - } - - ok = upb_inttable_insert(&m->itof, field_number, v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - - if (ctx->layout) { - const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); - const upb_MiniTable_Field* fields = mt->fields; - const int count = mt->field_count; - bool found = false; - for (int i = 0; i < count; i++) { - if (fields[i].number == field_number) { - f->layout_index = i; - found = true; - break; - } - } - UPB_ASSERT(found); - } - } else { - /* extension field. */ - f->is_extension_ = true; - f->scope.extension_scope = m; - _upb_DefBuilder_Add( - ctx, full_name, - _upb_DefUtil_Pack(f, UPB_DEFTYPE_EXT, sizeof(upb_FieldDef))); - f->layout_index = ctx->ext_count++; - if (ctx->layout) { - UPB_ASSERT(_upb_FieldDef_ExtensionMiniTable(f)->field.number == - field_number); - } - } - - if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { - _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, - f->type_); - } - - if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { - _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, - f->label_); - } - - /* We can't resolve the subdef or (in the case of extensions) the containing - * message yet, because it may not have been defined yet. We stash a pointer - * to the field_proto until later when we can properly resolve it. */ - f->sub.unresolved = field_proto; - - if (f->label_ == kUpb_Label_Required && - f->file->syntax == kUpb_Syntax_Proto3) { - _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", - f->full_name); - } - - if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); - upb_OneofDef* oneof; - upb_value v = upb_value_constptr(f); - - if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { - _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", - f->full_name); - } - - if (!m) { - _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", - f->full_name); - } - - if (oneof_index >= m->oneof_count) { - _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); - } - - oneof = (upb_OneofDef*)&m->oneofs[oneof_index]; - f->scope.oneof = oneof; - - oneof->field_count++; - if (f->proto3_optional_) { - oneof->synthetic = true; - } - - bool ok = upb_inttable_insert(&oneof->itof, f->number_, v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - - ok = upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - } else { - if (f->proto3_optional_) { - _upb_DefBuilder_Errf(ctx, - "field with proto3_optional was not in a oneof (%s)", - f->full_name); - } - } - - SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); - - if (google_protobuf_FieldOptions_has_packed(f->opts)) { - f->packed_ = google_protobuf_FieldOptions_packed(f->opts); - } else { - /* Repeated fields default to packed for proto3 only. */ - f->packed_ = upb_FieldDef_IsPrimitive(f) && - f->label_ == kUpb_Label_Repeated && - upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; - } -} - -static void create_method(upb_DefBuilder* ctx, - const google_protobuf_MethodDescriptorProto* method_proto, - upb_ServiceDef* s, upb_MethodDef* m) { - upb_StringView name = google_protobuf_MethodDescriptorProto_name(method_proto); - - m->service = s; - m->full_name = _upb_DefBuilder_MakeFullName(ctx, s->full_name, name); - m->client_streaming = - google_protobuf_MethodDescriptorProto_client_streaming(method_proto); - m->server_streaming = - google_protobuf_MethodDescriptorProto_server_streaming(method_proto); - m->input_type = symtab_resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_input_type(method_proto), UPB_DEFTYPE_MSG); - m->output_type = symtab_resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG); - - SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, method_proto); -} - -// Allocate and initialize an array of |n| method defs. -static upb_MethodDef* _upb_MethodDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s) { - upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); - for (int i = 0; i < n; i++) { - create_method(ctx, protos[i], s, &m[i]); - m[i].index = i; - } - return m; -} - -static void create_service(upb_DefBuilder* ctx, - const google_protobuf_ServiceDescriptorProto* svc_proto, - upb_ServiceDef* s) { - upb_StringView name; - size_t n; - - s->file = ctx->file; // Must happen prior to _upb_DefBuilder_Add() - - name = google_protobuf_ServiceDescriptorProto_name(svc_proto); - _upb_DefBuilder_CheckIdent(ctx, name, false); - s->full_name = _upb_DefBuilder_MakeFullName(ctx, ctx->file->package, name); - _upb_DefBuilder_Add( - ctx, s->full_name, - _upb_DefUtil_Pack(s, UPB_DEFTYPE_SERVICE, sizeof(upb_ServiceDef))); - - const google_protobuf_MethodDescriptorProto* const* methods = - google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); - s->method_count = n; - s->methods = _upb_MethodDefs_New(ctx, n, methods, s); - - SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, svc_proto); -} - -// Allocate and initialize an array of |n| service defs. -static upb_ServiceDef* _upb_ServiceDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_ServiceDescriptorProto* const* protos) { - upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); - for (int i = 0; i < n; i++) { - create_service(ctx, protos[i], &s[i]); - s[i].index = i; - } - return s; -} - -static int count_bits_debug(uint64_t x) { - // For assertions only, speed does not matter. - int n = 0; - while (x) { - if (x & 1) n++; - x >>= 1; - } - return n; -} - -static upb_MiniTable_Enum* create_enumlayout(upb_DefBuilder* ctx, - const upb_EnumDef* e) { - const char* desc = _upb_EnumDef_MiniDescriptor(e, ctx->tmp_arena); - if (!desc) - _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); - - upb_Status status; - upb_MiniTable_Enum* layout = - upb_MiniTable_BuildEnum(desc, strlen(desc), ctx->arena, &status); - if (!layout) - _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); - return layout; -} - -static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_EnumValueDescriptorProto* val_proto, - upb_EnumDef* e, upb_EnumValueDef* v) { - upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto); - upb_value val = upb_value_constptr(v); - - v->parent = e; // Must happen prior to _upb_DefBuilder_Add() - v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - v->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); - _upb_DefBuilder_Add( - ctx, v->full_name, - _upb_DefUtil_Pack(v, UPB_DEFTYPE_ENUMVAL, sizeof(upb_EnumDef))); - - SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, val_proto); - - bool ok = - upb_strtable_insert(&e->ntoi, name.data, name.size, val, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - - // Multiple enumerators can have the same number, first one wins. - if (!upb_inttable_lookup(&e->iton, v->number, NULL)) { - ok = upb_inttable_insert(&e->iton, v->number, val, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - } -} - -// Allocate and initialize an array of |n| enum value defs. -// TODO(b/243726666): This will eventually become the (only) public constructor. -static upb_EnumValueDef* _upb_EnumValueDefs_New( - upb_DefBuilder* ctx, const char* prefix, int n, - const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e) { - upb_EnumValueDef* v = - _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n); - - bool is_sorted = true; - uint32_t previous = 0; - for (size_t i = 0; i < n; i++) { - create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); - - const uint32_t current = v[i].number; - if (previous > current) is_sorted = false; - previous = current; - } - e->is_sorted = is_sorted; - - if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && - v[0].number != 0) { - _upb_DefBuilder_Errf(ctx, - "for proto3, the first enum value must be zero (%s)", - e->full_name); - } - - return v; -} - -static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_EnumDescriptorProto* enum_proto, - upb_EnumDef* e) { - const google_protobuf_EnumValueDescriptorProto* const* values; - upb_StringView name; - size_t n; - - e->file = ctx->file; // Must happen prior to _upb_DefBuilder_Add() - - name = google_protobuf_EnumDescriptorProto_name(enum_proto); - _upb_DefBuilder_CheckIdent(ctx, name, false); - - e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - _upb_DefBuilder_Add( - ctx, e->full_name, - _upb_DefUtil_Pack(e, UPB_DEFTYPE_ENUM, sizeof(upb_EnumDef))); - - values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); - - bool ok = upb_strtable_init(&e->ntoi, n, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - - ok = upb_inttable_init(&e->iton, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - - e->defaultval = 0; - e->value_count = n; - e->values = _upb_EnumValueDefs_New(ctx, prefix, n, values, e); - - if (n == 0) { - _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", - e->full_name); - } - - SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); - - upb_inttable_compact(&e->iton, ctx->arena); - - if (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2) { - if (ctx->layout) { - UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); - e->layout = ctx->layout->enums[ctx->enum_count++]; - } else { - e->layout = create_enumlayout(ctx, e); - } - } else { - e->layout = NULL; - } -} - -// Allocate and initialize an array of |n| enum defs. -// TODO(b/243726666): This will eventually become the (only) public constructor. -static upb_EnumDef* _upb_EnumDefs_New( - upb_DefBuilder* ctx, int n, const google_protobuf_EnumDescriptorProto* const* protos, - const upb_MessageDef* containing_type) { - // If a containing type is defined then get the full name from that. - // Otherwise use the package name from the file def. - const char* name = - containing_type ? containing_type->full_name : ctx->file->package; - - upb_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); - for (size_t i = 0; i < n; i++) { - create_enumdef(ctx, name, protos[i], &e[i]); - e[i].containing_type = containing_type; - } - return e; -} - -static void msgdef_create_nested(upb_DefBuilder* ctx, - const google_protobuf_DescriptorProto* msg_proto, - upb_MessageDef* m); - -static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_DescriptorProto* msg_proto, - const upb_MessageDef* containing_type, - const upb_MessageDef* _m) { - upb_MessageDef* m = (upb_MessageDef*)_m; - const google_protobuf_OneofDescriptorProto* const* oneofs; - const google_protobuf_FieldDescriptorProto* const* fields; - const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; - size_t i, n_oneof, n_field, n_ext_range; - upb_StringView name; - - m->file = ctx->file; // Must happen prior to _upb_DefBuilder_Add() - m->containing_type = containing_type; - - name = google_protobuf_DescriptorProto_name(msg_proto); - _upb_DefBuilder_CheckIdent(ctx, name, false); - - m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - _upb_DefBuilder_Add( - ctx, m->full_name, - _upb_DefUtil_Pack(m, UPB_DEFTYPE_MSG, sizeof(upb_MessageDef))); - - oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); - fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); - ext_ranges = - google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); - - bool ok = upb_inttable_init(&m->itof, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - - ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - - if (ctx->layout) { - /* create_fielddef() below depends on this being set. */ - UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count); - m->layout = ctx->layout->msgs[ctx->msg_count++]; - UPB_ASSERT(n_field == m->layout->field_count); - } else { - /* Allocate now (to allow cross-linking), populate later. */ - m->layout = _upb_DefBuilder_Alloc( - ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); - } - - SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); - - m->oneof_count = n_oneof; - m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); - - m->field_count = n_field; - m->fields = _upb_FieldDef_Alloc(ctx, n_field); - for (i = 0; i < n_field; i++) { - create_fielddef(ctx, m->full_name, m, fields[i], &m->fields[i], - /* is_extension= */ false); - } - - m->ext_range_count = n_ext_range; - m->ext_ranges = _upb_ExtensionRange_Alloc(ctx, n_ext_range); - for (i = 0; i < n_ext_range; i++) { - const google_protobuf_DescriptorProto_ExtensionRange* r = ext_ranges[i]; - upb_ExtensionRange* r_def = (upb_ExtensionRange*)&m->ext_ranges[i]; - int32_t start = google_protobuf_DescriptorProto_ExtensionRange_start(r); - int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(r); - int32_t max = - google_protobuf_MessageOptions_message_set_wire_format(m->opts) - ? INT32_MAX - : kUpb_MaxFieldNumber + 1; - - // A full validation would also check that each range is disjoint, and that - // none of the fields overlap with the extension ranges, but we are just - // sanity checking here. - if (start < 1 || end <= start || end > max) { - _upb_DefBuilder_Errf(ctx, - "Extension range (%d, %d) is invalid, message=%s\n", - (int)start, (int)end, m->full_name); - } - - r_def->start = start; - r_def->end = end; - SET_OPTIONS(r_def->opts, DescriptorProto_ExtensionRange, - ExtensionRangeOptions, r); - } - - finalize_oneofs(ctx, m); - assign_msg_wellknowntype(m); - upb_inttable_compact(&m->itof, ctx->arena); - msgdef_create_nested(ctx, msg_proto, m); -} - -// Allocate and initialize an array of |n| message defs. -static upb_MessageDef* _upb_MessageDefs_New( - upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, - const upb_MessageDef* containing_type) { - const char* name = - containing_type ? containing_type->full_name : ctx->file->package; - upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); - for (int i = 0; i < n; i++) { - create_msgdef(ctx, name, protos[i], containing_type, &m[i]); - } - return m; -} - -static void msgdef_create_nested(upb_DefBuilder* ctx, - const google_protobuf_DescriptorProto* msg_proto, - upb_MessageDef* m) { - size_t n; - - const google_protobuf_EnumDescriptorProto* const* enums = - google_protobuf_DescriptorProto_enum_type(msg_proto, &n); - m->nested_enum_count = n; - m->nested_enums = _upb_EnumDefs_New(ctx, n, enums, m); - - const google_protobuf_FieldDescriptorProto* const* exts = - google_protobuf_DescriptorProto_extension(msg_proto, &n); - m->nested_ext_count = n; - m->nested_exts = _upb_FieldDef_Alloc(ctx, n); - for (size_t i = 0; i < n; i++) { - create_fielddef(ctx, m->full_name, m, exts[i], &m->nested_exts[i], - /* is_extension= */ true); - ((upb_FieldDef*)&m->nested_exts[i])->index_ = i; - } - - const google_protobuf_DescriptorProto* const* msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - m->nested_msg_count = n; - m->nested_msgs = _upb_MessageDefs_New(ctx, n, msgs, m); -} - -static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix, - upb_FieldDef* f) { - const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; - upb_StringView name = - google_protobuf_FieldDescriptorProto_type_name(field_proto); - bool has_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); - switch ((int)f->type_) { - case FIELD_TYPE_UNSPECIFIED: { - // Type was not specified and must be inferred. - UPB_ASSERT(has_name); - upb_deftype_t type; - const void* def = - symtab_resolveany(ctx, f->full_name, prefix, name, &type); - switch (type) { - case UPB_DEFTYPE_ENUM: - f->sub.enumdef = def; - f->type_ = kUpb_FieldType_Enum; - break; - case UPB_DEFTYPE_MSG: - f->sub.msgdef = def; - f->type_ = kUpb_FieldType_Message; // It appears there is no way of - // this being a group. - break; - default: - _upb_DefBuilder_Errf(ctx, "Couldn't resolve type name for field %s", - f->full_name); - } - } - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - UPB_ASSERT(has_name); - f->sub.msgdef = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - break; - case kUpb_FieldType_Enum: - UPB_ASSERT(has_name); - f->sub.enumdef = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_ENUM); - break; - default: - // No resolution necessary. - break; - } -} - -static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, - upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { - _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", - f->full_name); - } - - upb_StringView name = google_protobuf_FieldDescriptorProto_extendee(field_proto); - const upb_MessageDef* m = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - f->msgdef = m; - - bool found = false; - - for (int i = 0, n = m->ext_range_count; i < n; i++) { - const upb_ExtensionRange* r = &m->ext_ranges[i]; - if (r->start <= f->number_ && f->number_ < r->end) { - found = true; - break; - } - } - - if (!found) { - _upb_DefBuilder_Errf( - ctx, - "field number %u in extension %s has no extension range in " - "message %s", - (unsigned)f->number_, f->full_name, f->msgdef->full_name); - } - - const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); - if (ctx->layout) { - UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); - } else { - upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; - fill_fieldlayout(&mut_ext->field, f); - mut_ext->field.presence = 0; - mut_ext->field.offset = 0; - mut_ext->field.submsg_index = 0; - mut_ext->extendee = f->msgdef->layout; - mut_ext->sub.submsg = f->sub.msgdef->layout; - } - - bool ok = upb_inttable_insert(&ctx->symtab->exts, (uintptr_t)ext, - upb_value_constptr(f), ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); -} - -static void resolve_default(upb_DefBuilder* ctx, upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - // Have to delay resolving of the default value until now because of the enum - // case, since enum defaults are specified with a label. - if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { - upb_StringView defaultval = - google_protobuf_FieldDescriptorProto_default_value(field_proto); - - if (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { - _upb_DefBuilder_Errf(ctx, - "proto3 fields cannot have explicit defaults (%s)", - f->full_name); - } - - if (upb_FieldDef_IsSubMessage(f)) { - _upb_DefBuilder_Errf(ctx, - "message fields cannot have explicit defaults (%s)", - f->full_name); - } - - parse_default(ctx, defaultval.data, defaultval.size, f); - f->has_default = true; - } else { - set_default_default(ctx, f); - f->has_default = false; - } -} - -static void resolve_fielddef(upb_DefBuilder* ctx, const char* prefix, - upb_FieldDef* f) { - // We have to stash this away since resolve_subdef() may overwrite it. - const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; - - resolve_subdef(ctx, prefix, f); - resolve_default(ctx, f, field_proto); - - if (f->is_extension_) { - resolve_extension(ctx, prefix, f, field_proto); - } -} - -static void resolve_msgdef(upb_DefBuilder* ctx, upb_MessageDef* m) { - for (int i = 0; i < m->field_count; i++) { - resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->fields[i]); - } - - m->in_message_set = false; - for (int i = 0; i < m->nested_ext_count; i++) { - upb_FieldDef* ext = (upb_FieldDef*)&m->nested_exts[i]; - resolve_fielddef(ctx, m->full_name, ext); - if (ext->type_ == kUpb_FieldType_Message && - ext->label_ == kUpb_Label_Optional && ext->sub.msgdef == m && - google_protobuf_MessageOptions_message_set_wire_format( - ext->msgdef->opts)) { - m->in_message_set = true; - } - } - - if (!ctx->layout) make_layout(ctx, m); - - for (int i = 0; i < m->nested_msg_count; i++) { - resolve_msgdef(ctx, (upb_MessageDef*)&m->nested_msgs[i]); - } -} - -static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { - size_t n; - google_protobuf_DescriptorProto_extension(msg_proto, &n); - int ext_count = n; - - const google_protobuf_DescriptorProto* const* nested_msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - for (size_t i = 0; i < n; i++) { - ext_count += count_exts_in_msg(nested_msgs[i]); - } - - return ext_count; -} - -// Allocate and initialize one file def, and add it to the context object. -static void _upb_FileDef_Create(upb_DefBuilder* ctx, - const google_protobuf_FileDescriptorProto* file_proto) { - upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); - ctx->file = file; - - const google_protobuf_DescriptorProto* const* msgs; - const google_protobuf_EnumDescriptorProto* const* enums; - const google_protobuf_FieldDescriptorProto* const* exts; - const google_protobuf_ServiceDescriptorProto* const* services; - const upb_StringView* strs; - const int32_t* public_deps; - const int32_t* weak_deps; - size_t i, n; - - file->symtab = ctx->symtab; - - /* Count all extensions in the file, to build a flat array of layouts. */ - google_protobuf_FileDescriptorProto_extension(file_proto, &n); - int ext_count = n; - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - for (int i = 0; i < n; i++) { - ext_count += count_exts_in_msg(msgs[i]); - } - file->ext_count = ext_count; - - if (ctx->layout) { - /* We are using the ext layouts that were passed in. */ - file->ext_layouts = ctx->layout->exts; - if (ctx->layout->ext_count != file->ext_count) { - _upb_DefBuilder_Errf(ctx, - "Extension count did not match layout (%d vs %d)", - ctx->layout->ext_count, file->ext_count); - } - } else { - /* We are building ext layouts from scratch. */ - file->ext_layouts = _upb_DefBuilder_Alloc( - ctx, sizeof(*file->ext_layouts) * file->ext_count); - upb_MiniTable_Extension* ext = - _upb_DefBuilder_Alloc(ctx, sizeof(*ext) * file->ext_count); - for (int i = 0; i < file->ext_count; i++) { - file->ext_layouts[i] = &ext[i]; - } - } - - if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { - _upb_DefBuilder_Errf(ctx, "File has no name"); - } - - file->name = strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); - - upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); - if (package.size) { - _upb_DefBuilder_CheckIdent(ctx, package, true); - file->package = strviewdup(ctx, package); - } else { - file->package = NULL; - } - - if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { - upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file_proto); - - if (streql_view(syntax, "proto2")) { - file->syntax = kUpb_Syntax_Proto2; - } else if (streql_view(syntax, "proto3")) { - file->syntax = kUpb_Syntax_Proto3; - } else { - _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(syntax)); - } - } else { - file->syntax = kUpb_Syntax_Proto2; - } - - /* Read options. */ - SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); - - /* Verify dependencies. */ - strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); - file->dep_count = n; - file->deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->deps) * n); - - for (i = 0; i < n; i++) { - upb_StringView str = strs[i]; - file->deps[i] = - upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); - if (!file->deps[i]) { - _upb_DefBuilder_Errf(ctx, - "Depends on file '" UPB_STRINGVIEW_FORMAT - "', but it has not been loaded", - UPB_STRINGVIEW_ARGS(str)); - } - } - - public_deps = google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); - file->public_dep_count = n; - file->public_deps = - _upb_DefBuilder_Alloc(ctx, sizeof(*file->public_deps) * n); - int32_t* mutable_public_deps = (int32_t*)file->public_deps; - for (i = 0; i < n; i++) { - if (public_deps[i] >= file->dep_count) { - _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", - (int)public_deps[i]); - } - mutable_public_deps[i] = public_deps[i]; - } - - weak_deps = google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); - file->weak_dep_count = n; - file->weak_deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->weak_deps) * n); - int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; - for (i = 0; i < n; i++) { - if (weak_deps[i] >= file->dep_count) { - _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", - (int)weak_deps[i]); - } - mutable_weak_deps[i] = weak_deps[i]; - } - - // Create enums. - enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); - file->top_lvl_enum_count = n; - file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); - - /* Create extensions. */ - exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); - file->top_lvl_ext_count = n; - file->top_lvl_exts = _upb_FieldDef_Alloc(ctx, n); - for (i = 0; i < n; i++) { - create_fielddef(ctx, file->package, NULL, exts[i], &file->top_lvl_exts[i], - /* is_extension= */ true); - ((upb_FieldDef*)&file->top_lvl_exts[i])->index_ = i; - } - - // Create messages. - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - file->top_lvl_msg_count = n; - file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); - - // Create services. - services = google_protobuf_FileDescriptorProto_service(file_proto, &n); - file->service_count = n; - file->services = _upb_ServiceDefs_New(ctx, n, services); - - /* Now that all names are in the table, build layouts and resolve refs. */ - for (i = 0; i < (size_t)file->top_lvl_ext_count; i++) { - resolve_fielddef(ctx, file->package, (upb_FieldDef*)&file->top_lvl_exts[i]); - } - - for (i = 0; i < (size_t)file->top_lvl_msg_count; i++) { - resolve_msgdef(ctx, (upb_MessageDef*)&file->top_lvl_msgs[i]); - } - - if (file->ext_count) { - bool ok = _upb_extreg_add(ctx->symtab->extreg, file->ext_layouts, - file->ext_count); - if (!ok) _upb_DefBuilder_OomErr(ctx); - } -} - -static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { - intptr_t iter = UPB_INTTABLE_BEGIN; - upb_StringView key; - upb_value val; - while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { - const upb_FileDef* f; - switch (deftype(val)) { - case UPB_DEFTYPE_EXT: - f = upb_FieldDef_File(_upb_DefUtil_Unpack(val, UPB_DEFTYPE_EXT)); - break; - case UPB_DEFTYPE_MSG: - f = upb_MessageDef_File(_upb_DefUtil_Unpack(val, UPB_DEFTYPE_MSG)); - break; - case UPB_DEFTYPE_ENUM: - f = upb_EnumDef_File(_upb_DefUtil_Unpack(val, UPB_DEFTYPE_ENUM)); - break; - case UPB_DEFTYPE_ENUMVAL: - f = upb_EnumDef_File(upb_EnumValueDef_Enum( - _upb_DefUtil_Unpack(val, UPB_DEFTYPE_ENUMVAL))); - break; - case UPB_DEFTYPE_SERVICE: - f = upb_ServiceDef_File(_upb_DefUtil_Unpack(val, UPB_DEFTYPE_SERVICE)); - break; - default: - UPB_UNREACHABLE(); - } - - if (f == file) upb_strtable_removeiter(&s->syms, &iter); - } -} - -static const upb_FileDef* _upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - const upb_MiniTable_File* layout, upb_Status* status) { - const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); - - // Determine whether we already know about this file. - { - upb_value v; - if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { - upb_Status_SetErrorFormat(status, "duplicate file name (%.*s)", - UPB_STRINGVIEW_ARGS(name)); - return NULL; - } - } - - upb_DefBuilder ctx = { - .symtab = s, - .layout = layout, - .msg_count = 0, - .enum_count = 0, - .ext_count = 0, - .status = status, - .file = NULL, - .arena = upb_Arena_New(), - .tmp_arena = upb_Arena_New(), - }; - - if (UPB_SETJMP(ctx.err)) { - UPB_ASSERT(!upb_Status_IsOk(status)); - if (ctx.file) { - remove_filedef(s, ctx.file); - ctx.file = NULL; - } - } else if (!ctx.arena || !ctx.tmp_arena) { - _upb_DefBuilder_OomErr(&ctx); - } else { - _upb_FileDef_Create(&ctx, file_proto); - upb_strtable_insert(&s->files, name.data, name.size, - upb_value_constptr(ctx.file), ctx.arena); - UPB_ASSERT(upb_Status_IsOk(status)); - upb_Arena_Fuse(s->arena, ctx.arena); - } - - if (ctx.arena) upb_Arena_Free(ctx.arena); - if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); - return ctx.file; -} - -const upb_FileDef* upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - upb_Status* status) { - return _upb_DefPool_AddFile(s, file_proto, NULL, status); -} - -/* Include here since we want most of this file to be stdio-free. */ -#include - -bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, - bool rebuild_minitable) { - /* Since this function should never fail (it would indicate a bug in upb) we - * print errors to stderr instead of returning error status to the user. */ - _upb_DefPool_Init** deps = init->deps; - google_protobuf_FileDescriptorProto* file; - upb_Arena* arena; - upb_Status status; - - upb_Status_Clear(&status); - - if (upb_DefPool_FindFileByName(s, init->filename)) { - return true; - } - - arena = upb_Arena_New(); - - for (; *deps; deps++) { - if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; - } - - file = google_protobuf_FileDescriptorProto_parse_ex( - init->descriptor.data, init->descriptor.size, NULL, - kUpb_DecodeOption_AliasString, arena); - s->bytes_loaded += init->descriptor.size; - - if (!file) { - upb_Status_SetErrorFormat( - &status, - "Failed to parse compiled-in descriptor for file '%s'. This should " - "never happen.", - init->filename); - goto err; - } - - const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; - if (!_upb_DefPool_AddFile(s, file, mt, &status)) { - goto err; - } - - upb_Arena_Free(arena); - return true; - -err: - fprintf(stderr, - "Error loading compiled-in descriptor for file '%s' (this should " - "never happen): %s\n", - init->filename, upb_Status_ErrorMessage(&status)); - upb_Arena_Free(arena); - return false; -} - -size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { - return s->bytes_loaded; -} - -upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } - -const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( - const upb_DefPool* s, const upb_MiniTable_Extension* ext) { - upb_value v; - bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); - UPB_ASSERT(ok); - return upb_value_getconstptr(v); -} - -const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, - const upb_MessageDef* m, - int32_t fieldnum) { - const upb_MiniTable* l = upb_MessageDef_MiniTable(m); - const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum); - return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; -} - -const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( - const upb_DefPool* s) { - return s->extreg; -} - -const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, - const upb_MessageDef* m, - size_t* count) { - size_t n = 0; - intptr_t iter = UPB_INTTABLE_BEGIN; - uintptr_t key; - upb_value val; - // This is O(all exts) instead of O(exts for m). If we need this to be - // efficient we may need to make extreg into a two-level table, or have a - // second per-message index. - while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { - const upb_FieldDef* f = upb_value_getconstptr(val); - if (upb_FieldDef_ContainingType(f) == m) n++; - } - const upb_FieldDef** exts = malloc(n * sizeof(*exts)); - iter = UPB_INTTABLE_BEGIN; - size_t i = 0; - while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { - const upb_FieldDef* f = upb_value_getconstptr(val); - if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; - } - *count = n; - return exts; -} diff --git a/upb/def.h b/upb/def.h index 5fd5fb703b..164b91b072 100644 --- a/upb/def.h +++ b/upb/def.h @@ -25,395 +25,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// This header is deprecated, use upb/reflection/def.h instead + #ifndef UPB_DEF_H_ #define UPB_DEF_H_ -#include "google/protobuf/descriptor.upb.h" -#include "upb/internal/table.h" -#include "upb/upb.h" - -// Must be last. -#include "upb/port_def.inc" - -#ifdef __cplusplus -extern "C" { -#endif - -struct upb_EnumDef; -typedef struct upb_EnumDef upb_EnumDef; -struct upb_EnumValueDef; -typedef struct upb_EnumValueDef upb_EnumValueDef; -struct upb_ExtensionRange; -typedef struct upb_ExtensionRange upb_ExtensionRange; -struct upb_FieldDef; -typedef struct upb_FieldDef upb_FieldDef; -struct upb_FileDef; -typedef struct upb_FileDef upb_FileDef; -struct upb_MethodDef; -typedef struct upb_MethodDef upb_MethodDef; -struct upb_MessageDef; -typedef struct upb_MessageDef upb_MessageDef; -struct upb_OneofDef; -typedef struct upb_OneofDef upb_OneofDef; -struct upb_ServiceDef; -typedef struct upb_ServiceDef upb_ServiceDef; -struct upb_streamdef; -typedef struct upb_streamdef upb_streamdef; -struct upb_DefPool; -typedef struct upb_DefPool upb_DefPool; - -typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; - -/* All the different kind of well known type messages. For simplicity of check, - * number wrappers and string wrappers are grouped together. Make sure the - * order and merber of these groups are not changed. - */ -typedef enum { - kUpb_WellKnown_Unspecified, - kUpb_WellKnown_Any, - kUpb_WellKnown_FieldMask, - kUpb_WellKnown_Duration, - kUpb_WellKnown_Timestamp, - /* number wrappers */ - kUpb_WellKnown_DoubleValue, - kUpb_WellKnown_FloatValue, - kUpb_WellKnown_Int64Value, - kUpb_WellKnown_UInt64Value, - kUpb_WellKnown_Int32Value, - kUpb_WellKnown_UInt32Value, - /* string wrappers */ - kUpb_WellKnown_StringValue, - kUpb_WellKnown_BytesValue, - kUpb_WellKnown_BoolValue, - kUpb_WellKnown_Value, - kUpb_WellKnown_ListValue, - kUpb_WellKnown_Struct -} upb_WellKnown; - -/* upb_FieldDef ***************************************************************/ - -/* Maximum field number allowed for FieldDefs. This is an inherent limit of the - * protobuf wire format. */ -#define kUpb_MaxFieldNumber ((1 << 29) - 1) - -const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f); -bool upb_FieldDef_HasOptions(const upb_FieldDef* f); -const char* upb_FieldDef_FullName(const upb_FieldDef* f); -upb_CType upb_FieldDef_CType(const upb_FieldDef* f); -upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); -upb_Label upb_FieldDef_Label(const upb_FieldDef* f); -uint32_t upb_FieldDef_Number(const upb_FieldDef* f); -const char* upb_FieldDef_Name(const upb_FieldDef* f); -const char* upb_FieldDef_JsonName(const upb_FieldDef* f); -bool upb_FieldDef_HasJsonName(const upb_FieldDef* f); -bool upb_FieldDef_IsExtension(const upb_FieldDef* f); -bool upb_FieldDef_IsPacked(const upb_FieldDef* f); -const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f); -const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f); -const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f); -const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f); -const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f); -uint32_t upb_FieldDef_Index(const upb_FieldDef* f); -bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f); -bool upb_FieldDef_IsString(const upb_FieldDef* f); -bool upb_FieldDef_IsOptional(const upb_FieldDef* f); -bool upb_FieldDef_IsRequired(const upb_FieldDef* f); -bool upb_FieldDef_IsRepeated(const upb_FieldDef* f); -bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f); -bool upb_FieldDef_IsMap(const upb_FieldDef* f); -bool upb_FieldDef_HasDefault(const upb_FieldDef* f); -bool upb_FieldDef_HasSubDef(const upb_FieldDef* f); -bool upb_FieldDef_HasPresence(const upb_FieldDef* f); -const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); -const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f); -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f); -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( - const upb_FieldDef* f); -bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f); - -/* upb_OneofDef ***************************************************************/ - -const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o); -bool upb_OneofDef_HasOptions(const upb_OneofDef* o); -const char* upb_OneofDef_Name(const upb_OneofDef* o); -const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o); -uint32_t upb_OneofDef_Index(const upb_OneofDef* o); -bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o); -int upb_OneofDef_FieldCount(const upb_OneofDef* o); -const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i); - -/* Oneof lookups: - * - ntof: look up a field by name. - * - ntofz: look up a field by name (as a null-terminated string). - * - itof: look up a field by number. */ -const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, - const char* name, - size_t length); -UPB_INLINE const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, - const char* name) { - return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); -} -const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, - uint32_t num); - -/* upb_MessageDef *************************************************************/ - -/* Well-known field tag numbers for map-entry messages. */ -#define kUpb_MapEntry_KeyFieldNumber 1 -#define kUpb_MapEntry_ValueFieldNumber 2 - -/* Well-known field tag numbers for Any messages. */ -#define kUpb_Any_TypeFieldNumber 1 -#define kUpb_Any_ValueFieldNumber 2 - -/* Well-known field tag numbers for duration messages. */ -#define kUpb_Duration_SecondsFieldNumber 1 -#define kUpb_Duration_NanosFieldNumber 2 - -/* Well-known field tag numbers for timestamp messages. */ -#define kUpb_Timestamp_SecondsFieldNumber 1 -#define kUpb_Timestamp_NanosFieldNumber 2 - -const google_protobuf_MessageOptions* upb_MessageDef_Options( - const upb_MessageDef* m); -bool upb_MessageDef_HasOptions(const upb_MessageDef* m); -const char* upb_MessageDef_FullName(const upb_MessageDef* m); -const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m); -const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m); -const char* upb_MessageDef_Name(const upb_MessageDef* m); -upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m); -upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); -int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m); -int upb_MessageDef_FieldCount(const upb_MessageDef* m); -int upb_MessageDef_OneofCount(const upb_MessageDef* m); -const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, - int i); -const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i); -const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i); -const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, - uint32_t i); -const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len); -const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len); -const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m); - -UPB_INLINE const upb_OneofDef* upb_MessageDef_FindOneofByName( - const upb_MessageDef* m, const char* name) { - return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); -} - -UPB_INLINE const upb_FieldDef* upb_MessageDef_FindFieldByName( - const upb_MessageDef* m, const char* name) { - return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); -} - -UPB_INLINE bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { - return google_protobuf_MessageOptions_map_entry(upb_MessageDef_Options(m)); -} - -UPB_INLINE bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { - return google_protobuf_MessageOptions_message_set_wire_format( - upb_MessageDef_Options(m)); -} - -/* Nested entities. */ -int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); -int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); -int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m); -const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, - int i); -const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i); -const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, - int i); - -/* Lookup of either field or oneof by name. Returns whether either was found. - * If the return is true, then the found def will be set, and the non-found - * one set to NULL. */ -bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, - const char* name, size_t len, - const upb_FieldDef** f, - const upb_OneofDef** o); - -UPB_INLINE bool upb_MessageDef_FindByName(const upb_MessageDef* m, - const char* name, - const upb_FieldDef** f, - const upb_OneofDef** o) { - return upb_MessageDef_FindByNameWithSize(m, name, strlen(name), f, o); -} - -/* Returns a field by either JSON name or regular proto name. */ -const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( - const upb_MessageDef* m, const char* name, size_t len); -UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName( - const upb_MessageDef* m, const char* name) { - return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name)); -} - -/* upb_ExtensionRange *********************************************************/ - -const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( - const upb_ExtensionRange* r); -bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); -int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r); -int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); - -/* upb_EnumDef ****************************************************************/ - -const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e); -bool upb_EnumDef_HasOptions(const upb_EnumDef* e); -const char* upb_EnumDef_FullName(const upb_EnumDef* e); -const char* upb_EnumDef_Name(const upb_EnumDef* e); -const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e); -const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e); -int32_t upb_EnumDef_Default(const upb_EnumDef* e); -int upb_EnumDef_ValueCount(const upb_EnumDef* e); -const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); - -const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( - const upb_EnumDef* e, const char* name, size_t len); -const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, - int32_t num); -bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num); - -// Convenience wrapper. -UPB_INLINE const upb_EnumValueDef* upb_EnumDef_FindValueByName( - const upb_EnumDef* e, const char* name) { - return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); -} - -// Builds and returns a mini descriptor, or NULL if OOM. -const char* _upb_EnumDef_MiniDescriptor(const upb_EnumDef* e, upb_Arena* a); - -/* upb_EnumValueDef ***********************************************************/ - -const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( - const upb_EnumValueDef* e); -bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* e); -const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* e); -const char* upb_EnumValueDef_Name(const upb_EnumValueDef* e); -int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* e); -uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* e); -const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* e); - -/* upb_FileDef ****************************************************************/ - -const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f); -bool upb_FileDef_HasOptions(const upb_FileDef* f); -const char* upb_FileDef_Name(const upb_FileDef* f); -const char* upb_FileDef_Package(const upb_FileDef* f); -upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f); -int upb_FileDef_DependencyCount(const upb_FileDef* f); -int upb_FileDef_PublicDependencyCount(const upb_FileDef* f); -int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); -int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f); -int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f); -int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f); -int upb_FileDef_ServiceCount(const upb_FileDef* f); -const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i); -const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i); -const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i); -const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i); -const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i); -const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i); -const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i); -const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); -const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f); -const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f); - -/* upb_MethodDef **************************************************************/ - -const google_protobuf_MethodOptions* upb_MethodDef_Options( - const upb_MethodDef* m); -bool upb_MethodDef_HasOptions(const upb_MethodDef* m); -const char* upb_MethodDef_FullName(const upb_MethodDef* m); -int upb_MethodDef_Index(const upb_MethodDef* m); -const char* upb_MethodDef_Name(const upb_MethodDef* m); -const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); -const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); -const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); -bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m); -bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); - -/* upb_ServiceDef *************************************************************/ - -const google_protobuf_ServiceOptions* upb_ServiceDef_Options( - const upb_ServiceDef* s); -bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s); -const char* upb_ServiceDef_FullName(const upb_ServiceDef* s); -const char* upb_ServiceDef_Name(const upb_ServiceDef* s); -int upb_ServiceDef_Index(const upb_ServiceDef* s); -const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s); -int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); -const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i); -const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, - const char* name); - -/* upb_DefPool ****************************************************************/ - -upb_DefPool* upb_DefPool_New(void); -void upb_DefPool_Free(upb_DefPool* s); -const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, - const char* sym); -const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len); -const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, - const char* sym); -const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, - const char* sym); -const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, - const char* sym); -const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len); -const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, - const char* name); -const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, - const char* name); -const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( - const upb_DefPool* s, const char* name, size_t size); -const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, - const char* name); -const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, - const char* name, - size_t len); -const upb_FileDef* upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file, - upb_Status* status); -size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s); -upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s); -const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( - const upb_DefPool* s, const upb_MiniTable_Extension* ext); -const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, - const upb_MessageDef* m, - int32_t fieldnum); -const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( - const upb_DefPool* s); -const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, - const upb_MessageDef* m, - size_t* count); - -/* For generated code only: loads a generated descriptor. */ -typedef struct _upb_DefPool_Init { - struct _upb_DefPool_Init** deps; /* Dependencies of this file. */ - const upb_MiniTable_File* layout; - const char* filename; - upb_StringView descriptor; /* Serialized descriptor. */ -} _upb_DefPool_Init; - -// Should only be directly called by tests. This variant lets us suppress -// the use of compiled-in tables, forcing a rebuild of the tables at runtime. -bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, - bool rebuild_minitable); - -UPB_INLINE bool _upb_DefPool_LoadDefInit(upb_DefPool* s, - const _upb_DefPool_Init* init) { - return _upb_DefPool_LoadDefInitEx(s, init, false); -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#include "upb/port_undef.inc" +#include "upb/reflection/def.h" #endif /* UPB_DEF_H_ */ diff --git a/upb/def.hpp b/upb/def.hpp index 49cc560816..4a62909ab2 100644 --- a/upb/def.hpp +++ b/upb/def.hpp @@ -23,419 +23,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// This header is deprecated, use upb/reflection/def.hpp instead + #ifndef UPB_DEF_HPP_ #define UPB_DEF_HPP_ -#include -#include -#include -#include - -#include "upb/def.h" -#include "upb/reflection.h" -#include "upb/upb.hpp" - -namespace upb { - -typedef upb_MessageValue MessageValue; - -class EnumDefPtr; -class FileDefPtr; -class MessageDefPtr; -class OneofDefPtr; - -// A upb::FieldDefPtr describes a single field in a message. It is most often -// found as a part of a upb_MessageDef, but can also stand alone to represent -// an extension. -class FieldDefPtr { - public: - FieldDefPtr() : ptr_(nullptr) {} - explicit FieldDefPtr(const upb_FieldDef* ptr) : ptr_(ptr) {} - - const upb_FieldDef* ptr() const { return ptr_; } - explicit operator bool() const { return ptr_ != nullptr; } - - typedef upb_CType Type; - typedef upb_Label Label; - typedef upb_FieldType DescriptorType; - - const char* full_name() const { return upb_FieldDef_FullName(ptr_); } - - Type type() const { return upb_FieldDef_CType(ptr_); } - Label label() const { return upb_FieldDef_Label(ptr_); } - const char* name() const { return upb_FieldDef_Name(ptr_); } - const char* json_name() const { return upb_FieldDef_JsonName(ptr_); } - uint32_t number() const { return upb_FieldDef_Number(ptr_); } - bool is_extension() const { return upb_FieldDef_IsExtension(ptr_); } - - // For non-string, non-submessage fields, this indicates whether binary - // protobufs are encoded in packed or non-packed format. - // - // Note: this accessor reflects the fact that "packed" has different defaults - // depending on whether the proto is proto2 or proto3. - bool packed() const { return upb_FieldDef_IsPacked(ptr_); } - - // An integer that can be used as an index into an array of fields for - // whatever message this field belongs to. Guaranteed to be less than - // f->containing_type()->field_count(). May only be accessed once the def has - // been finalized. - uint32_t index() const { return upb_FieldDef_Index(ptr_); } - - // The MessageDef to which this field belongs. - // - // If this field has been added to a MessageDef, that message can be retrieved - // directly (this is always the case for frozen FieldDefs). - // - // If the field has not yet been added to a MessageDef, you can set the name - // of the containing type symbolically instead. This is mostly useful for - // extensions, where the extension is declared separately from the message. - MessageDefPtr containing_type() const; - - // The OneofDef to which this field belongs, or NULL if this field is not part - // of a oneof. - OneofDefPtr containing_oneof() const; - - // The field's type according to the enum in descriptor.proto. This is not - // the same as UPB_TYPE_*, because it distinguishes between (for example) - // INT32 and SINT32, whereas our "type" enum does not. This return of - // descriptor_type() is a function of type(), integer_format(), and - // is_tag_delimited(). - DescriptorType descriptor_type() const { return upb_FieldDef_Type(ptr_); } - - // Convenient field type tests. - bool IsSubMessage() const { return upb_FieldDef_IsSubMessage(ptr_); } - bool IsString() const { return upb_FieldDef_IsString(ptr_); } - bool IsSequence() const { return upb_FieldDef_IsRepeated(ptr_); } - bool IsPrimitive() const { return upb_FieldDef_IsPrimitive(ptr_); } - bool IsMap() const { return upb_FieldDef_IsMap(ptr_); } - - MessageValue default_value() const { return upb_FieldDef_Default(ptr_); } - - // Returns the enum or submessage def for this field, if any. The field's - // type must match (ie. you may only call enum_subdef() for fields where - // type() == kUpb_CType_Enum). - EnumDefPtr enum_subdef() const; - MessageDefPtr message_subdef() const; - - private: - const upb_FieldDef* ptr_; -}; - -// Class that represents a oneof. -class OneofDefPtr { - public: - OneofDefPtr() : ptr_(nullptr) {} - explicit OneofDefPtr(const upb_OneofDef* ptr) : ptr_(ptr) {} - - const upb_OneofDef* ptr() const { return ptr_; } - explicit operator bool() const { return ptr_ != nullptr; } - - // Returns the MessageDef that contains this OneofDef. - MessageDefPtr containing_type() const; - - // Returns the name of this oneof. - const char* name() const { return upb_OneofDef_Name(ptr_); } - - // Returns the number of fields in the oneof. - int field_count() const { return upb_OneofDef_FieldCount(ptr_); } - FieldDefPtr field(int i) const { - return FieldDefPtr(upb_OneofDef_Field(ptr_, i)); - } - - // Looks up by name. - FieldDefPtr FindFieldByName(const char* name, size_t len) const { - return FieldDefPtr(upb_OneofDef_LookupNameWithSize(ptr_, name, len)); - } - FieldDefPtr FindFieldByName(const char* name) const { - return FieldDefPtr(upb_OneofDef_LookupName(ptr_, name)); - } - - template - FieldDefPtr FindFieldByName(const T& str) const { - return FindFieldByName(str.c_str(), str.size()); - } - - // Looks up by tag number. - FieldDefPtr FindFieldByNumber(uint32_t num) const { - return FieldDefPtr(upb_OneofDef_LookupNumber(ptr_, num)); - } - - private: - const upb_OneofDef* ptr_; -}; - -// Structure that describes a single .proto message type. -class MessageDefPtr { - public: - MessageDefPtr() : ptr_(nullptr) {} - explicit MessageDefPtr(const upb_MessageDef* ptr) : ptr_(ptr) {} - - const upb_MessageDef* ptr() const { return ptr_; } - explicit operator bool() const { return ptr_ != nullptr; } - - FileDefPtr file() const; - - const char* full_name() const { return upb_MessageDef_FullName(ptr_); } - const char* name() const { return upb_MessageDef_Name(ptr_); } - - // The number of fields that belong to the MessageDef. - int field_count() const { return upb_MessageDef_FieldCount(ptr_); } - FieldDefPtr field(int i) const { - return FieldDefPtr(upb_MessageDef_Field(ptr_, i)); - } - - // The number of oneofs that belong to the MessageDef. - int oneof_count() const { return upb_MessageDef_OneofCount(ptr_); } - OneofDefPtr oneof(int i) const { - return OneofDefPtr(upb_MessageDef_Oneof(ptr_, i)); - } - - upb_Syntax syntax() const { return upb_MessageDef_Syntax(ptr_); } - - // These return null pointers if the field is not found. - FieldDefPtr FindFieldByNumber(uint32_t number) const { - return FieldDefPtr(upb_MessageDef_FindFieldByNumber(ptr_, number)); - } - FieldDefPtr FindFieldByName(const char* name, size_t len) const { - return FieldDefPtr(upb_MessageDef_FindFieldByNameWithSize(ptr_, name, len)); - } - FieldDefPtr FindFieldByName(const char* name) const { - return FieldDefPtr(upb_MessageDef_FindFieldByName(ptr_, name)); - } - - template - FieldDefPtr FindFieldByName(const T& str) const { - return FindFieldByName(str.c_str(), str.size()); - } - - OneofDefPtr FindOneofByName(const char* name, size_t len) const { - return OneofDefPtr(upb_MessageDef_FindOneofByNameWithSize(ptr_, name, len)); - } - - OneofDefPtr FindOneofByName(const char* name) const { - return OneofDefPtr(upb_MessageDef_FindOneofByName(ptr_, name)); - } - - template - OneofDefPtr FindOneofByName(const T& str) const { - return FindOneofByName(str.c_str(), str.size()); - } - - // Is this message a map entry? - bool mapentry() const { return upb_MessageDef_IsMapEntry(ptr_); } - - // Return the type of well known type message. kUpb_WellKnown_Unspecified for - // non-well-known message. - upb_WellKnown wellknowntype() const { - return upb_MessageDef_WellKnownType(ptr_); - } - - private: - class FieldIter { - public: - explicit FieldIter(const upb_MessageDef* m, int i) : m_(m), i_(i) {} - void operator++() { i_++; } - - FieldDefPtr operator*() { - return FieldDefPtr(upb_MessageDef_Field(m_, i_)); - } - bool operator!=(const FieldIter& other) { return i_ != other.i_; } - bool operator==(const FieldIter& other) { return i_ == other.i_; } - - private: - const upb_MessageDef* m_; - int i_; - }; - - class FieldAccessor { - public: - explicit FieldAccessor(const upb_MessageDef* md) : md_(md) {} - FieldIter begin() { return FieldIter(md_, 0); } - FieldIter end() { return FieldIter(md_, upb_MessageDef_FieldCount(md_)); } - - private: - const upb_MessageDef* md_; - }; - - class OneofIter { - public: - explicit OneofIter(const upb_MessageDef* m, int i) : m_(m), i_(i) {} - void operator++() { i_++; } - - OneofDefPtr operator*() { - return OneofDefPtr(upb_MessageDef_Oneof(m_, i_)); - } - bool operator!=(const OneofIter& other) { return i_ != other.i_; } - bool operator==(const OneofIter& other) { return i_ == other.i_; } - - private: - const upb_MessageDef* m_; - int i_; - }; - - class OneofAccessor { - public: - explicit OneofAccessor(const upb_MessageDef* md) : md_(md) {} - OneofIter begin() { return OneofIter(md_, 0); } - OneofIter end() { return OneofIter(md_, upb_MessageDef_OneofCount(md_)); } - - private: - const upb_MessageDef* md_; - }; - - public: - FieldAccessor fields() const { return FieldAccessor(ptr()); } - OneofAccessor oneofs() const { return OneofAccessor(ptr()); } - - private: - const upb_MessageDef* ptr_; -}; - -class EnumValDefPtr { - public: - EnumValDefPtr() : ptr_(nullptr) {} - explicit EnumValDefPtr(const upb_EnumValueDef* ptr) : ptr_(ptr) {} - - int32_t number() const { return upb_EnumValueDef_Number(ptr_); } - const char* full_name() const { return upb_EnumValueDef_FullName(ptr_); } - const char* name() const { return upb_EnumValueDef_Name(ptr_); } - - private: - const upb_EnumValueDef* ptr_; -}; - -class EnumDefPtr { - public: - EnumDefPtr() : ptr_(nullptr) {} - explicit EnumDefPtr(const upb_EnumDef* ptr) : ptr_(ptr) {} - - const upb_EnumDef* ptr() const { return ptr_; } - explicit operator bool() const { return ptr_ != nullptr; } - - const char* full_name() const { return upb_EnumDef_FullName(ptr_); } - const char* name() const { return upb_EnumDef_Name(ptr_); } - - // The value that is used as the default when no field default is specified. - // If not set explicitly, the first value that was added will be used. - // The default value must be a member of the enum. - // Requires that value_count() > 0. - int32_t default_value() const { return upb_EnumDef_Default(ptr_); } - - // Returns the number of values currently defined in the enum. Note that - // multiple names can refer to the same number, so this may be greater than - // the total number of unique numbers. - int value_count() const { return upb_EnumDef_ValueCount(ptr_); } - - // Lookups from name to integer, returning true if found. - EnumValDefPtr FindValueByName(const char* name) const { - return EnumValDefPtr(upb_EnumDef_FindValueByName(ptr_, name)); - } - - // Finds the name corresponding to the given number, or NULL if none was - // found. If more than one name corresponds to this number, returns the - // first one that was added. - EnumValDefPtr FindValueByNumber(int32_t num) const { - return EnumValDefPtr(upb_EnumDef_FindValueByNumber(ptr_, num)); - } - - private: - const upb_EnumDef* ptr_; -}; - -// Class that represents a .proto file with some things defined in it. -// -// Many users won't care about FileDefs, but they are necessary if you want to -// read the values of file-level options. -class FileDefPtr { - public: - explicit FileDefPtr(const upb_FileDef* ptr) : ptr_(ptr) {} - - const upb_FileDef* ptr() const { return ptr_; } - explicit operator bool() const { return ptr_ != nullptr; } - - // Get/set name of the file (eg. "foo/bar.proto"). - const char* name() const { return upb_FileDef_Name(ptr_); } - - // Package name for definitions inside the file (eg. "foo.bar"). - const char* package() const { return upb_FileDef_Package(ptr_); } - - // Syntax for the file. Defaults to proto2. - upb_Syntax syntax() const { return upb_FileDef_Syntax(ptr_); } - - // Get the list of dependencies from the file. These are returned in the - // order that they were added to the FileDefPtr. - int dependency_count() const { return upb_FileDef_DependencyCount(ptr_); } - const FileDefPtr dependency(int index) const { - return FileDefPtr(upb_FileDef_Dependency(ptr_, index)); - } - - private: - const upb_FileDef* ptr_; -}; - -// Non-const methods in upb::DefPool are NOT thread-safe. -class DefPool { - public: - DefPool() : ptr_(upb_DefPool_New(), upb_DefPool_Free) {} - explicit DefPool(upb_DefPool* s) : ptr_(s, upb_DefPool_Free) {} - - const upb_DefPool* ptr() const { return ptr_.get(); } - upb_DefPool* ptr() { return ptr_.get(); } - - // Finds an entry in the symbol table with this exact name. If not found, - // returns NULL. - MessageDefPtr FindMessageByName(const char* sym) const { - return MessageDefPtr(upb_DefPool_FindMessageByName(ptr_.get(), sym)); - } - - EnumDefPtr FindEnumByName(const char* sym) const { - return EnumDefPtr(upb_DefPool_FindEnumByName(ptr_.get(), sym)); - } - - FileDefPtr FindFileByName(const char* name) const { - return FileDefPtr(upb_DefPool_FindFileByName(ptr_.get(), name)); - } - - // TODO: iteration? - - // Adds the given serialized FileDescriptorProto to the pool. - FileDefPtr AddFile(const google_protobuf_FileDescriptorProto* file_proto, - Status* status) { - return FileDefPtr( - upb_DefPool_AddFile(ptr_.get(), file_proto, status->ptr())); - } - - private: - std::unique_ptr ptr_; -}; - -// TODO(b/236632406): This typedef is deprecated. Delete it. -using SymbolTable = DefPool; - -inline FileDefPtr MessageDefPtr::file() const { - return FileDefPtr(upb_MessageDef_File(ptr_)); -} - -inline MessageDefPtr FieldDefPtr::message_subdef() const { - return MessageDefPtr(upb_FieldDef_MessageSubDef(ptr_)); -} - -inline MessageDefPtr FieldDefPtr::containing_type() const { - return MessageDefPtr(upb_FieldDef_ContainingType(ptr_)); -} - -inline MessageDefPtr OneofDefPtr::containing_type() const { - return MessageDefPtr(upb_OneofDef_ContainingType(ptr_)); -} - -inline OneofDefPtr FieldDefPtr::containing_oneof() const { - return OneofDefPtr(upb_FieldDef_ContainingOneof(ptr_)); -} - -inline EnumDefPtr FieldDefPtr::enum_subdef() const { - return EnumDefPtr(upb_FieldDef_EnumSubDef(ptr_)); -} - -} // namespace upb +#include "upb/reflection/def.hpp" #endif // UPB_DEF_HPP_ diff --git a/upb/mini_table_accessors.c b/upb/mini_table_accessors.c index 4c892e0e9e..69847a96a3 100644 --- a/upb/mini_table_accessors.c +++ b/upb/mini_table_accessors.c @@ -186,7 +186,6 @@ upb_GetExtension_Status upb_MiniTable_GetOrPromoteExtension( int field_number = ext_table->field.number; upb_FindUnknownRet result = upb_MiniTable_FindUnknown(msg, field_number); if (result.status != kUpb_FindUnknown_Ok) { - UPB_ASSERT(result.status != kUpb_GetExtension_ParseError); return kUpb_GetExtension_NotPresent; } // Decode and promote from unknown. @@ -197,7 +196,7 @@ upb_GetExtension_Status upb_MiniTable_GetOrPromoteExtension( } const char* data = result.ptr; uint32_t tag; - uint64_t message_len; + uint64_t message_len = 0; data = decode_tag(data, &tag); data = decode_varint64(data, &message_len); upb_DecodeStatus status = @@ -245,7 +244,6 @@ upb_GetExtensionAsBytes_Status upb_MiniTable_GetExtensionAsBytes( int field_number = ext_table->field.number; upb_FindUnknownRet result = upb_MiniTable_FindUnknown(msg, field_number); if (result.status != kUpb_FindUnknown_Ok) { - UPB_ASSERT(result.status != kUpb_GetExtension_ParseError); return kUpb_GetExtensionAsBytes_NotPresent; } const char* data = result.ptr; @@ -328,7 +326,7 @@ upb_FindUnknownRet upb_MiniTable_FindUnknown(const upb_Message* msg, uint64_t uint64_val; while (ptr < end) { - uint32_t tag; + uint32_t tag = 0; int field; int wire_type; const char* unknown_begin = ptr; diff --git a/upb/mini_table_accessors_test.cc b/upb/mini_table_accessors_test.cc index 7f66a94ba7..3b57c7a8fa 100644 --- a/upb/mini_table_accessors_test.cc +++ b/upb/mini_table_accessors_test.cc @@ -446,10 +446,9 @@ TEST(GeneratedCode, Extensions) { // Get unknown extension bytes before promotion. const char* extension_data; size_t len; - upb_GetExtensionAsBytes_Status status = status = - upb_MiniTable_GetExtensionAsBytes(base_msg, - &upb_test_ModelExtension2_model_ext_ext, - 0, arena, &extension_data, &len); + upb_GetExtensionAsBytes_Status status = upb_MiniTable_GetExtensionAsBytes( + base_msg, &upb_test_ModelExtension2_model_ext_ext, 0, arena, + &extension_data, &len); EXPECT_EQ(kUpb_GetExtensionAsBytes_Ok, status); EXPECT_EQ(0x48, extension_data[0]); EXPECT_EQ(5, extension_data[1]); diff --git a/upb/reflection.h b/upb/reflection.h index 1fea8c6972..7b751378fa 100644 --- a/upb/reflection.h +++ b/upb/reflection.h @@ -25,87 +25,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// This header is deprecated, use upb/reflection/message.h instead + #ifndef UPB_REFLECTION_H_ #define UPB_REFLECTION_H_ -#include "upb/def.h" -#include "upb/message_value.h" -#include "upb/msg.h" -#include "upb/upb.h" - -// Must be last. -#include "upb/port_def.inc" - -#ifdef __cplusplus -extern "C" { -#endif - -upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); - -/** upb_Message - * *******************************************************************/ - -/* Creates a new message of the given type in the given arena. */ -upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a); - -/* Returns the value associated with this field. */ -upb_MessageValue upb_Message_Get(const upb_Message* msg, const upb_FieldDef* f); - -/* Returns a mutable pointer to a map, array, or submessage value. If the given - * arena is non-NULL this will construct a new object if it was not previously - * present. May not be called for primitive fields. */ -upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, - const upb_FieldDef* f, - upb_Arena* a); - -/* May only be called for fields where upb_FieldDef_HasPresence(f) == true. */ -bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f); - -/* Returns the field that is set in the oneof, or NULL if none are set. */ -const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, - const upb_OneofDef* o); - -/* Sets the given field to the given value. For a msg/array/map/string, the - * caller must ensure that the target data outlives |msg| (by living either in - * the same arena or a different arena that outlives it). - * - * Returns false if allocation fails. */ -bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, - upb_MessageValue val, upb_Arena* a); - -/* Clears any field presence and sets the value back to its default. */ -void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f); - -/* Clear all data and unknown fields. */ -void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m); - -/* Iterate over present fields. - * - * size_t iter = kUpb_Message_Begin; - * const upb_FieldDef *f; - * upb_MessageValue val; - * while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) { - * process_field(f, val); - * } - * - * If ext_pool is NULL, no extensions will be returned. If the given symtab - * returns extensions that don't match what is in this message, those extensions - * will be skipped. - */ - -#define kUpb_Message_Begin -1 -bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, const upb_FieldDef** f, - upb_MessageValue* val, size_t* iter); - -/* Clears all unknown field data from this message and all submessages. */ -bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int maxdepth); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#include "upb/port_undef.inc" +#include "upb/reflection/message.h" #endif /* UPB_REFLECTION_H_ */ diff --git a/upb/reflection.hpp b/upb/reflection.hpp index b653893c0d..a2443fb6d4 100644 --- a/upb/reflection.hpp +++ b/upb/reflection.hpp @@ -23,15 +23,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// This header is deprecated, use upb/reflection/message.hpp instead + #ifndef UPB_REFLECTION_HPP_ #define UPB_REFLECTION_HPP_ -#include "upb/reflection.h" - -namespace upb { - -typedef upb_MessageValue MessageValue; - -} // namespace upb +#include "upb/reflection/message.hpp" #endif // UPB_REFLECTION_HPP_ diff --git a/upb/reflection/common.h b/upb/reflection/common.h new file mode 100644 index 0000000000..04b98a620e --- /dev/null +++ b/upb/reflection/common.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +// Declarations common to all public def types. + +#ifndef UPB_REFLECTION_COMMON_H_ +#define UPB_REFLECTION_COMMON_H_ + +#include "google/protobuf/descriptor.upb.h" + +typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; + +// Forward declarations for circular references. +typedef struct upb_DefPool upb_DefPool; +typedef struct upb_EnumDef upb_EnumDef; +typedef struct upb_EnumValueDef upb_EnumValueDef; +typedef struct upb_ExtensionRange upb_ExtensionRange; +typedef struct upb_FieldDef upb_FieldDef; +typedef struct upb_FileDef upb_FileDef; +typedef struct upb_MessageDef upb_MessageDef; +typedef struct upb_MethodDef upb_MethodDef; +typedef struct upb_OneofDef upb_OneofDef; +typedef struct upb_ServiceDef upb_ServiceDef; + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +typedef struct upb_DefBuilder upb_DefBuilder; + +#endif /* UPB_REFLECTION_COMMON_H_ */ diff --git a/upb/mini_descriptor.c b/upb/reflection/def.h similarity index 71% rename from upb/mini_descriptor.c rename to upb/reflection/def.h index 321af1be5d..be04a9a596 100644 --- a/upb/mini_descriptor.c +++ b/upb/reflection/def.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2022, Google LLC + * Copyright (c) 2009-2021, Google LLC * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,21 +25,18 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "upb/internal/mini_descriptor.h" +#ifndef UPB_REFLECTION_DEF_H_ +#define UPB_REFLECTION_DEF_H_ -// Must be last. -#include "upb/port_def.inc" +#include "upb/reflection/def_pool.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/enum_value_def.h" +#include "upb/reflection/extension_range.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/file_def.h" +#include "upb/reflection/message_def.h" +#include "upb/reflection/method_def.h" +#include "upb/reflection/oneof_def.h" +#include "upb/reflection/service_def.h" -const char* upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e, upb_Arena* a) { - return _upb_EnumDef_MiniDescriptor(e, a); -} - -const char* upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, - upb_Arena* a) { - return _upb_MiniDescriptor_EncodeField(f, a); -} - -const char* upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, - upb_Arena* a) { - return _upb_MiniDescriptor_EncodeMessage(m, a); -} +#endif /* UPB_REFLECTION_DEF_H_ */ diff --git a/upb/reflection/def.hpp b/upb/reflection/def.hpp new file mode 100644 index 0000000000..55dd3b9a85 --- /dev/null +++ b/upb/reflection/def.hpp @@ -0,0 +1,441 @@ +// Copyright (c) 2009-2021, Google LLC +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Google LLC nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef UPB_REFLECTION_DEF_HPP_ +#define UPB_REFLECTION_DEF_HPP_ + +#include +#include +#include +#include + +#include "upb/reflection/def.h" +#include "upb/reflection/message.h" +#include "upb/upb.hpp" + +namespace upb { + +typedef upb_MessageValue MessageValue; + +class EnumDefPtr; +class FileDefPtr; +class MessageDefPtr; +class OneofDefPtr; + +// A upb::FieldDefPtr describes a single field in a message. It is most often +// found as a part of a upb_MessageDef, but can also stand alone to represent +// an extension. +class FieldDefPtr { + public: + FieldDefPtr() : ptr_(nullptr) {} + explicit FieldDefPtr(const upb_FieldDef* ptr) : ptr_(ptr) {} + + const upb_FieldDef* ptr() const { return ptr_; } + explicit operator bool() const { return ptr_ != nullptr; } + + typedef upb_CType Type; + typedef upb_Label Label; + typedef upb_FieldType DescriptorType; + + const char* full_name() const { return upb_FieldDef_FullName(ptr_); } + + Type type() const { return upb_FieldDef_CType(ptr_); } + Label label() const { return upb_FieldDef_Label(ptr_); } + const char* name() const { return upb_FieldDef_Name(ptr_); } + const char* json_name() const { return upb_FieldDef_JsonName(ptr_); } + uint32_t number() const { return upb_FieldDef_Number(ptr_); } + bool is_extension() const { return upb_FieldDef_IsExtension(ptr_); } + + // For non-string, non-submessage fields, this indicates whether binary + // protobufs are encoded in packed or non-packed format. + // + // Note: this accessor reflects the fact that "packed" has different defaults + // depending on whether the proto is proto2 or proto3. + bool packed() const { return upb_FieldDef_IsPacked(ptr_); } + + // An integer that can be used as an index into an array of fields for + // whatever message this field belongs to. Guaranteed to be less than + // f->containing_type()->field_count(). May only be accessed once the def has + // been finalized. + uint32_t index() const { return upb_FieldDef_Index(ptr_); } + + // The MessageDef to which this field belongs. + // + // If this field has been added to a MessageDef, that message can be retrieved + // directly (this is always the case for frozen FieldDefs). + // + // If the field has not yet been added to a MessageDef, you can set the name + // of the containing type symbolically instead. This is mostly useful for + // extensions, where the extension is declared separately from the message. + MessageDefPtr containing_type() const; + + // The OneofDef to which this field belongs, or NULL if this field is not part + // of a oneof. + OneofDefPtr containing_oneof() const; + + // The field's type according to the enum in descriptor.proto. This is not + // the same as UPB_TYPE_*, because it distinguishes between (for example) + // INT32 and SINT32, whereas our "type" enum does not. This return of + // descriptor_type() is a function of type(), integer_format(), and + // is_tag_delimited(). + DescriptorType descriptor_type() const { return upb_FieldDef_Type(ptr_); } + + // Convenient field type tests. + bool IsSubMessage() const { return upb_FieldDef_IsSubMessage(ptr_); } + bool IsString() const { return upb_FieldDef_IsString(ptr_); } + bool IsSequence() const { return upb_FieldDef_IsRepeated(ptr_); } + bool IsPrimitive() const { return upb_FieldDef_IsPrimitive(ptr_); } + bool IsMap() const { return upb_FieldDef_IsMap(ptr_); } + + MessageValue default_value() const { return upb_FieldDef_Default(ptr_); } + + // Returns the enum or submessage def for this field, if any. The field's + // type must match (ie. you may only call enum_subdef() for fields where + // type() == kUpb_CType_Enum). + EnumDefPtr enum_subdef() const; + MessageDefPtr message_subdef() const; + + private: + const upb_FieldDef* ptr_; +}; + +// Class that represents a oneof. +class OneofDefPtr { + public: + OneofDefPtr() : ptr_(nullptr) {} + explicit OneofDefPtr(const upb_OneofDef* ptr) : ptr_(ptr) {} + + const upb_OneofDef* ptr() const { return ptr_; } + explicit operator bool() const { return ptr_ != nullptr; } + + // Returns the MessageDef that contains this OneofDef. + MessageDefPtr containing_type() const; + + // Returns the name of this oneof. + const char* name() const { return upb_OneofDef_Name(ptr_); } + + // Returns the number of fields in the oneof. + int field_count() const { return upb_OneofDef_FieldCount(ptr_); } + FieldDefPtr field(int i) const { + return FieldDefPtr(upb_OneofDef_Field(ptr_, i)); + } + + // Looks up by name. + FieldDefPtr FindFieldByName(const char* name, size_t len) const { + return FieldDefPtr(upb_OneofDef_LookupNameWithSize(ptr_, name, len)); + } + FieldDefPtr FindFieldByName(const char* name) const { + return FieldDefPtr(upb_OneofDef_LookupName(ptr_, name)); + } + + template + FieldDefPtr FindFieldByName(const T& str) const { + return FindFieldByName(str.c_str(), str.size()); + } + + // Looks up by tag number. + FieldDefPtr FindFieldByNumber(uint32_t num) const { + return FieldDefPtr(upb_OneofDef_LookupNumber(ptr_, num)); + } + + private: + const upb_OneofDef* ptr_; +}; + +// Structure that describes a single .proto message type. +class MessageDefPtr { + public: + MessageDefPtr() : ptr_(nullptr) {} + explicit MessageDefPtr(const upb_MessageDef* ptr) : ptr_(ptr) {} + + const upb_MessageDef* ptr() const { return ptr_; } + explicit operator bool() const { return ptr_ != nullptr; } + + FileDefPtr file() const; + + const char* full_name() const { return upb_MessageDef_FullName(ptr_); } + const char* name() const { return upb_MessageDef_Name(ptr_); } + + // The number of fields that belong to the MessageDef. + int field_count() const { return upb_MessageDef_FieldCount(ptr_); } + FieldDefPtr field(int i) const { + return FieldDefPtr(upb_MessageDef_Field(ptr_, i)); + } + + // The number of oneofs that belong to the MessageDef. + int oneof_count() const { return upb_MessageDef_OneofCount(ptr_); } + OneofDefPtr oneof(int i) const { + return OneofDefPtr(upb_MessageDef_Oneof(ptr_, i)); + } + + upb_Syntax syntax() const { return upb_MessageDef_Syntax(ptr_); } + + // These return null pointers if the field is not found. + FieldDefPtr FindFieldByNumber(uint32_t number) const { + return FieldDefPtr(upb_MessageDef_FindFieldByNumber(ptr_, number)); + } + FieldDefPtr FindFieldByName(const char* name, size_t len) const { + return FieldDefPtr(upb_MessageDef_FindFieldByNameWithSize(ptr_, name, len)); + } + FieldDefPtr FindFieldByName(const char* name) const { + return FieldDefPtr(upb_MessageDef_FindFieldByName(ptr_, name)); + } + + template + FieldDefPtr FindFieldByName(const T& str) const { + return FindFieldByName(str.c_str(), str.size()); + } + + OneofDefPtr FindOneofByName(const char* name, size_t len) const { + return OneofDefPtr(upb_MessageDef_FindOneofByNameWithSize(ptr_, name, len)); + } + + OneofDefPtr FindOneofByName(const char* name) const { + return OneofDefPtr(upb_MessageDef_FindOneofByName(ptr_, name)); + } + + template + OneofDefPtr FindOneofByName(const T& str) const { + return FindOneofByName(str.c_str(), str.size()); + } + + // Is this message a map entry? + bool mapentry() const { return upb_MessageDef_IsMapEntry(ptr_); } + + // Return the type of well known type message. kUpb_WellKnown_Unspecified for + // non-well-known message. + upb_WellKnown wellknowntype() const { + return upb_MessageDef_WellKnownType(ptr_); + } + + private: + class FieldIter { + public: + explicit FieldIter(const upb_MessageDef* m, int i) : m_(m), i_(i) {} + void operator++() { i_++; } + + FieldDefPtr operator*() { + return FieldDefPtr(upb_MessageDef_Field(m_, i_)); + } + bool operator!=(const FieldIter& other) { return i_ != other.i_; } + bool operator==(const FieldIter& other) { return i_ == other.i_; } + + private: + const upb_MessageDef* m_; + int i_; + }; + + class FieldAccessor { + public: + explicit FieldAccessor(const upb_MessageDef* md) : md_(md) {} + FieldIter begin() { return FieldIter(md_, 0); } + FieldIter end() { return FieldIter(md_, upb_MessageDef_FieldCount(md_)); } + + private: + const upb_MessageDef* md_; + }; + + class OneofIter { + public: + explicit OneofIter(const upb_MessageDef* m, int i) : m_(m), i_(i) {} + void operator++() { i_++; } + + OneofDefPtr operator*() { + return OneofDefPtr(upb_MessageDef_Oneof(m_, i_)); + } + bool operator!=(const OneofIter& other) { return i_ != other.i_; } + bool operator==(const OneofIter& other) { return i_ == other.i_; } + + private: + const upb_MessageDef* m_; + int i_; + }; + + class OneofAccessor { + public: + explicit OneofAccessor(const upb_MessageDef* md) : md_(md) {} + OneofIter begin() { return OneofIter(md_, 0); } + OneofIter end() { return OneofIter(md_, upb_MessageDef_OneofCount(md_)); } + + private: + const upb_MessageDef* md_; + }; + + public: + FieldAccessor fields() const { return FieldAccessor(ptr()); } + OneofAccessor oneofs() const { return OneofAccessor(ptr()); } + + private: + const upb_MessageDef* ptr_; +}; + +class EnumValDefPtr { + public: + EnumValDefPtr() : ptr_(nullptr) {} + explicit EnumValDefPtr(const upb_EnumValueDef* ptr) : ptr_(ptr) {} + + int32_t number() const { return upb_EnumValueDef_Number(ptr_); } + const char* full_name() const { return upb_EnumValueDef_FullName(ptr_); } + const char* name() const { return upb_EnumValueDef_Name(ptr_); } + + private: + const upb_EnumValueDef* ptr_; +}; + +class EnumDefPtr { + public: + EnumDefPtr() : ptr_(nullptr) {} + explicit EnumDefPtr(const upb_EnumDef* ptr) : ptr_(ptr) {} + + const upb_EnumDef* ptr() const { return ptr_; } + explicit operator bool() const { return ptr_ != nullptr; } + + const char* full_name() const { return upb_EnumDef_FullName(ptr_); } + const char* name() const { return upb_EnumDef_Name(ptr_); } + + // The value that is used as the default when no field default is specified. + // If not set explicitly, the first value that was added will be used. + // The default value must be a member of the enum. + // Requires that value_count() > 0. + int32_t default_value() const { return upb_EnumDef_Default(ptr_); } + + // Returns the number of values currently defined in the enum. Note that + // multiple names can refer to the same number, so this may be greater than + // the total number of unique numbers. + int value_count() const { return upb_EnumDef_ValueCount(ptr_); } + + // Lookups from name to integer, returning true if found. + EnumValDefPtr FindValueByName(const char* name) const { + return EnumValDefPtr(upb_EnumDef_FindValueByName(ptr_, name)); + } + + // Finds the name corresponding to the given number, or NULL if none was + // found. If more than one name corresponds to this number, returns the + // first one that was added. + EnumValDefPtr FindValueByNumber(int32_t num) const { + return EnumValDefPtr(upb_EnumDef_FindValueByNumber(ptr_, num)); + } + + private: + const upb_EnumDef* ptr_; +}; + +// Class that represents a .proto file with some things defined in it. +// +// Many users won't care about FileDefs, but they are necessary if you want to +// read the values of file-level options. +class FileDefPtr { + public: + explicit FileDefPtr(const upb_FileDef* ptr) : ptr_(ptr) {} + + const upb_FileDef* ptr() const { return ptr_; } + explicit operator bool() const { return ptr_ != nullptr; } + + // Get/set name of the file (eg. "foo/bar.proto"). + const char* name() const { return upb_FileDef_Name(ptr_); } + + // Package name for definitions inside the file (eg. "foo.bar"). + const char* package() const { return upb_FileDef_Package(ptr_); } + + // Syntax for the file. Defaults to proto2. + upb_Syntax syntax() const { return upb_FileDef_Syntax(ptr_); } + + // Get the list of dependencies from the file. These are returned in the + // order that they were added to the FileDefPtr. + int dependency_count() const { return upb_FileDef_DependencyCount(ptr_); } + const FileDefPtr dependency(int index) const { + return FileDefPtr(upb_FileDef_Dependency(ptr_, index)); + } + + private: + const upb_FileDef* ptr_; +}; + +// Non-const methods in upb::DefPool are NOT thread-safe. +class DefPool { + public: + DefPool() : ptr_(upb_DefPool_New(), upb_DefPool_Free) {} + explicit DefPool(upb_DefPool* s) : ptr_(s, upb_DefPool_Free) {} + + const upb_DefPool* ptr() const { return ptr_.get(); } + upb_DefPool* ptr() { return ptr_.get(); } + + // Finds an entry in the symbol table with this exact name. If not found, + // returns NULL. + MessageDefPtr FindMessageByName(const char* sym) const { + return MessageDefPtr(upb_DefPool_FindMessageByName(ptr_.get(), sym)); + } + + EnumDefPtr FindEnumByName(const char* sym) const { + return EnumDefPtr(upb_DefPool_FindEnumByName(ptr_.get(), sym)); + } + + FileDefPtr FindFileByName(const char* name) const { + return FileDefPtr(upb_DefPool_FindFileByName(ptr_.get(), name)); + } + + // TODO: iteration? + + // Adds the given serialized FileDescriptorProto to the pool. + FileDefPtr AddFile(const google_protobuf_FileDescriptorProto* file_proto, + Status* status) { + return FileDefPtr( + upb_DefPool_AddFile(ptr_.get(), file_proto, status->ptr())); + } + + private: + std::unique_ptr ptr_; +}; + +// TODO(b/236632406): This typedef is deprecated. Delete it. +using SymbolTable = DefPool; + +inline FileDefPtr MessageDefPtr::file() const { + return FileDefPtr(upb_MessageDef_File(ptr_)); +} + +inline MessageDefPtr FieldDefPtr::message_subdef() const { + return MessageDefPtr(upb_FieldDef_MessageSubDef(ptr_)); +} + +inline MessageDefPtr FieldDefPtr::containing_type() const { + return MessageDefPtr(upb_FieldDef_ContainingType(ptr_)); +} + +inline MessageDefPtr OneofDefPtr::containing_type() const { + return MessageDefPtr(upb_OneofDef_ContainingType(ptr_)); +} + +inline OneofDefPtr FieldDefPtr::containing_oneof() const { + return OneofDefPtr(upb_FieldDef_ContainingOneof(ptr_)); +} + +inline EnumDefPtr FieldDefPtr::enum_subdef() const { + return EnumDefPtr(upb_FieldDef_EnumSubDef(ptr_)); +} + +} // namespace upb + +#endif // UPB_REFLECTION_DEF_HPP_ diff --git a/upb/reflection/def_builder.c b/upb/reflection/def_builder.c new file mode 100644 index 0000000000..8ca6404778 --- /dev/null +++ b/upb/reflection/def_builder.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/def_builder.h" + +#include + +#include "upb/reflection/def_pool.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/field_def.h" + +// Must be last. +#include "upb/port_def.inc" + +/* The upb core does not generally have a concept of default instances. However + * for descriptor options we make an exception since the max size is known and + * modest (<200 bytes). All types can share a default instance since it is + * initialized to zeroes. + * + * We have to allocate an extra pointer for upb's internal metadata. */ +static const char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; +const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; + +const char* _upb_DefBuilder_FullToShort(const char* fullname) { + const char* p; + + if (fullname == NULL) { + return NULL; + } else if ((p = strrchr(fullname, '.')) == NULL) { + /* No '.' in the name, return the full string. */ + return fullname; + } else { + /* Return one past the last '.'. */ + return p + 1; + } +} + +void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(ctx->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(ctx->err, 1); +} + +void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) { + upb_Status_SetErrorMessage(ctx->status, "out of memory"); + UPB_LONGJMP(ctx->err, 1); +} + +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name) { + if (prefix) { + // ret = prefix + '.' + name; + size_t n = strlen(prefix); + char* ret = _upb_DefBuilder_Alloc(ctx, n + name.size + 2); + strcpy(ret, prefix); + ret[n] = '.'; + memcpy(&ret[n + 1], name.data, name.size); + ret[n + 1 + name.size] = '\0'; + return ret; + } else { + char* ret = upb_strdup2(name.data, name.size, ctx->arena); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; + } +} + +static bool remove_component(char* base, size_t* len) { + if (*len == 0) return false; + + for (size_t i = *len - 1; i > 0; i--) { + if (base[i] == '.') { + *len = i; + return true; + } + } + + *len = 0; + return true; +} + +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type) { + if (sym.size == 0) goto notfound; + upb_value v; + if (sym.data[0] == '.') { + /* Symbols starting with '.' are absolute, so we do a single lookup. + * Slice to omit the leading '.' */ + if (!_upb_DefPool_LookupAny2(ctx->symtab, sym.data + 1, sym.size - 1, &v)) { + goto notfound; + } + } else { + /* Remove components from base until we find an entry or run out. */ + size_t baselen = base ? strlen(base) : 0; + char* tmp = malloc(sym.size + baselen + 1); + while (1) { + char* p = tmp; + if (baselen) { + memcpy(p, base, baselen); + p[baselen] = '.'; + p += baselen + 1; + } + memcpy(p, sym.data, sym.size); + p += sym.size; + if (_upb_DefPool_LookupAny2(ctx->symtab, tmp, p - tmp, &v)) { + break; + } + if (!remove_component(tmp, &baselen)) { + free(tmp); + goto notfound; + } + } + free(tmp); + } + + *type = _upb_DefType_Type(v); + return _upb_DefType_Unpack(v, *type); + +notfound: + _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(sym)); +} + +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type) { + upb_deftype_t found_type; + const void* ret = + _upb_DefBuilder_ResolveAny(ctx, from_name_dbg, base, sym, &found_type); + if (ret && found_type != type) { + _upb_DefBuilder_Errf(ctx, + "type mismatch when resolving %s: couldn't find " + "name " UPB_STRINGVIEW_FORMAT " with type=%d", + from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); + } + return ret; +} + +// Per ASCII this will lower-case a letter. If the result is a letter, the +// input was definitely a letter. If the output is not a letter, this may +// have transformed the character unpredictably. +static char upb_ascii_lower(char ch) { return ch | 0x20; } + +// isalpha() etc. from are locale-dependent, which we don't want. +static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { + return low <= c && c <= high; +} + +static bool upb_isletter(char c) { + char lower = upb_ascii_lower(c); + return upb_isbetween(lower, 'a', 'z') || c == '_'; +} + +static bool upb_isalphanum(char c) { + return upb_isletter(c) || upb_isbetween(c, '0', '9'); +} + +static bool TryGetChar(const char** src, const char* end, char* ch) { + if (*src == end) return false; + *ch = **src; + *src += 1; + return true; +} + +static char TryGetHexDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '9') { + return ch - '0'; + } + ch = upb_ascii_lower(ch); + if ('a' <= ch && ch <= 'f') { + return ch - 'a' + 0xa; + } + *src -= 1; // Char wasn't actually a hex digit. + return -1; +} + +static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char hex_digit = TryGetHexDigit(src, end); + if (hex_digit < 0) { + _upb_DefBuilder_Errf( + ctx, "\\x cannot be followed by non-hex digit in field '%s' default", + upb_FieldDef_FullName(f)); + return 0; + } + unsigned int ret = hex_digit; + while ((hex_digit = TryGetHexDigit(src, end)) >= 0) { + ret = (ret << 4) | hex_digit; + } + if (ret > 0xff) { + _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", + upb_FieldDef_FullName(f)); + return 0; + } + return ret; +} + +static char TryGetOctalDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '7') { + return ch - '0'; + } + *src -= 1; // Char wasn't actually an octal digit. + return -1; +} + +static char upb_DefBuilder_ParseOctalEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char ch = 0; + for (int i = 0; i < 3; i++) { + char digit; + if ((digit = TryGetOctalDigit(src, end)) >= 0) { + ch = (ch << 3) | digit; + } + } + return ch; +} + +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) { + _upb_DefBuilder_Errf(ctx, "unterminated escape sequence in field %s", + upb_FieldDef_FullName(f)); + return 0; + } + switch (ch) { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '\"': + return '\"'; + case '?': + return '\?'; + case 'x': + case 'X': + return upb_DefBuilder_ParseHexEscape(ctx, f, src, end); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + *src -= 1; + return upb_DefBuilder_ParseOctalEscape(ctx, f, src, end); + } + _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); +} + +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full) { + const char* str = name.data; + const size_t len = name.size; + bool start = true; + for (size_t i = 0; i < len; i++) { + const char c = str[i]; + if (c == '.') { + if (start || !full) { + _upb_DefBuilder_Errf( + ctx, "invalid name: unexpected '.' (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + _upb_DefBuilder_Errf(ctx, + "invalid name: path components must start with a " + "letter (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = false; + } else if (!upb_isalphanum(c)) { + _upb_DefBuilder_Errf( + ctx, + "invalid name: non-alphanumeric character (" UPB_STRINGVIEW_FORMAT + ")", + UPB_STRINGVIEW_ARGS(name)); + } + } + if (start) { + _upb_DefBuilder_Errf(ctx, + "invalid name: empty part (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + + // We should never reach this point. + UPB_ASSERT(false); +} diff --git a/upb/reflection/def_builder.h b/upb/reflection/def_builder.h new file mode 100644 index 0000000000..4b7358c77a --- /dev/null +++ b/upb/reflection/def_builder.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_REFLECTION_DEF_BUILDER_H_ +#define UPB_REFLECTION_DEF_BUILDER_H_ + +#include "upb/reflection/common.h" +#include "upb/reflection/def_pool.h" +#include "upb/reflection/def_type.h" + +// Must be last. +#include "upb/port_def.inc" + +// We want to copy the options verbatim into the destination options proto. +// We use serialize+parse as our deep copy. +#define UBP_DEF_SET_OPTIONS(target, desc_type, options_type, proto) \ + if (google_protobuf_##desc_type##_has_options(proto)) { \ + size_t size; \ + char* pb = google_protobuf_##options_type##_serialize( \ + google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ + if (!pb) _upb_DefBuilder_OomErr(ctx); \ + target = \ + google_protobuf_##options_type##_parse(pb, size, _upb_DefBuilder_Arena(ctx)); \ + if (!target) _upb_DefBuilder_OomErr(ctx); \ + } else { \ + target = (const google_protobuf_##options_type*)kUpbDefOptDefault; \ + } + +#ifdef __cplusplus +extern "C" { +#endif + +struct upb_DefBuilder { + upb_DefPool* symtab; + upb_FileDef* file; // File we are building. + upb_Arena* arena; // Allocate defs here. + upb_Arena* tmp_arena; // For temporary allocations. + upb_Status* status; // Record errors here. + const upb_MiniTable_File* layout; // NULL if we should build layouts. + int enum_count; // Count of enums built so far. + int msg_count; // Count of messages built so far. + int ext_count; // Count of extensions built so far. + jmp_buf err; // longjmp() on error. +}; + +extern const char* kUpbDefOptDefault; + +UPB_NORETURN void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, + ...) UPB_PRINTF(2, 3); +UPB_NORETURN void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx); + +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name); + +// Given a symbol and the base symbol inside which it is defined, +// find the symbol's definition. +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type); + +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type); + +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end); + +const char* _upb_DefBuilder_FullToShort(const char* fullname); + +UPB_INLINE void* _upb_DefBuilder_Alloc(upb_DefBuilder* ctx, size_t bytes) { + if (bytes == 0) return NULL; + void* ret = upb_Arena_Malloc(ctx->arena, bytes); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; +} + +// Adds a symbol |v| to the symtab, which must be a def pointer previously +// packed with pack_def(). The def's pointer to upb_FileDef* must be set before +// adding, so we know which entries to remove if building this file fails. +UPB_INLINE void _upb_DefBuilder_Add(upb_DefBuilder* ctx, const char* name, + upb_value v) { + // TODO: table should support an operation "tryinsert" to avoid the double + // lookup. + if (_upb_DefPool_Contains(ctx->symtab, name)) { + _upb_DefBuilder_Errf(ctx, "duplicate symbol '%s'", name); + } + bool ok = _upb_DefPool_Insert(ctx->symtab, name, v); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +UPB_INLINE upb_Arena* _upb_DefBuilder_Arena(const upb_DefBuilder* ctx) { + return ctx->arena; +} + +UPB_INLINE upb_FileDef* _upb_DefBuilder_File(const upb_DefBuilder* ctx) { + return ctx->file; +} + +// This version of CheckIdent() is only called by other, faster versions after +// they detect a parsing error. +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full); + +// Verify a relative identifier string. The loop is branchless for speed. +UPB_INLINE void _upb_DefBuilder_CheckIdentNotFull(upb_DefBuilder* ctx, + upb_StringView name) { + bool good = name.size > 0; + + for (size_t i = 0; i < name.size; i++) { + const char c = name.data[i]; + const char d = c | 0x20; // force lowercase + const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); + const bool is_numer = ('0' <= c) & (c <= '9') & (i != 0); + + good &= is_alpha | is_numer; + } + + if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, false); +} + +// Verify a full identifier string. This is slightly more complicated than +// verifying a relative identifier string because we must track '.' chars. +UPB_INLINE void _upb_DefBuilder_CheckIdentFull(upb_DefBuilder* ctx, + upb_StringView name) { + bool good = name.size > 0; + bool start = true; + + for (size_t i = 0; i < name.size; i++) { + const char c = name.data[i]; + const char d = c | 0x20; // force lowercase + const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); + const bool is_numer = ('0' <= c) & (c <= '9') & !start; + const bool is_dot = (c == '.') & !start; + + good &= is_alpha | is_numer | is_dot; + start = is_dot; + } + + if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, true); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_DEF_BUILDER_H_ */ diff --git a/upb/reflection/def_builder_test.cc b/upb/reflection/def_builder_test.cc new file mode 100644 index 0000000000..113e574e33 --- /dev/null +++ b/upb/reflection/def_builder_test.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009-2022, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/def_builder.h" + +#include "gtest/gtest.h" +#include "upb/reflection/def.hpp" + +// Must be last. +#include "upb/port_def.inc" + +struct IdentTest { + const char* text; + bool ok; +}; + +static const std::vector FullIdentTests = { + {"foo.bar", true}, {"foo.", true}, {"foo", true}, + + {"foo.7bar", false}, {".foo", false}, {"#", false}, + {".", false}, {"", false}, +}; + +static const std::vector NotFullIdentTests = { + {"foo", true}, {"foo1", true}, + + {"foo.bar", false}, {"1foo", false}, {"#", false}, + {".", false}, {"", false}, +}; + +TEST(DefBuilder, TestIdents) { + upb_StringView sv; + upb_Status status; + upb_DefBuilder ctx; + ctx.status = &status; + upb_Status_Clear(&status); + + for (const auto& test : FullIdentTests) { + sv.data = test.text; + sv.size = strlen(test.text); + + if (UPB_SETJMP(ctx.err)) { + EXPECT_FALSE(test.ok); + } else { + _upb_DefBuilder_CheckIdentFull(&ctx, sv); + EXPECT_TRUE(test.ok); + } + } + + for (const auto& test : NotFullIdentTests) { + sv.data = test.text; + sv.size = strlen(test.text); + + if (UPB_SETJMP(ctx.err)) { + EXPECT_FALSE(test.ok); + } else { + _upb_DefBuilder_CheckIdentNotFull(&ctx, sv); + EXPECT_TRUE(test.ok); + } + } +} diff --git a/upb/reflection/def_pool.c b/upb/reflection/def_pool.c new file mode 100644 index 0000000000..7ab375ec60 --- /dev/null +++ b/upb/reflection/def_pool.c @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/def_pool.h" + +#include + +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/enum_value_def.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/file_def.h" +#include "upb/reflection/message_def.h" +#include "upb/reflection/service_def.h" + +// Must be last. +#include "upb/port_def.inc" + +struct upb_DefPool { + upb_Arena* arena; + upb_strtable syms; // full_name -> packed def ptr + upb_strtable files; // file_name -> (upb_FileDef*) + upb_inttable exts; // (upb_MiniTable_Extension*) -> (upb_FieldDef*) + upb_ExtensionRegistry* extreg; + size_t bytes_loaded; +}; + +void upb_DefPool_Free(upb_DefPool* s) { + upb_Arena_Free(s->arena); + upb_gfree(s); +} + +upb_DefPool* upb_DefPool_New(void) { + upb_DefPool* s = upb_gmalloc(sizeof(*s)); + if (!s) return NULL; + + s->arena = upb_Arena_New(); + s->bytes_loaded = 0; + + if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; + if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; + if (!upb_inttable_init(&s->exts, s->arena)) goto err; + + s->extreg = upb_ExtensionRegistry_New(s->arena); + if (!s->extreg) goto err; + + return s; + +err: + upb_Arena_Free(s->arena); + upb_gfree(s); + return NULL; +} + +bool _upb_DefPool_Contains(const upb_DefPool* s, const char* sym) { + return upb_strtable_lookup(&s->syms, sym, NULL); +} + +bool _upb_DefPool_Insert(upb_DefPool* s, const char* sym, upb_value v) { + return _upb_DefPool_Insert2(s, sym, strlen(sym), v); +} + +bool _upb_DefPool_Insert2(upb_DefPool* s, const char* sym, size_t size, + upb_value v) { + return upb_strtable_insert(&s->syms, sym, size, v, s->arena); +} + +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext, + upb_FieldDef* f, upb_Arena* a) { + return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), + a); +} + +static const void* _upb_DefPool_Lookup(const upb_DefPool* s, const char* sym, + upb_deftype_t type) { + return _upb_DefPool_Lookup2(s, sym, strlen(sym), type); +} + +const void* _upb_DefPool_Lookup2(const upb_DefPool* s, const char* sym, + size_t size, upb_deftype_t type) { + upb_value v; + return upb_strtable_lookup2(&s->syms, sym, size, &v) + ? _upb_DefType_Unpack(v, type) + : NULL; +} + +bool _upb_DefPool_LookupAny2(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v) { + return upb_strtable_lookup2(&s->syms, sym, size, v); +} + +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) { + return s->extreg; +} + +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Lookup(s, sym, UPB_DEFTYPE_MSG); +} + +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len) { + return _upb_DefPool_Lookup2(s, sym, len, UPB_DEFTYPE_MSG); +} + +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Lookup(s, sym, UPB_DEFTYPE_ENUM); +} + +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Lookup(s, sym, UPB_DEFTYPE_ENUMVAL); +} + +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name) { + upb_value v; + return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) + : NULL; +} + +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len) { + upb_value v; + return upb_strtable_lookup2(&s->files, name, len, &v) + ? upb_value_getconstptr(v) + : NULL; +} + +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + upb_value v; + if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; + + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_FIELD: + return _upb_DefType_Unpack(v, UPB_DEFTYPE_FIELD); + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return _upb_MessageDef_InMessageSet(m) + ? upb_MessageDef_NestedExtension(m, 0) + : NULL; + } + default: + break; + } + + return NULL; +} + +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); +} + +const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name) { + return _upb_DefPool_Lookup(s, name, UPB_DEFTYPE_SERVICE); +} + +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + return _upb_DefPool_Lookup2(s, name, size, UPB_DEFTYPE_SERVICE); +} + +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name) { + upb_value v; + // TODO(haberman): non-extension fields and oneofs. + if (upb_strtable_lookup(&s->syms, name, &v)) { + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_EXT: { + const upb_FieldDef* f = _upb_DefType_Unpack(v, UPB_DEFTYPE_EXT); + return upb_FieldDef_File(f); + } + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return upb_MessageDef_File(m); + } + case UPB_DEFTYPE_ENUM: { + const upb_EnumDef* e = _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUM); + return upb_EnumDef_File(e); + } + case UPB_DEFTYPE_ENUMVAL: { + const upb_EnumValueDef* ev = + _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUMVAL); + return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); + } + case UPB_DEFTYPE_SERVICE: { + const upb_ServiceDef* service = + _upb_DefType_Unpack(v, UPB_DEFTYPE_SERVICE); + return upb_ServiceDef_File(service); + } + default: + UPB_UNREACHABLE(); + } + } + + const char* last_dot = strrchr(name, '.'); + if (last_dot) { + const upb_MessageDef* parent = + upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); + if (parent) { + const char* shortname = last_dot + 1; + if (upb_MessageDef_FindByNameWithSize(parent, shortname, + strlen(shortname), NULL, NULL)) { + return upb_MessageDef_File(parent); + } + } + } + + return NULL; +} + +static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { + intptr_t iter = UPB_INTTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { + const upb_FileDef* f; + switch (_upb_DefType_Type(val)) { + case UPB_DEFTYPE_EXT: + f = upb_FieldDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_EXT)); + break; + case UPB_DEFTYPE_MSG: + f = upb_MessageDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_MSG)); + break; + case UPB_DEFTYPE_ENUM: + f = upb_EnumDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_ENUM)); + break; + case UPB_DEFTYPE_ENUMVAL: + f = upb_EnumDef_File(upb_EnumValueDef_Enum( + _upb_DefType_Unpack(val, UPB_DEFTYPE_ENUMVAL))); + break; + case UPB_DEFTYPE_SERVICE: + f = upb_ServiceDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_SERVICE)); + break; + default: + UPB_UNREACHABLE(); + } + + if (f == file) upb_strtable_removeiter(&s->syms, &iter); + } +} + +static const upb_FileDef* _upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + const upb_MiniTable_File* layout, upb_Status* status) { + const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); + + // Determine whether we already know about this file. + { + upb_value v; + if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { + upb_Status_SetErrorFormat(status, + "duplicate file name " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + return NULL; + } + } + + upb_DefBuilder ctx = { + .symtab = s, + .layout = layout, + .msg_count = 0, + .enum_count = 0, + .ext_count = 0, + .status = status, + .file = NULL, + .arena = upb_Arena_New(), + .tmp_arena = upb_Arena_New(), + }; + + if (UPB_SETJMP(ctx.err)) { + UPB_ASSERT(!upb_Status_IsOk(status)); + if (ctx.file) { + remove_filedef(s, ctx.file); + ctx.file = NULL; + } + } else if (!ctx.arena || !ctx.tmp_arena) { + _upb_DefBuilder_OomErr(&ctx); + } else { + _upb_FileDef_Create(&ctx, file_proto); + upb_strtable_insert(&s->files, name.data, name.size, + upb_value_constptr(ctx.file), ctx.arena); + UPB_ASSERT(upb_Status_IsOk(status)); + upb_Arena_Fuse(s->arena, ctx.arena); + } + + if (ctx.arena) upb_Arena_Free(ctx.arena); + if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); + return ctx.file; +} + +const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + upb_Status* status) { + return _upb_DefPool_AddFile(s, file_proto, NULL, status); +} + +/* Include here since we want most of this file to be stdio-free. */ +#include + +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable) { + /* Since this function should never fail (it would indicate a bug in upb) we + * print errors to stderr instead of returning error status to the user. */ + _upb_DefPool_Init** deps = init->deps; + google_protobuf_FileDescriptorProto* file; + upb_Arena* arena; + upb_Status status; + + upb_Status_Clear(&status); + + if (upb_DefPool_FindFileByName(s, init->filename)) { + return true; + } + + arena = upb_Arena_New(); + + for (; *deps; deps++) { + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; + } + + file = google_protobuf_FileDescriptorProto_parse_ex( + init->descriptor.data, init->descriptor.size, NULL, + kUpb_DecodeOption_AliasString, arena); + s->bytes_loaded += init->descriptor.size; + + if (!file) { + upb_Status_SetErrorFormat( + &status, + "Failed to parse compiled-in descriptor for file '%s'. This should " + "never happen.", + init->filename); + goto err; + } + + const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { + goto err; + } + + upb_Arena_Free(arena); + return true; + +err: + fprintf(stderr, + "Error loading compiled-in descriptor for file '%s' (this should " + "never happen): %s\n", + init->filename, upb_Status_ErrorMessage(&status)); + upb_Arena_Free(arena); + return false; +} + +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { + return s->bytes_loaded; +} + +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } + +const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTable_Extension* ext) { + upb_value v; + bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); + UPB_ASSERT(ok); + return upb_value_getconstptr(v); +} + +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum) { + const upb_MiniTable* l = upb_MessageDef_MiniTable(m); + const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum); + return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +} + +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s) { + return s->extreg; +} + +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count) { + size_t n = 0; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + // This is O(all exts) instead of O(exts for m). If we need this to be + // efficient we may need to make extreg into a two-level table, or have a + // second per-message index. + while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) n++; + } + const upb_FieldDef** exts = malloc(n * sizeof(*exts)); + iter = UPB_INTTABLE_BEGIN; + size_t i = 0; + while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; + } + *count = n; + return exts; +} + +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { + return _upb_DefPool_LoadDefInitEx(s, init, false); +} diff --git a/upb/reflection/def_pool.h b/upb/reflection/def_pool.h new file mode 100644 index 0000000000..765053eaaa --- /dev/null +++ b/upb/reflection/def_pool.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_DEF_POOL_H_ +#define UPB_REFLECTION_DEF_POOL_H_ + +#include "upb/reflection/common.h" +#include "upb/reflection/def_type.h" +#include "upb/string_view.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +void upb_DefPool_Free(upb_DefPool* s); + +upb_DefPool* upb_DefPool_New(void); + +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym); + +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len); + +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym); + +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym); + +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name); + +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len); + +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size); + +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym); + +const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name); + +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size); + +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name); + +const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + upb_Status* status); + +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum); + +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s); + +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +// For generated code only: loads a generated descriptor. +typedef struct _upb_DefPool_Init { + struct _upb_DefPool_Init** deps; // Dependencies of this file. + const upb_MiniTable_File* layout; + const char* filename; + upb_StringView descriptor; // Serialized descriptor. +} _upb_DefPool_Init; + +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s); +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s); + +bool _upb_DefPool_Contains(const upb_DefPool* s, const char* sym); + +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s); + +bool _upb_DefPool_Insert(upb_DefPool* s, const char* sym, upb_value v); +bool _upb_DefPool_Insert2(upb_DefPool* s, const char* sym, size_t size, + upb_value v); + +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext, + upb_FieldDef* f, upb_Arena* a); + +const void* _upb_DefPool_Lookup2(const upb_DefPool* s, const char* sym, + size_t size, upb_deftype_t type); + +bool _upb_DefPool_LookupAny2(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v); + +const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTable_Extension* ext); + +// Should only be directly called by tests. This variant lets us suppress +// the use of compiled-in tables, forcing a rebuild of the tables at runtime. +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable); + +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_DEF_POOL_H_ */ diff --git a/upb/mini_descriptor.h b/upb/reflection/def_type.c similarity index 65% rename from upb/mini_descriptor.h rename to upb/reflection/def_type.c index 374794a011..033e7102f9 100644 --- a/upb/mini_descriptor.h +++ b/upb/reflection/def_type.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2022, Google LLC + * Copyright (c) 2009-2021, Google LLC * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,33 +25,26 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef UPB_MINI_DESCRIPTOR_H_ -#define UPB_MINI_DESCRIPTOR_H_ - -#include "upb/arena.h" -#include "upb/def.h" +#include "upb/reflection/def_type.h" // Must be last. #include "upb/port_def.inc" -#ifdef __cplusplus -extern "C" { -#endif - -// Creates and returns a mini descriptor string for an enum, or NULL on error. -const char* upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e, upb_Arena* a); - -// Creates and returns a mini descriptor string for a field, or NULL on error. -const char* upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, upb_Arena* a); - -// Creates and returns a mini descriptor string for a message, or NULL on error. -const char* upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, - upb_Arena* a); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#include "upb/port_undef.inc" - -#endif /* UPB_MINI_DESCRIPTOR_H_ */ +upb_deftype_t _upb_DefType_Type(upb_value v) { + const uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return num & UPB_DEFTYPE_MASK; +} + +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type) { + uintptr_t num = (uintptr_t)ptr; + UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); + num |= type; + return upb_value_constptr((const void*)num); +} + +const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type) { + uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return (num & UPB_DEFTYPE_MASK) == type + ? (const void*)(num & ~UPB_DEFTYPE_MASK) + : NULL; +} diff --git a/upb/reflection/def_type.h b/upb/reflection/def_type.h new file mode 100644 index 0000000000..31ce3e263c --- /dev/null +++ b/upb/reflection/def_type.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_REFLECTION_DEF_TYPE_H_ +#define UPB_REFLECTION_DEF_TYPE_H_ + +#include "upb/internal/table.h" + +// Must be last. +#include "upb/port_def.inc" + +// Inside a symtab we store tagged pointers to specific def types. +typedef enum { + UPB_DEFTYPE_MASK = 7, + + // Only inside symtab table. + UPB_DEFTYPE_EXT = 0, + UPB_DEFTYPE_MSG = 1, + UPB_DEFTYPE_ENUM = 2, + UPB_DEFTYPE_ENUMVAL = 3, + UPB_DEFTYPE_SERVICE = 4, + + // Only inside message table. + UPB_DEFTYPE_FIELD = 0, + UPB_DEFTYPE_ONEOF = 1, + UPB_DEFTYPE_FIELD_JSONNAME = 2, +} upb_deftype_t; + +#ifdef __cplusplus +extern "C" { +#endif + +// Our 3-bit pointer tagging requires all pointers to be multiples of 8. +// The arena will always yield 8-byte-aligned addresses, however we put +// the defs into arrays. For each element in the array to be 8-byte-aligned, +// the sizes of each def type must also be a multiple of 8. +// +// If any of these asserts fail, we need to add or remove padding on 32-bit +// machines (64-bit machines will have 8-byte alignment already due to +// pointers, which all of these structs have). +UPB_INLINE void _upb_DefType_CheckPadding(size_t size) { + UPB_ASSERT((size & UPB_DEFTYPE_MASK) == 0); +} + +upb_deftype_t _upb_DefType_Type(upb_value v); + +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type); + +const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_DEF_TYPE_H_ */ diff --git a/upb/reflection/enum_def.c b/upb/reflection/enum_def.c new file mode 100644 index 0000000000..0998d03c8f --- /dev/null +++ b/upb/reflection/enum_def.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/enum_def.h" + +#include + +#include "upb/mini_table.h" +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/enum_value_def.h" +#include "upb/reflection/file_def.h" +#include "upb/reflection/message_def.h" +#include "upb/reflection/mini_descriptor_encode.h" + +// Must be last. +#include "upb/port_def.inc" + +struct upb_EnumDef { + const google_protobuf_EnumOptions* opts; + const upb_MiniTable_Enum* layout; // Only for proto2. + const upb_FileDef* file; + const upb_MessageDef* containing_type; // Could be merged with "file". + const char* full_name; + upb_strtable ntoi; + upb_inttable iton; + const upb_EnumValueDef* values; + int value_count; + int32_t defaultval; + bool is_sorted; // Whether all of the values are defined in ascending order. +}; + +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { + return (upb_EnumDef*)&e[i]; +} + +// TODO: Maybe implement this on top of a ZCOS instead? +void _upb_EnumDef_Debug(const upb_EnumDef* e) { + fprintf(stderr, "enum %s (%p) {\n", e->full_name, e); + fprintf(stderr, " value_count: %d\n", e->value_count); + fprintf(stderr, " default: %d\n", e->defaultval); + fprintf(stderr, " is_sorted: %d\n", e->is_sorted); + fprintf(stderr, "}\n"); +} + +const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e) { + return e->layout; +} + +bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a) { + const char* name = upb_EnumValueDef_Name(v); + const upb_value val = upb_value_constptr(v); + bool ok = upb_strtable_insert(&e->ntoi, name, strlen(name), val, a); + if (!ok) return false; + + // Multiple enumerators can have the same number, first one wins. + const int number = upb_EnumValueDef_Number(v); + if (!upb_inttable_lookup(&e->iton, number, NULL)) { + return upb_inttable_insert(&e->iton, number, val, a); + } + return true; +} + +static int cmp_values(const void* a, const void* b) { + const uint32_t A = upb_EnumValueDef_Number(*(const upb_EnumValueDef**)a); + const uint32_t B = upb_EnumValueDef_Number(*(const upb_EnumValueDef**)b); + return (A < B) ? -1 : (A > B); +} + +const char* _upb_EnumDef_MiniDescriptor(const upb_EnumDef* e, upb_Arena* a) { + if (e->is_sorted) return _upb_MiniDescriptor_EncodeEnum(e, NULL, a); + + const upb_EnumValueDef** sorted = (const upb_EnumValueDef**)upb_Arena_Malloc( + a, e->value_count * sizeof(void*)); + if (!sorted) return NULL; + + for (size_t i = 0; i < e->value_count; i++) { + sorted[i] = upb_EnumDef_Value(e, i); + } + qsort(sorted, e->value_count, sizeof(void*), cmp_values); + + return _upb_MiniDescriptor_EncodeEnum(e, sorted, a); +} + +const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { + return e->opts; +} + +bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { + return e->opts != (void*)kUpbDefOptDefault; +} + +const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } + +const char* upb_EnumDef_Name(const upb_EnumDef* e) { + return _upb_DefBuilder_FullToShort(e->full_name); +} + +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } + +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { + return e->containing_type; +} + +int32_t upb_EnumDef_Default(const upb_EnumDef* e) { + UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); + return e->defaultval; +} + +int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } + +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name) { + return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); +} + +const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* e, const char* name, size_t size) { + upb_value v; + return upb_strtable_lookup2(&e->ntoi, name, size, &v) + ? upb_value_getconstptr(v) + : NULL; +} + +const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, + int32_t num) { + upb_value v; + return upb_inttable_lookup(&e->iton, num, &v) ? upb_value_getconstptr(v) + : NULL; +} + +bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { + // We could use upb_EnumDef_FindValueByNumber(e, num) != NULL, but we expect + // this to be faster (especially for small numbers). + return upb_MiniTable_Enum_CheckValue(e->layout, num); +} + +const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { + UPB_ASSERT(0 <= i && i < e->value_count); + return _upb_EnumValueDef_At(e->values, i); +} + +static upb_MiniTable_Enum* create_enumlayout(upb_DefBuilder* ctx, + const upb_EnumDef* e) { + const char* desc = _upb_EnumDef_MiniDescriptor(e, ctx->tmp_arena); + if (!desc) + _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); + + upb_Status status; + upb_MiniTable_Enum* layout = + upb_MiniTable_BuildEnum(desc, strlen(desc), ctx->arena, &status); + if (!layout) + _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); + return layout; +} + +static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumDescriptorProto* enum_proto, + upb_EnumDef* e) { + const google_protobuf_EnumValueDescriptorProto* const* values; + upb_StringView name; + size_t n; + + // Must happen before _upb_DefBuilder_Add() + e->file = _upb_DefBuilder_File(ctx); + + name = google_protobuf_EnumDescriptorProto_name(enum_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + + e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, e->full_name, + _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); + + values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); + + bool ok = upb_strtable_init(&e->ntoi, n, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_inttable_init(&e->iton, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + e->defaultval = 0; + e->value_count = n; + e->values = _upb_EnumValueDefs_New(ctx, prefix, n, values, e, &e->is_sorted); + + if (n == 0) { + _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", + e->full_name); + } + + UBP_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); + + upb_inttable_compact(&e->iton, ctx->arena); + + if (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2) { + if (ctx->layout) { + UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); + e->layout = ctx->layout->enums[ctx->enum_count++]; + } else { + e->layout = create_enumlayout(ctx, e); + } + } else { + e->layout = NULL; + } +} + +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto* const* protos, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); + + // If a containing type is defined then get the full name from that. + // Otherwise use the package name from the file def. + const char* name = containing_type ? upb_MessageDef_FullName(containing_type) + : _upb_FileDef_RawPackage(ctx->file); + + upb_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); + for (size_t i = 0; i < n; i++) { + create_enumdef(ctx, name, protos[i], &e[i]); + e[i].containing_type = containing_type; + } + return e; +} diff --git a/upb/reflection/enum_def.h b/upb/reflection/enum_def.h new file mode 100644 index 0000000000..0693453185 --- /dev/null +++ b/upb/reflection/enum_def.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_DEF_H_ +#define UPB_REFLECTION_ENUM_DEF_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num); +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e); +int32_t upb_EnumDef_Default(const upb_EnumDef* e); +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e); +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name); +const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* e, const char* name, size_t size); +const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, + int32_t num); +const char* upb_EnumDef_FullName(const upb_EnumDef* e); +bool upb_EnumDef_HasOptions(const upb_EnumDef* e); +const char* upb_EnumDef_Name(const upb_EnumDef* e); +const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e); +const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); +int upb_EnumDef_ValueCount(const upb_EnumDef* e); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i); +bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a); +const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); + +// Builds and returns a mini descriptor, or NULL if OOM. +const char* _upb_EnumDef_MiniDescriptor(const upb_EnumDef* e, upb_Arena* a); + +// Allocate and initialize an array of |n| enum defs. +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto* const* protos, + const upb_MessageDef* containing_type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_ENUM_DEF_H_ */ diff --git a/upb/reflection/enum_value_def.c b/upb/reflection/enum_value_def.c new file mode 100644 index 0000000000..ad7504a9f2 --- /dev/null +++ b/upb/reflection/enum_value_def.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/enum_value_def.h" + +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/file_def.h" + +// Must be last. +#include "upb/port_def.inc" + +struct upb_EnumValueDef { + const google_protobuf_EnumValueOptions* opts; + const upb_EnumDef* parent; + const char* full_name; + int32_t number; +}; + +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { + return (upb_EnumValueDef*)&v[i]; +} + +const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( + const upb_EnumValueDef* v) { + return v->opts; +} + +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) { + return v->opts != (void*)kUpbDefOptDefault; +} + +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) { + return v->parent; +} + +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) { + return v->full_name; +} + +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) { + return _upb_DefBuilder_FullToShort(v->full_name); +} + +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; } + +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { + // Compute index in our parent's array. + return v - upb_EnumDef_Value(v->parent, 0); +} + +static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumValueDescriptorProto* val_proto, + upb_EnumDef* e, upb_EnumValueDef* v) { + upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto); + + v->parent = e; // Must happen prior to _upb_DefBuilder_Add() + v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + v->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); + _upb_DefBuilder_Add(ctx, v->full_name, + _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); + + UBP_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, + val_proto); + + bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e, + bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); + + upb_EnumValueDef* v = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n); + + *is_sorted = true; + uint32_t previous = 0; + for (size_t i = 0; i < n; i++) { + create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); + + const uint32_t current = v[i].number; + if (previous > current) *is_sorted = false; + previous = current; + } + + if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && + v[0].number != 0) { + _upb_DefBuilder_Errf(ctx, + "for proto3, the first enum value must be zero (%s)", + upb_EnumDef_FullName(e)); + } + + return v; +} diff --git a/upb/reflection/enum_value_def.h b/upb/reflection/enum_value_def.h new file mode 100644 index 0000000000..31bd7b5f27 --- /dev/null +++ b/upb/reflection/enum_value_def.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_VALUE_DEF_H_ +#define UPB_REFLECTION_ENUM_VALUE_DEF_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v); +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v); +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v); +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v); +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v); +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v); +const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( + const upb_EnumValueDef* v); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i); + +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e, + bool* is_sorted); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_ENUM_VALUE_DEF_H_ */ diff --git a/upb/reflection/extension_range.c b/upb/reflection/extension_range.c new file mode 100644 index 0000000000..c48176a382 --- /dev/null +++ b/upb/reflection/extension_range.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/extension_range.h" + +#include "upb/reflection/def_builder.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/message_def.h" + +// Must be last. +#include "upb/port_def.inc" + +struct upb_ExtensionRange { + const google_protobuf_ExtensionRangeOptions* opts; + int32_t start; + int32_t end; +}; + +upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i) { + return (upb_ExtensionRange*)&r[i]; +} + +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r) { + return r->opts; +} + +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { + return r->opts != (void*)kUpbDefOptDefault; +} + +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r) { + return r->start; +} + +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } + +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ExtensionRange* const* protos, + const upb_MessageDef* m) { + upb_ExtensionRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); + + for (int i = 0; i < n; i++) { + const int32_t start = + google_protobuf_DescriptorProto_ExtensionRange_start(protos[i]); + const int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(protos[i]); + const int32_t max = + google_protobuf_MessageOptions_message_set_wire_format(upb_MessageDef_Options(m)) + ? INT32_MAX + : kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + _upb_DefBuilder_Errf(ctx, + "Extension range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } + + r[i].start = start; + r[i].end = end; + UBP_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, protos[i]); + } + + return r; +} diff --git a/upb/reflection/extension_range.h b/upb/reflection/extension_range.h new file mode 100644 index 0000000000..dd6ac1597d --- /dev/null +++ b/upb/reflection/extension_range.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_EXTENSION_RANGE_H_ +#define UPB_REFLECTION_EXTENSION_RANGE_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r); +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); + +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i); + +// Allocate and initialize an array of |n| extension ranges owned by |m|. +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ExtensionRange* const* protos, + const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_EXTENSION_RANGE_H_ */ diff --git a/upb/reflection/field_def.c b/upb/reflection/field_def.c new file mode 100644 index 0000000000..0ac1ce6e08 --- /dev/null +++ b/upb/reflection/field_def.c @@ -0,0 +1,1215 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/field_def.h" + +#include +#include + +#include "upb/mini_table.h" +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_pool.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/enum_value_def.h" +#include "upb/reflection/extension_range.h" +#include "upb/reflection/file_def.h" +#include "upb/reflection/message_def.h" +#include "upb/reflection/oneof_def.h" + +// Must be last. +#include "upb/port_def.inc" + +#define UPB_FIELD_TYPE_UNSPECIFIED 0 + +typedef struct { + size_t len; + char str[1]; // Null-terminated string data follows. +} str_t; + +struct upb_FieldDef { + const google_protobuf_FieldOptions* opts; + const upb_FileDef* file; + const upb_MessageDef* msgdef; + const char* full_name; + const char* json_name; + union { + int64_t sint; + uint64_t uint; + double dbl; + float flt; + bool boolean; + str_t* str; + } defaultval; + union { + const upb_OneofDef* oneof; + const upb_MessageDef* extension_scope; + } scope; + union { + const upb_MessageDef* msgdef; + const upb_EnumDef* enumdef; + const google_protobuf_FieldDescriptorProto* unresolved; + } sub; + uint32_t number_; + uint16_t index_; + uint16_t layout_index; /* Index into msgdef->layout->fields or file->exts */ + bool has_default; + bool is_extension_; + bool packed_; + bool proto3_optional_; + bool has_json_name_; + upb_FieldType type_; + upb_Label label_; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { + return (upb_FieldDef*)&f[i]; +} + +const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f) { + return f->opts; +} + +bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { + return f->opts != (void*)kUpbDefOptDefault; +} + +const char* upb_FieldDef_FullName(const upb_FieldDef* f) { + return f->full_name; +} + +upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { + switch (f->type_) { + case kUpb_FieldType_Double: + return kUpb_CType_Double; + case kUpb_FieldType_Float: + return kUpb_CType_Float; + case kUpb_FieldType_Int64: + case kUpb_FieldType_SInt64: + case kUpb_FieldType_SFixed64: + return kUpb_CType_Int64; + case kUpb_FieldType_Int32: + case kUpb_FieldType_SFixed32: + case kUpb_FieldType_SInt32: + return kUpb_CType_Int32; + case kUpb_FieldType_UInt64: + case kUpb_FieldType_Fixed64: + return kUpb_CType_UInt64; + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Fixed32: + return kUpb_CType_UInt32; + case kUpb_FieldType_Enum: + return kUpb_CType_Enum; + case kUpb_FieldType_Bool: + return kUpb_CType_Bool; + case kUpb_FieldType_String: + return kUpb_CType_String; + case kUpb_FieldType_Bytes: + return kUpb_CType_Bytes; + case kUpb_FieldType_Group: + case kUpb_FieldType_Message: + return kUpb_CType_Message; + } + UPB_UNREACHABLE(); +} + +upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } + +uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } + +upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } + +uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } + +bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { + return f->is_extension_; +} + +bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->packed_; } + +const char* upb_FieldDef_Name(const upb_FieldDef* f) { + return _upb_DefBuilder_FullToShort(f->full_name); +} + +const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { + return f->json_name; +} + +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { + return f->has_json_name_; +} + +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } + +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { + return f->msgdef; +} + +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { + return f->is_extension_ ? f->scope.extension_scope : NULL; +} + +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { + return f->is_extension_ ? NULL : f->scope.oneof; +} + +const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { + const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); + if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; + return oneof; +} + +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { + UPB_ASSERT(!upb_FieldDef_IsSubMessage(f)); + upb_MessageValue ret; + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return (upb_MessageValue){.bool_val = f->defaultval.boolean}; + case kUpb_CType_Int64: + return (upb_MessageValue){.int64_val = f->defaultval.sint}; + case kUpb_CType_UInt64: + return (upb_MessageValue){.uint64_val = f->defaultval.uint}; + case kUpb_CType_Enum: + case kUpb_CType_Int32: + return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; + case kUpb_CType_UInt32: + return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; + case kUpb_CType_Float: + return (upb_MessageValue){.float_val = f->defaultval.flt}; + case kUpb_CType_Double: + return (upb_MessageValue){.double_val = f->defaultval.dbl}; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + str_t* str = f->defaultval.str; + if (str) { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = str->str, .size = str->len}}; + } else { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = NULL, .size = 0}}; + } + } + default: + UPB_UNREACHABLE(); + } + + return ret; +} + +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; +} + +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; +} + +const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) { + UPB_ASSERT(!upb_FieldDef_IsExtension(f)); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); + return &layout->fields[f->layout_index]; +} + +const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( + const upb_FieldDef* f) { + UPB_ASSERT(upb_FieldDef_IsExtension(f)); + const upb_FileDef* file = upb_FieldDef_File(f); + return _upb_FileDef_ExtensionMiniTable(file, f->layout_index); +} + +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { + return f->proto3_optional_; +} + +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message; +} + +bool upb_FieldDef_IsString(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_String || + upb_FieldDef_CType(f) == kUpb_CType_Bytes; +} + +bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Optional; +} + +bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Required; +} + +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Repeated; +} + +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { + return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); +} + +bool upb_FieldDef_IsMap(const upb_FieldDef* f) { + return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && + upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); +} + +bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } + +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsSubMessage(f) || + upb_FieldDef_CType(f) == kUpb_CType_Enum; +} + +bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { + if (upb_FieldDef_IsRepeated(f)) return false; + const upb_FileDef* file = upb_FieldDef_File(f); + return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || + upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; +} + +static bool between(int32_t x, int32_t low, int32_t high) { + return x >= low && x <= high; +} + +bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } +bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } +bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } + +bool upb_FieldDef_checkdescriptortype(int32_t type) { + return between(type, 1, 18); +} + +/* Code to build defs from descriptor protos. *********************************/ + +/* There is a question of how much validation to do here. It will be difficult + * to perfectly match the amount of validation performed by proto2. But since + * this code is used to directly build defs from Ruby (for example) we do need + * to validate important constraints like uniqueness of names and numbers. */ + +static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; } + +static size_t upb_MessageValue_sizeof(upb_CType type) { + switch (type) { + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return 8; + case kUpb_CType_Enum: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Float: + return 4; + case kUpb_CType_Bool: + return 1; + case kUpb_CType_Message: + return sizeof(void*); + case kUpb_CType_Bytes: + case kUpb_CType_String: + return sizeof(upb_StringView); + } + UPB_UNREACHABLE(); +} + +static uint8_t upb_msg_fielddefsize(const upb_FieldDef* f) { + if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { + upb_MapEntry ent; + UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); + return sizeof(ent.k); + } else if (upb_FieldDef_IsRepeated(f)) { + return sizeof(void*); + } else { + return upb_MessageValue_sizeof(upb_FieldDef_CType(f)); + } +} + +static uint32_t upb_MiniTable_place(upb_DefBuilder* ctx, upb_MiniTable* l, + size_t size, const upb_MessageDef* m) { + size_t ofs = UPB_ALIGN_UP(l->size, size); + size_t next = ofs + size; + + if (next > UINT16_MAX) { + _upb_DefBuilder_Errf(ctx, + "size of message %s exceeded max size of %zu bytes", + upb_MessageDef_FullName(m), (size_t)UINT16_MAX); + } + + l->size = next; + return ofs; +} + +static int field_number_cmp(const void* p1, const void* p2) { + const upb_MiniTable_Field* f1 = p1; + const upb_MiniTable_Field* f2 = p2; + return f1->number - f2->number; +} + +static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l, + upb_MiniTable_Field* fields) { + int i; + int n = upb_MessageDef_FieldCount(m); + int dense_below = 0; + for (i = 0; i < n; i++) { + upb_FieldDef* f = + (upb_FieldDef*)upb_MessageDef_FindFieldByNumber(m, fields[i].number); + UPB_ASSERT(f); + f->layout_index = i; + if (i < UINT8_MAX && fields[i].number == i + 1 && + (i == 0 || fields[i - 1].number == i)) { + dense_below = i + 1; + } + } + l->dense_below = dense_below; +} + +static uint8_t map_descriptortype(const upb_FieldDef* f) { + uint8_t type = upb_FieldDef_Type(f); + /* See TableDescriptorType() in upbc/generator.cc for details and + * rationale of these exceptions. */ + if (type == kUpb_FieldType_String) { + const upb_FileDef* file = upb_FieldDef_File(f); + const upb_Syntax syntax = upb_FileDef_Syntax(file); + + if (syntax == kUpb_Syntax_Proto2) return kUpb_FieldType_Bytes; + } else if (type == kUpb_FieldType_Enum) { + const upb_FileDef* file = upb_EnumDef_File(f->sub.enumdef); + const upb_Syntax syntax = upb_FileDef_Syntax(file); + + if (syntax == kUpb_Syntax_Proto3 || UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 || + // TODO(https://github.com/protocolbuffers/upb/issues/541): + // fix map enum values to check for unknown enum values and put + // them in the unknown field set. + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { + return kUpb_FieldType_Int32; + } + } + return type; +} + +static void fill_fieldlayout(upb_MiniTable_Field* field, + const upb_FieldDef* f) { + field->number = upb_FieldDef_Number(f); + field->descriptortype = map_descriptortype(f); + + if (upb_FieldDef_IsMap(f)) { + field->mode = + kUpb_FieldMode_Map | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); + } else if (upb_FieldDef_IsRepeated(f)) { + field->mode = + kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); + } else { + /* Maps descriptor type -> elem_size_lg2. */ + static const uint8_t sizes[] = { + -1, /* invalid descriptor type */ + kUpb_FieldRep_8Byte, /* DOUBLE */ + kUpb_FieldRep_4Byte, /* FLOAT */ + kUpb_FieldRep_8Byte, /* INT64 */ + kUpb_FieldRep_8Byte, /* UINT64 */ + kUpb_FieldRep_4Byte, /* INT32 */ + kUpb_FieldRep_8Byte, /* FIXED64 */ + kUpb_FieldRep_4Byte, /* FIXED32 */ + kUpb_FieldRep_1Byte, /* BOOL */ + kUpb_FieldRep_StringView, /* STRING */ + kUpb_FieldRep_Pointer, /* GROUP */ + kUpb_FieldRep_Pointer, /* MESSAGE */ + kUpb_FieldRep_StringView, /* BYTES */ + kUpb_FieldRep_4Byte, /* UINT32 */ + kUpb_FieldRep_4Byte, /* ENUM */ + kUpb_FieldRep_4Byte, /* SFIXED32 */ + kUpb_FieldRep_8Byte, /* SFIXED64 */ + kUpb_FieldRep_4Byte, /* SINT32 */ + kUpb_FieldRep_8Byte, /* SINT64 */ + }; + field->mode = kUpb_FieldMode_Scalar | + (sizes[field->descriptortype] << kUpb_FieldRep_Shift); + } + + if (upb_FieldDef_IsPacked(f)) { + field->mode |= kUpb_LabelFlags_IsPacked; + } + + if (upb_FieldDef_IsExtension(f)) { + field->mode |= kUpb_LabelFlags_IsExtension; + } +} + +/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. + * It computes a dynamic layout for all of the fields in |m|. */ +void _upb_FieldDef_MakeLayout(upb_DefBuilder* ctx, const upb_MessageDef* m) { + upb_MiniTable* l = (upb_MiniTable*)upb_MessageDef_MiniTable(m); + size_t field_count = upb_MessageDef_FieldCount(m); + size_t sublayout_count = 0; + upb_MiniTable_Sub* subs; + upb_MiniTable_Field* fields; + + memset(l, 0, sizeof(*l) + sizeof(_upb_FastTable_Entry)); + + // Count sub-messages. + for (size_t i = 0; i < field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + if (upb_FieldDef_IsSubMessage(f)) { + sublayout_count++; + } + if (upb_FieldDef_CType(f) == kUpb_CType_Enum && + upb_FileDef_Syntax(upb_EnumDef_File(f->sub.enumdef)) == + kUpb_Syntax_Proto2) { + sublayout_count++; + } + } + + fields = _upb_DefBuilder_Alloc(ctx, field_count * sizeof(*fields)); + subs = _upb_DefBuilder_Alloc(ctx, sublayout_count * sizeof(*subs)); + + l->field_count = upb_MessageDef_FieldCount(m); + l->fields = fields; + l->subs = subs; + l->table_mask = 0; + l->required_count = 0; + + if (upb_MessageDef_ExtensionRangeCount(m) > 0) { + if (google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(m))) { + l->ext = kUpb_ExtMode_IsMessageSet; + } else { + l->ext = kUpb_ExtMode_Extendable; + } + } else { + l->ext = kUpb_ExtMode_NonExtendable; + } + + /* TODO(haberman): initialize fast tables so that reflection-based parsing + * can get the same speeds as linked-in types. */ + l->fasttable[0].field_parser = &_upb_FastDecoder_DecodeGeneric; + l->fasttable[0].field_data = 0; + + if (upb_MessageDef_IsMapEntry(m)) { + /* TODO(haberman): refactor this method so this special case is more + * elegant. */ + const upb_FieldDef* key = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* val = upb_MessageDef_FindFieldByNumber(m, 2); + fields[0].number = 1; + fields[1].number = 2; + fields[0].mode = kUpb_FieldMode_Scalar; + fields[1].mode = kUpb_FieldMode_Scalar; + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].descriptortype = map_descriptortype(key); + fields[1].descriptortype = map_descriptortype(val); + fields[0].offset = 0; + fields[1].offset = sizeof(upb_StringView); + fields[1].submsg_index = 0; + + if (upb_FieldDef_CType(val) == kUpb_CType_Message) { + subs[0].submsg = + upb_MessageDef_MiniTable(upb_FieldDef_MessageSubDef(val)); + } + + upb_FieldDef* fielddefs = (upb_FieldDef*)upb_MessageDef_Field(m, 0); + UPB_ASSERT(fielddefs[0].number_ == 1); + UPB_ASSERT(fielddefs[1].number_ == 2); + fielddefs[0].layout_index = 0; + fielddefs[1].layout_index = 1; + + l->field_count = 2; + l->size = 2 * sizeof(upb_StringView); + l->size = UPB_ALIGN_UP(l->size, 8); + l->dense_below = 2; + return; + } + + /* Allocate data offsets in three stages: + * + * 1. hasbits. + * 2. regular fields. + * 3. oneof fields. + * + * OPT: There is a lot of room for optimization here to minimize the size. + */ + + /* Assign hasbits for required fields first. */ + size_t hasbit = 0; + + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; + if (upb_FieldDef_Label(f) == kUpb_Label_Required) { + field->presence = ++hasbit; + if (hasbit >= 63) { + _upb_DefBuilder_Errf(ctx, "Message with >=63 required fields: %s", + upb_MessageDef_FullName(m)); + } + l->required_count++; + } + } + + /* Allocate hasbits and set basic field attributes. */ + sublayout_count = 0; + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; + + fill_fieldlayout(field, f); + + if (field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group) { + field->submsg_index = sublayout_count++; + subs[field->submsg_index].submsg = + upb_MessageDef_MiniTable(upb_FieldDef_MessageSubDef(f)); + } else if (field->descriptortype == kUpb_FieldType_Enum) { + field->submsg_index = sublayout_count++; + subs[field->submsg_index].subenum = + _upb_EnumDef_MiniTable(upb_FieldDef_EnumSubDef(f)); + UPB_ASSERT(subs[field->submsg_index].subenum); + } + + if (upb_FieldDef_Label(f) == kUpb_Label_Required) { + /* Hasbit was already assigned. */ + } else if (upb_FieldDef_HasPresence(f) && + !upb_FieldDef_RealContainingOneof(f)) { + /* We don't use hasbit 0, so that 0 can indicate "no presence" in the + * table. This wastes one hasbit, but we don't worry about it for now. */ + field->presence = ++hasbit; + } else { + field->presence = 0; + } + } + + /* Account for space used by hasbits. */ + l->size = hasbit ? div_round_up(hasbit + 1, 8) : 0; + + /* Allocate non-oneof fields. */ + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + size_t field_size = upb_msg_fielddefsize(f); + size_t index = upb_FieldDef_Index(f); + + if (upb_FieldDef_RealContainingOneof(f)) { + /* Oneofs are handled separately below. */ + continue; + } + + fields[index].offset = upb_MiniTable_place(ctx, l, field_size, m); + } + + /* Allocate oneof fields. Each oneof field consists of a uint32 for the case + * and space for the actual data. */ + for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { + const upb_OneofDef* o = upb_MessageDef_Oneof(m, i); + size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ + size_t field_size = 0; + uint32_t case_offset; + uint32_t data_offset; + + if (upb_OneofDef_IsSynthetic(o)) continue; + + if (upb_OneofDef_FieldCount(o) == 0) { + _upb_DefBuilder_Errf(ctx, "Oneof must have at least one field (%s)", + upb_OneofDef_FullName(o)); + } + + /* Calculate field size: the max of all field sizes. */ + for (int j = 0; j < upb_OneofDef_FieldCount(o); j++) { + const upb_FieldDef* f = upb_OneofDef_Field(o, j); + field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); + } + + /* Align and allocate case offset. */ + case_offset = upb_MiniTable_place(ctx, l, case_size, m); + data_offset = upb_MiniTable_place(ctx, l, field_size, m); + + for (int i = 0; i < upb_OneofDef_FieldCount(o); i++) { + const upb_FieldDef* f = upb_OneofDef_Field(o, i); + fields[upb_FieldDef_Index(f)].offset = data_offset; + fields[upb_FieldDef_Index(f)].presence = ~case_offset; + } + } + + /* Size of the entire structure should be a multiple of its greatest + * alignment. TODO: track overall alignment for real? */ + l->size = UPB_ALIGN_UP(l->size, 8); + + /* Sort fields by number. */ + if (fields) { + qsort(fields, upb_MessageDef_FieldCount(m), sizeof(*fields), + field_number_cmp); + } + assign_layout_indices(m, l, fields); +} + +static bool streql2(const char* a, size_t n, const char* b) { + return n == strlen(b) && memcmp(a, b, n) == 0; +} + +static size_t getjsonname(const char* name, size_t size, char* buf, + size_t len) { + size_t src, dst = 0; + bool ucase_next = false; + +#define WRITE(byte) \ + ++dst; \ + if (dst < len) \ + buf[dst - 1] = byte; \ + else if (dst == len) \ + buf[dst - 1] = '\0' + + if (!name) { + WRITE('\0'); + return 0; + } + + /* Implement the transformation as described in the spec: + * 1. upper case all letters after an underscore. + * 2. remove all underscores. + */ + for (src = 0; src < size; src++) { + if (name[src] == '_') { + ucase_next = true; + continue; + } + + if (ucase_next) { + WRITE(toupper(name[src])); + ucase_next = false; + } else { + WRITE(name[src]); + } + } + + WRITE('\0'); + return dst; + +#undef WRITE +} + +static char* makejsonname(upb_DefBuilder* ctx, const char* name, size_t size) { + size_t json_size = size + 1; // +1 for trailing '\0' + char* json_name = _upb_DefBuilder_Alloc(ctx, json_size); + getjsonname(name, size, json_name, json_size); + return json_name; +} + +static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + if (!ret) _upb_DefBuilder_OomErr(ctx); + ret->len = len; + if (len) memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; +} + +static str_t* unescape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char* data, size_t len) { + // Size here is an upper bound; escape sequences could ultimately shrink it. + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + char* dst = &ret->str[0]; + const char* src = data; + const char* end = data + len; + + while (src < end) { + if (*src == '\\') { + src++; + *dst++ = _upb_DefBuilder_ParseEscape(ctx, f, &src, end); + } else { + *dst++ = *src++; + } + } + + ret->len = dst - &ret->str[0]; + return ret; +} + +static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, + upb_FieldDef* f) { + char* end; + char nullz[64]; + errno = 0; + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + case kUpb_CType_Double: + case kUpb_CType_Float: + /* Standard C number parsing functions expect null-terminated strings. */ + if (len >= sizeof(nullz) - 1) { + _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); + } + memcpy(nullz, str, len); + nullz[len] = '\0'; + str = nullz; + break; + default: + break; + } + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: { + long val = strtol(str, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_Enum: { + const upb_EnumDef* e = f->sub.enumdef; + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str, len); + if (!ev) { + goto invalid; + } + f->defaultval.sint = upb_EnumValueDef_Number(ev); + break; + } + case kUpb_CType_Int64: { + long long val = strtoll(str, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_UInt32: { + unsigned long val = strtoul(str, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_UInt64: { + unsigned long long val = strtoull(str, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_Double: { + double val = strtod(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.dbl = val; + break; + } + case kUpb_CType_Float: { + float val = strtof(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.flt = val; + break; + } + case kUpb_CType_Bool: { + if (streql2(str, len, "false")) { + f->defaultval.boolean = false; + } else if (streql2(str, len, "true")) { + f->defaultval.boolean = true; + } else { + goto invalid; + } + break; + } + case kUpb_CType_String: + f->defaultval.str = newstr(ctx, str, len); + break; + case kUpb_CType_Bytes: + f->defaultval.str = unescape(ctx, f, str, len); + break; + case kUpb_CType_Message: + /* Should not have a default value. */ + _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", + upb_FieldDef_FullName(f)); + } + + return; + +invalid: + _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", + (int)len, str, upb_FieldDef_FullName(f), + (int)upb_FieldDef_Type(f)); +} + +static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + f->defaultval.sint = 0; + break; + case kUpb_CType_UInt64: + case kUpb_CType_UInt32: + f->defaultval.uint = 0; + break; + case kUpb_CType_Double: + case kUpb_CType_Float: + f->defaultval.dbl = 0; + break; + case kUpb_CType_String: + case kUpb_CType_Bytes: + f->defaultval.str = newstr(ctx, NULL, 0); + break; + case kUpb_CType_Bool: + f->defaultval.boolean = false; + break; + case kUpb_CType_Enum: { + const upb_EnumValueDef* v = upb_EnumDef_Value(f->sub.enumdef, 0); + f->defaultval.sint = upb_EnumValueDef_Number(v); + } + case kUpb_CType_Message: + break; + } +} + +static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, + upb_MessageDef* m, + const google_protobuf_FieldDescriptorProto* field_proto, + upb_FieldDef* f) { + const char* json_name; + + // Must happen before _upb_DefBuilder_Add() + f->file = _upb_DefBuilder_File(ctx); + + if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { + _upb_DefBuilder_Errf(ctx, "field has no name"); + } + + const upb_StringView name = google_protobuf_FieldDescriptorProto_name(field_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + const char* full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + + if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) { + const upb_StringView sv = + google_protobuf_FieldDescriptorProto_json_name(field_proto); + json_name = upb_strdup2(sv.data, sv.size, ctx->arena); + if (!json_name) _upb_DefBuilder_OomErr(ctx); + f->has_json_name_ = true; + } else { + json_name = makejsonname(ctx, name.data, name.size); + f->has_json_name_ = false; + } + + f->full_name = full_name; + f->json_name = json_name; + f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); + f->number_ = google_protobuf_FieldDescriptorProto_number(field_proto); + f->scope.oneof = NULL; + f->proto3_optional_ = + google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); + f->msgdef = m; + + bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); + bool has_type_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); + + f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); + + if (has_type) { + switch (f->type_) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + if (!has_type_name) { + _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", + (int)f->type_, full_name); + } + break; + default: + if (has_type_name) { + _upb_DefBuilder_Errf( + ctx, "invalid type for field with type_name set (%s, %d)", + full_name, (int)f->type_); + } + } + } else if (has_type_name) { + f->type_ = + UPB_FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef() + } + + if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { + _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, + f->type_); + } + + if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { + _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, + f->label_); + } + + /* We can't resolve the subdef or (in the case of extensions) the containing + * message yet, because it may not have been defined yet. We stash a pointer + * to the field_proto until later when we can properly resolve it. */ + f->sub.unresolved = field_proto; + + if (f->label_ == kUpb_Label_Required && + upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", + f->full_name); + } + + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); + + if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { + _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", + f->full_name); + } + + if (!m) { + _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", + f->full_name); + } + + if (oneof_index >= upb_MessageDef_OneofCount(m)) { + _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); + } + + upb_OneofDef* oneof = (upb_OneofDef*)upb_MessageDef_Oneof(m, oneof_index); + f->scope.oneof = oneof; + + bool ok = _upb_OneofDef_Insert(oneof, f, name.data, name.size, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } else { + if (f->proto3_optional_) { + _upb_DefBuilder_Errf(ctx, + "field with proto3_optional was not in a oneof (%s)", + f->full_name); + } + } + + UBP_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); + + if (google_protobuf_FieldOptions_has_packed(f->opts)) { + f->packed_ = google_protobuf_FieldOptions_packed(f->opts); + } else { + // Repeated fields default to packed for proto3 only. + f->packed_ = upb_FieldDef_IsPrimitive(f) && + f->label_ == kUpb_Label_Repeated && + upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; + } +} + +static void _upb_FieldDef_CreateExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + _upb_FieldDef_Create(ctx, prefix, m, field_proto, f); + f->is_extension_ = true; + + f->scope.extension_scope = m; + _upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT)); + f->layout_index = ctx->ext_count++; + + if (ctx->layout) { + UPB_ASSERT(_upb_FieldDef_ExtensionMiniTable(f)->field.number == f->number_); + } +} + +static void _upb_FieldDef_CreateNotExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + _upb_FieldDef_Create(ctx, prefix, m, field_proto, f); + f->is_extension_ = false; + + _upb_MessageDef_InsertField(ctx, m, f); + + if (ctx->layout) { + const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); + const upb_MiniTable_Field* fields = mt->fields; + const int count = mt->field_count; + bool found = false; + for (int i = 0; i < count; i++) { + if (fields[i].number == f->number_) { + f->layout_index = i; + found = true; + break; + } + } + UPB_ASSERT(found); + } +} + +upb_FieldDef* _upb_FieldDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix, + upb_MessageDef* m, bool is_ext) { + _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); + upb_FieldDef* f = + (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); + + if (is_ext) { + for (size_t i = 0; i < n; i++) { + _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, &f[i]); + f[i].index_ = i; + } + } else { + for (size_t i = 0; i < n; i++) { + _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, &f[i]); + f[i].index_ = i; + } + } + return f; +} + +static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f) { + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; + upb_StringView name = + google_protobuf_FieldDescriptorProto_type_name(field_proto); + bool has_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); + switch ((int)f->type_) { + case UPB_FIELD_TYPE_UNSPECIFIED: { + // Type was not specified and must be inferred. + UPB_ASSERT(has_name); + upb_deftype_t type; + const void* def = + _upb_DefBuilder_ResolveAny(ctx, f->full_name, prefix, name, &type); + switch (type) { + case UPB_DEFTYPE_ENUM: + f->sub.enumdef = def; + f->type_ = kUpb_FieldType_Enum; + break; + case UPB_DEFTYPE_MSG: + f->sub.msgdef = def; + f->type_ = kUpb_FieldType_Message; // It appears there is no way of + // this being a group. + break; + default: + _upb_DefBuilder_Errf(ctx, "Couldn't resolve type name for field %s", + f->full_name); + } + } + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + UPB_ASSERT(has_name); + f->sub.msgdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_MSG); + break; + case kUpb_FieldType_Enum: + UPB_ASSERT(has_name); + f->sub.enumdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_ENUM); + break; + default: + // No resolution necessary. + break; + } +} + +static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { + _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", + f->full_name); + } + + upb_StringView name = google_protobuf_FieldDescriptorProto_extendee(field_proto); + const upb_MessageDef* m = + _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); + f->msgdef = m; + + bool found = false; + + for (int i = 0, n = upb_MessageDef_ExtensionRangeCount(m); i < n; i++) { + const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i); + if (upb_ExtensionRange_Start(r) <= f->number_ && + f->number_ < upb_ExtensionRange_End(r)) { + found = true; + break; + } + } + + if (!found) { + _upb_DefBuilder_Errf( + ctx, + "field number %u in extension %s has no extension range in " + "message %s", + (unsigned)f->number_, f->full_name, upb_MessageDef_FullName(f->msgdef)); + } + + const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); + if (ctx->layout) { + UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); + } else { + upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; + fill_fieldlayout(&mut_ext->field, f); + mut_ext->field.presence = 0; + mut_ext->field.offset = 0; + mut_ext->field.submsg_index = 0; + mut_ext->extendee = upb_MessageDef_MiniTable(f->msgdef); + mut_ext->sub.submsg = upb_MessageDef_MiniTable(f->sub.msgdef); + } + + bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +static void resolve_default(upb_DefBuilder* ctx, upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + // Have to delay resolving of the default value until now because of the enum + // case, since enum defaults are specified with a label. + if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { + upb_StringView defaultval = + google_protobuf_FieldDescriptorProto_default_value(field_proto); + + if (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, + "proto3 fields cannot have explicit defaults (%s)", + f->full_name); + } + + if (upb_FieldDef_IsSubMessage(f)) { + _upb_DefBuilder_Errf(ctx, + "message fields cannot have explicit defaults (%s)", + f->full_name); + } + + parse_default(ctx, defaultval.data, defaultval.size, f); + f->has_default = true; + } else { + set_default_default(ctx, f); + f->has_default = false; + } +} + +void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f) { + // We have to stash this away since resolve_subdef() may overwrite it. + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; + + resolve_subdef(ctx, prefix, f); + resolve_default(ctx, f, field_proto); + + if (f->is_extension_) { + resolve_extension(ctx, prefix, f, field_proto); + } +} diff --git a/upb/reflection/field_def.h b/upb/reflection/field_def.h new file mode 100644 index 0000000000..409ee70733 --- /dev/null +++ b/upb/reflection/field_def.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_FIELD_DEF_H_ +#define UPB_REFLECTION_FIELD_DEF_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port_def.inc" + +// Maximum field number allowed for FieldDefs. +// This is an inherent limit of the protobuf wire format. +#define kUpb_MaxFieldNumber ((1 << 29) - 1) + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f); +upb_CType upb_FieldDef_CType(const upb_FieldDef* f); +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f); +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f); +const char* upb_FieldDef_FullName(const upb_FieldDef* f); +bool upb_FieldDef_HasDefault(const upb_FieldDef* f); +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f); +bool upb_FieldDef_HasOptions(const upb_FieldDef* f); +bool upb_FieldDef_HasPresence(const upb_FieldDef* f); +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f); +uint32_t upb_FieldDef_Index(const upb_FieldDef* f); +bool upb_FieldDef_IsExtension(const upb_FieldDef* f); +bool upb_FieldDef_IsMap(const upb_FieldDef* f); +bool upb_FieldDef_IsOptional(const upb_FieldDef* f); +bool upb_FieldDef_IsPacked(const upb_FieldDef* f); +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f); +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f); +bool upb_FieldDef_IsRequired(const upb_FieldDef* f); +bool upb_FieldDef_IsString(const upb_FieldDef* f); +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f); +const char* upb_FieldDef_JsonName(const upb_FieldDef* f); +upb_Label upb_FieldDef_Label(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); +const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f); +const char* upb_FieldDef_Name(const upb_FieldDef* f); +uint32_t upb_FieldDef_Number(const upb_FieldDef* f); +const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f); +const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f); +upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i); +const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( + const upb_FieldDef* f); +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f); + +// Allocate and initialize an array of |n| field defs. +upb_FieldDef* _upb_FieldDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix, + upb_MessageDef* m, bool is_ext); + +void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f); + +void _upb_FieldDef_MakeLayout(upb_DefBuilder* ctx, const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_FIELD_DEF_H_ */ diff --git a/upb/reflection/file_def.c b/upb/reflection/file_def.c new file mode 100644 index 0000000000..4a48286420 --- /dev/null +++ b/upb/reflection/file_def.c @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/file_def.h" + +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_pool.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/message_def.h" +#include "upb/reflection/service_def.h" + +// Must be last. +#include "upb/port_def.inc" + +struct upb_FileDef { + const google_protobuf_FileOptions* opts; + const char* name; + const char* package; + + const upb_FileDef** deps; + const int32_t* public_deps; + const int32_t* weak_deps; + const upb_MessageDef* top_lvl_msgs; + const upb_EnumDef* top_lvl_enums; + const upb_FieldDef* top_lvl_exts; + const upb_ServiceDef* services; + const upb_MiniTable_Extension** ext_layouts; + const upb_DefPool* symtab; + + int dep_count; + int public_dep_count; + int weak_dep_count; + int top_lvl_msg_count; + int top_lvl_enum_count; + int top_lvl_ext_count; + int service_count; + int ext_count; // All exts in the file. + upb_Syntax syntax; +}; + +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { + return f->opts; +} + +bool upb_FileDef_HasOptions(const upb_FileDef* f) { + return f->opts != (void*)kUpbDefOptDefault; +} + +const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } + +const char* upb_FileDef_Package(const upb_FileDef* f) { + return f->package ? f->package : ""; +} + +const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; } + +upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } + +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { + return f->top_lvl_msg_count; +} + +int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } + +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { + return f->public_dep_count; +} + +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { + return f->weak_dep_count; +} + +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { + return f->public_deps; +} + +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { + return f->weak_deps; +} + +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { + return f->top_lvl_enum_count; +} + +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { + return f->top_lvl_ext_count; +} + +int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } + +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->dep_count); + return f->deps[i]; +} + +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->public_deps[i]]; +} + +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->weak_deps[i]]; +} + +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); + return _upb_MessageDef_At(f->top_lvl_msgs, i); +} + +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); + return _upb_EnumDef_At(f->top_lvl_enums, i); +} + +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); + return _upb_FieldDef_At(f->top_lvl_exts, i); +} + +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->service_count); + return _upb_ServiceDef_At(f->services, i); +} + +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } + +const upb_MiniTable_Extension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i) { + return f->ext_layouts[i]; +} + +static char* strviewdup(upb_DefBuilder* ctx, upb_StringView view) { + char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; +} + +static bool streql_view(upb_StringView view, const char* b) { + return view.size == strlen(b) && memcmp(view.data, b, view.size) == 0; +} + +static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { + size_t n; + google_protobuf_DescriptorProto_extension(msg_proto, &n); + int ext_count = n; + + const google_protobuf_DescriptorProto* const* nested_msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + for (size_t i = 0; i < n; i++) { + ext_count += count_exts_in_msg(nested_msgs[i]); + } + + return ext_count; +} + +// Allocate and initialize one file def, and add it to the context object. +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const google_protobuf_FileDescriptorProto* file_proto) { + upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); + ctx->file = file; + + const google_protobuf_DescriptorProto* const* msgs; + const google_protobuf_EnumDescriptorProto* const* enums; + const google_protobuf_FieldDescriptorProto* const* exts; + const google_protobuf_ServiceDescriptorProto* const* services; + const upb_StringView* strs; + const int32_t* public_deps; + const int32_t* weak_deps; + size_t i, n; + + file->symtab = ctx->symtab; + + // Count all extensions in the file, to build a flat array of layouts. + google_protobuf_FileDescriptorProto_extension(file_proto, &n); + int ext_count = n; + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + for (int i = 0; i < n; i++) { + ext_count += count_exts_in_msg(msgs[i]); + } + file->ext_count = ext_count; + + if (ctx->layout) { + // We are using the ext layouts that were passed in. + file->ext_layouts = ctx->layout->exts; + if (ctx->layout->ext_count != file->ext_count) { + _upb_DefBuilder_Errf(ctx, + "Extension count did not match layout (%d vs %d)", + ctx->layout->ext_count, file->ext_count); + } + } else { + // We are building ext layouts from scratch. + file->ext_layouts = _upb_DefBuilder_Alloc( + ctx, sizeof(*file->ext_layouts) * file->ext_count); + upb_MiniTable_Extension* ext = + _upb_DefBuilder_Alloc(ctx, sizeof(*ext) * file->ext_count); + for (int i = 0; i < file->ext_count; i++) { + file->ext_layouts[i] = &ext[i]; + } + } + + if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { + _upb_DefBuilder_Errf(ctx, "File has no name"); + } + + file->name = strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); + + upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); + if (package.size) { + _upb_DefBuilder_CheckIdentFull(ctx, package); + file->package = strviewdup(ctx, package); + } else { + file->package = NULL; + } + + if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { + upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file_proto); + + if (streql_view(syntax, "proto2")) { + file->syntax = kUpb_Syntax_Proto2; + } else if (streql_view(syntax, "proto3")) { + file->syntax = kUpb_Syntax_Proto3; + } else { + _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(syntax)); + } + } else { + file->syntax = kUpb_Syntax_Proto2; + } + + // Read options. + UBP_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); + + // Verify dependencies. + strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); + file->dep_count = n; + file->deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->deps) * n); + + for (i = 0; i < n; i++) { + upb_StringView str = strs[i]; + file->deps[i] = + upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); + if (!file->deps[i]) { + _upb_DefBuilder_Errf(ctx, + "Depends on file '" UPB_STRINGVIEW_FORMAT + "', but it has not been loaded", + UPB_STRINGVIEW_ARGS(str)); + } + } + + public_deps = google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); + file->public_dep_count = n; + file->public_deps = + _upb_DefBuilder_Alloc(ctx, sizeof(*file->public_deps) * n); + int32_t* mutable_public_deps = (int32_t*)file->public_deps; + for (i = 0; i < n; i++) { + if (public_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", + (int)public_deps[i]); + } + mutable_public_deps[i] = public_deps[i]; + } + + weak_deps = google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); + file->weak_dep_count = n; + file->weak_deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->weak_deps) * n); + int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; + for (i = 0; i < n; i++) { + if (weak_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", + (int)weak_deps[i]); + } + mutable_weak_deps[i] = weak_deps[i]; + } + + // Create enums. + enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); + file->top_lvl_enum_count = n; + file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); + + // Create extensions. + exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); + file->top_lvl_ext_count = n; + file->top_lvl_exts = + _upb_FieldDefs_New(ctx, n, exts, file->package, NULL, true); + + // Create messages. + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + file->top_lvl_msg_count = n; + file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); + + // Create services. + services = google_protobuf_FileDescriptorProto_service(file_proto, &n); + file->service_count = n; + file->services = _upb_ServiceDefs_New(ctx, n, services); + + // Now that all names are in the table, build layouts and resolve refs. + for (i = 0; i < (size_t)file->top_lvl_ext_count; i++) { + _upb_FieldDef_Resolve( + ctx, file->package, + (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i)); + } + + for (i = 0; i < (size_t)file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_Resolve(ctx, m); + } + + if (file->ext_count) { + bool ok = _upb_extreg_add(_upb_DefPool_ExtReg(ctx->symtab), + file->ext_layouts, file->ext_count); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } +} diff --git a/upb/reflection/file_def.h b/upb/reflection/file_def.h new file mode 100644 index 0000000000..0ccad42f4b --- /dev/null +++ b/upb/reflection/file_def.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_FILE_DEF_H_ +#define UPB_REFLECTION_FILE_DEF_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i); +int upb_FileDef_DependencyCount(const upb_FileDef* f); +bool upb_FileDef_HasOptions(const upb_FileDef* f); +const char* upb_FileDef_Name(const upb_FileDef* f); +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f); +const char* upb_FileDef_Package(const upb_FileDef* f); +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); + +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i); +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f); + +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i); +int upb_FileDef_ServiceCount(const upb_FileDef* f); + +upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f); + +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f); + +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f); + +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f); + +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i); +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +const upb_MiniTable_Extension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i); +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f); +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f); + +// upb_FileDef_Package() returns "" if f->package is NULL, this does not. +const char* _upb_FileDef_RawPackage(const upb_FileDef* f); + +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const google_protobuf_FileDescriptorProto* file_proto); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_FILE_DEF_H_ */ diff --git a/upb/reflection.c b/upb/reflection/message.c similarity index 97% rename from upb/reflection.c rename to upb/reflection/message.c index f2913b2465..6cd92d08d2 100644 --- a/upb/reflection.c +++ b/upb/reflection/message.c @@ -25,13 +25,21 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "upb/reflection.h" +#include "upb/reflection/message.h" #include #include "upb/internal/table.h" #include "upb/map.h" #include "upb/msg.h" +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_pool.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/message_def.h" +#include "upb/reflection/oneof_def.h" + +// Must be last. #include "upb/port_def.inc" static size_t get_field_size(const upb_MiniTable_Field* f) { @@ -59,9 +67,6 @@ static size_t get_field_size(const upb_MiniTable_Field* f) { return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; } -/** upb_Message - * *******************************************************************/ - upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a) { return _upb_Message_New(upb_MessageDef_MiniTable(m), a); } diff --git a/upb/reflection/message.h b/upb/reflection/message.h new file mode 100644 index 0000000000..68728c0c93 --- /dev/null +++ b/upb/reflection/message.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_REFLECTION_MESSAGE_H_ +#define UPB_REFLECTION_MESSAGE_H_ + +#include "upb/map.h" +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); + +/* Creates a new message of the given type in the given arena. */ +upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a); + +/* Returns the value associated with this field. */ +upb_MessageValue upb_Message_Get(const upb_Message* msg, const upb_FieldDef* f); + +/* Returns a mutable pointer to a map, array, or submessage value. If the given + * arena is non-NULL this will construct a new object if it was not previously + * present. May not be called for primitive fields. */ +upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, + const upb_FieldDef* f, + upb_Arena* a); + +/* May only be called for fields where upb_FieldDef_HasPresence(f) == true. */ +bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f); + +/* Returns the field that is set in the oneof, or NULL if none are set. */ +const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, + const upb_OneofDef* o); + +/* Sets the given field to the given value. For a msg/array/map/string, the + * caller must ensure that the target data outlives |msg| (by living either in + * the same arena or a different arena that outlives it). + * + * Returns false if allocation fails. */ +bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a); + +/* Clears any field presence and sets the value back to its default. */ +void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f); + +/* Clear all data and unknown fields. */ +void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m); + +/* Iterate over present fields. + * + * size_t iter = kUpb_Message_Begin; + * const upb_FieldDef *f; + * upb_MessageValue val; + * while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) { + * process_field(f, val); + * } + * + * If ext_pool is NULL, no extensions will be returned. If the given symtab + * returns extensions that don't match what is in this message, those extensions + * will be skipped. + */ + +#define kUpb_Message_Begin -1 +bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, const upb_FieldDef** f, + upb_MessageValue* val, size_t* iter); + +/* Clears all unknown field data from this message and all submessages. */ +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int maxdepth); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_MESSAGE_H_ */ diff --git a/upb/reflection/message.hpp b/upb/reflection/message.hpp new file mode 100644 index 0000000000..425be98d2d --- /dev/null +++ b/upb/reflection/message.hpp @@ -0,0 +1,37 @@ +// Copyright (c) 2009-2021, Google LLC +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Google LLC nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef UPB_REFLECTION_MESSAGE_HPP_ +#define UPB_REFLECTION_MESSAGE_HPP_ + +#include "upb/reflection/message.h" + +namespace upb { + +typedef upb_MessageValue MessageValue; + +} // namespace upb + +#endif // UPB_REFLECTION_MESSAGE_HPP_ diff --git a/upb/reflection/message_def.c b/upb/reflection/message_def.c new file mode 100644 index 0000000000..82fb544926 --- /dev/null +++ b/upb/reflection/message_def.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/message_def.h" + +#include "upb/mini_table.h" +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/extension_range.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/file_def.h" +#include "upb/reflection/oneof_def.h" + +// Must be last. +#include "upb/port_def.inc" + +struct upb_MessageDef { + const google_protobuf_MessageOptions* opts; + const upb_MiniTable* layout; + const upb_FileDef* file; + const upb_MessageDef* containing_type; + const char* full_name; + + // Tables for looking up fields by number and name. + upb_inttable itof; + upb_strtable ntof; + + /* All nested defs. + * MEM: We could save some space here by putting nested defs in a contiguous + * region and calculating counts from offsets or vice-versa. */ + const upb_FieldDef* fields; + const upb_OneofDef* oneofs; + const upb_ExtensionRange* ext_ranges; + const upb_MessageDef* nested_msgs; + const upb_EnumDef* nested_enums; + const upb_FieldDef* nested_exts; + int field_count; + int real_oneof_count; + int oneof_count; + int ext_range_count; + int nested_msg_count; + int nested_enum_count; + int nested_ext_count; + bool in_message_set; + upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +static void assign_msg_wellknowntype(upb_MessageDef* m) { + const char* name = upb_MessageDef_FullName(m); + if (name == NULL) { + m->well_known_type = kUpb_WellKnown_Unspecified; + return; + } + if (!strcmp(name, "google.protobuf.Any")) { + m->well_known_type = kUpb_WellKnown_Any; + } else if (!strcmp(name, "google.protobuf.FieldMask")) { + m->well_known_type = kUpb_WellKnown_FieldMask; + } else if (!strcmp(name, "google.protobuf.Duration")) { + m->well_known_type = kUpb_WellKnown_Duration; + } else if (!strcmp(name, "google.protobuf.Timestamp")) { + m->well_known_type = kUpb_WellKnown_Timestamp; + } else if (!strcmp(name, "google.protobuf.DoubleValue")) { + m->well_known_type = kUpb_WellKnown_DoubleValue; + } else if (!strcmp(name, "google.protobuf.FloatValue")) { + m->well_known_type = kUpb_WellKnown_FloatValue; + } else if (!strcmp(name, "google.protobuf.Int64Value")) { + m->well_known_type = kUpb_WellKnown_Int64Value; + } else if (!strcmp(name, "google.protobuf.UInt64Value")) { + m->well_known_type = kUpb_WellKnown_UInt64Value; + } else if (!strcmp(name, "google.protobuf.Int32Value")) { + m->well_known_type = kUpb_WellKnown_Int32Value; + } else if (!strcmp(name, "google.protobuf.UInt32Value")) { + m->well_known_type = kUpb_WellKnown_UInt32Value; + } else if (!strcmp(name, "google.protobuf.BoolValue")) { + m->well_known_type = kUpb_WellKnown_BoolValue; + } else if (!strcmp(name, "google.protobuf.StringValue")) { + m->well_known_type = kUpb_WellKnown_StringValue; + } else if (!strcmp(name, "google.protobuf.BytesValue")) { + m->well_known_type = kUpb_WellKnown_BytesValue; + } else if (!strcmp(name, "google.protobuf.Value")) { + m->well_known_type = kUpb_WellKnown_Value; + } else if (!strcmp(name, "google.protobuf.ListValue")) { + m->well_known_type = kUpb_WellKnown_ListValue; + } else if (!strcmp(name, "google.protobuf.Struct")) { + m->well_known_type = kUpb_WellKnown_Struct; + } else { + m->well_known_type = kUpb_WellKnown_Unspecified; + } +} + +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) { + return (upb_MessageDef*)&m[i]; +} + +const google_protobuf_MessageOptions* upb_MessageDef_Options( + const upb_MessageDef* m) { + return m->opts; +} + +bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { + return m->opts != (void*)kUpbDefOptDefault; +} + +const char* upb_MessageDef_FullName(const upb_MessageDef* m) { + return m->full_name; +} + +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { + return m->file; +} + +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { + return m->containing_type; +} + +const char* upb_MessageDef_Name(const upb_MessageDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); +} + +upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { + return upb_FileDef_Syntax(m->file); +} + +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i) { + upb_value val; + return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) + : NULL; +} + +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } + + return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); +} + +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } + + return _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); +} + +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t len, + upb_value v, upb_Arena* a) { + return upb_strtable_insert(&m->ntof, name, len, v, a); +} + +bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t len, + const upb_FieldDef** out_f, + const upb_OneofDef** out_o) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; + } + + const upb_FieldDef* f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + const upb_OneofDef* o = _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); + if (out_f) *out_f = f; + if (out_o) *out_o = o; + return f || o; /* False if this was a JSON name. */ +} + +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + const upb_FieldDef* f; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } + + f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + if (!f) f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD_JSONNAME); + + return f; +} + +int upb_MessageDef_numfields(const upb_MessageDef* m) { return m->field_count; } + +int upb_MessageDef_numoneofs(const upb_MessageDef* m) { return m->oneof_count; } + +int upb_MessageDef_numrealoneofs(const upb_MessageDef* m) { + return m->real_oneof_count; +} + +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { + return m->ext_range_count; +} + +int upb_MessageDef_FieldCount(const upb_MessageDef* m) { + return m->field_count; +} + +int upb_MessageDef_OneofCount(const upb_MessageDef* m) { + return m->oneof_count; +} + +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { + return m->nested_msg_count; +} + +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { + return m->nested_enum_count; +} + +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { + return m->nested_ext_count; +} + +int upb_MessageDef_realoneofcount(const upb_MessageDef* m) { + return m->real_oneof_count; +} + +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { + return m->layout; +} + +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->ext_range_count); + return _upb_ExtensionRange_At(m->ext_ranges, i); +} + +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->field_count); + return _upb_FieldDef_At(m->fields, i); +} + +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->oneof_count); + return _upb_OneofDef_At(m->oneofs, i); +} + +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_msg_count); + return &m->nested_msgs[i]; +} + +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->nested_enum_count); + return _upb_EnumDef_At(m->nested_enums, i); +} + +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_ext_count); + return _upb_FieldDef_At(m->nested_exts, i); +} + +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { + return m->well_known_type; +} + +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m) { + return m->in_message_set; +} + +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); +} + +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); +} + +bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_map_entry(upb_MessageDef_Options(m)); +} + +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(m)); +} + +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) { + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i); + _upb_FieldDef_Resolve(ctx, upb_MessageDef_FullName(m), f); + } + + m->in_message_set = false; + for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { + upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i); + _upb_FieldDef_Resolve(ctx, upb_MessageDef_FullName(m), ext); + if (upb_FieldDef_Type(ext) == kUpb_FieldType_Message && + upb_FieldDef_Label(ext) == kUpb_Label_Optional && + upb_FieldDef_MessageSubDef(ext) == m && + google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(upb_FieldDef_ContainingType(ext)))) { + m->in_message_set = true; + } + } + + if (!ctx->layout) _upb_FieldDef_MakeLayout(ctx, m); + + for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) { + upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); + _upb_MessageDef_Resolve(ctx, n); + } +} + +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f) { + const int32_t field_number = upb_FieldDef_Number(f); + + if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { + _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); + } + + const char* json_name = upb_FieldDef_JsonName(f); + const char* shortname = upb_FieldDef_Name(f); + const size_t shortnamelen = strlen(shortname); + + upb_value v = upb_value_constptr(f); + + upb_value existing_v; + if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { + _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); + } + + const upb_value field_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD); + bool ok = + _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + if (strcmp(shortname, json_name) != 0) { + if (upb_strtable_lookup(&m->ntof, json_name, &v)) { + _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); + } + + const size_t json_size = strlen(json_name); + const upb_value json_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD_JSONNAME); + ok = _upb_MessageDef_Insert(m, json_name, json_size, json_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } + + if (upb_inttable_lookup(&m->itof, field_number, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); + } + + ok = upb_inttable_insert(&m->itof, field_number, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +static void msgdef_create_nested(upb_DefBuilder* ctx, + const google_protobuf_DescriptorProto* msg_proto, + upb_MessageDef* m) { + size_t n; + + const google_protobuf_EnumDescriptorProto* const* enums = + google_protobuf_DescriptorProto_enum_type(msg_proto, &n); + m->nested_enum_count = n; + m->nested_enums = _upb_EnumDefs_New(ctx, n, enums, m); + + const google_protobuf_FieldDescriptorProto* const* exts = + google_protobuf_DescriptorProto_extension(msg_proto, &n); + m->nested_ext_count = n; + m->nested_exts = _upb_FieldDefs_New(ctx, n, exts, m->full_name, m, true); + + const google_protobuf_DescriptorProto* const* msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + m->nested_msg_count = n; + m->nested_msgs = _upb_MessageDefs_New(ctx, n, msgs, m); +} + +static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_DescriptorProto* msg_proto, + const upb_MessageDef* containing_type, + const upb_MessageDef* _m) { + upb_MessageDef* m = (upb_MessageDef*)_m; + const google_protobuf_OneofDescriptorProto* const* oneofs; + const google_protobuf_FieldDescriptorProto* const* fields; + const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; + size_t n_oneof, n_field, n_ext_range; + upb_StringView name; + + // Must happen before _upb_DefBuilder_Add() + m->file = _upb_DefBuilder_File(ctx); + + m->containing_type = containing_type; + + name = google_protobuf_DescriptorProto_name(msg_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + + m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG)); + + oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); + fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); + ext_ranges = + google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); + + bool ok = upb_inttable_init(&m->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + if (ctx->layout) { + /* create_fielddef() below depends on this being set. */ + UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count); + m->layout = ctx->layout->msgs[ctx->msg_count++]; + UPB_ASSERT(n_field == m->layout->field_count); + } else { + /* Allocate now (to allow cross-linking), populate later. */ + m->layout = _upb_DefBuilder_Alloc( + ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); + } + + UBP_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); + + m->oneof_count = n_oneof; + m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); + + m->field_count = n_field; + m->fields = _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, false); + + m->ext_range_count = n_ext_range; + m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); + + const size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); + m->real_oneof_count = m->oneof_count - synthetic_count; + + assign_msg_wellknowntype(m); + upb_inttable_compact(&m->itof, ctx->arena); + msgdef_create_nested(ctx, msg_proto, m); +} + +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New( + upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); + + const char* name = containing_type ? containing_type->full_name + : _upb_FileDef_RawPackage(ctx->file); + upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); + for (int i = 0; i < n; i++) { + create_msgdef(ctx, name, protos[i], containing_type, &m[i]); + } + return m; +} diff --git a/upb/reflection/message_def.h b/upb/reflection/message_def.h new file mode 100644 index 0000000000..d8b8382128 --- /dev/null +++ b/upb/reflection/message_def.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_MESSAGE_DEF_H_ +#define UPB_REFLECTION_MESSAGE_DEF_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port_def.inc" + +// Well-known field tag numbers for map-entry messages. +#define kUpb_MapEntry_KeyFieldNumber 1 +#define kUpb_MapEntry_ValueFieldNumber 2 + +// Well-known field tag numbers for Any messages. +#define kUpb_Any_TypeFieldNumber 1 +#define kUpb_Any_ValueFieldNumber 2 + +// Well-known field tag numbers for duration messages. +#define kUpb_Duration_SecondsFieldNumber 1 +#define kUpb_Duration_NanosFieldNumber 2 + +// Well-known field tag numbers for timestamp messages. +#define kUpb_Timestamp_SecondsFieldNumber 1 +#define kUpb_Timestamp_NanosFieldNumber 2 + +// All the different kind of well known type messages. For simplicity of check, +// number wrappers and string wrappers are grouped together. Make sure the +// order and number of these groups are not changed. +typedef enum { + kUpb_WellKnown_Unspecified, + kUpb_WellKnown_Any, + kUpb_WellKnown_FieldMask, + kUpb_WellKnown_Duration, + kUpb_WellKnown_Timestamp, + + // number wrappers + kUpb_WellKnown_DoubleValue, + kUpb_WellKnown_FloatValue, + kUpb_WellKnown_Int64Value, + kUpb_WellKnown_UInt64Value, + kUpb_WellKnown_Int32Value, + kUpb_WellKnown_UInt32Value, + + // string wrappers + kUpb_WellKnown_StringValue, + kUpb_WellKnown_BytesValue, + kUpb_WellKnown_BoolValue, + kUpb_WellKnown_Value, + kUpb_WellKnown_ListValue, + kUpb_WellKnown_Struct, +} upb_WellKnown; + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m); + +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i); +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m); + +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i); +int upb_MessageDef_FieldCount(const upb_MessageDef* m); + +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m); + +// Returns a field by either JSON name or regular proto name. +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName( + const upb_MessageDef* m, const char* name) { + return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name)); +} + +// Lookup of either field or oneof by name. Returns whether either was found. +// If the return is true, then the found def will be set, and the non-found +// one set to NULL. +bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t size, + const upb_FieldDef** f, + const upb_OneofDef** o); +UPB_INLINE bool upb_MessageDef_FindByName(const upb_MessageDef* m, + const char* name, + const upb_FieldDef** f, + const upb_OneofDef** o) { + return upb_MessageDef_FindByNameWithSize(m, name, strlen(name), f, o); +} + +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name); +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i); +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name); +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +const char* upb_MessageDef_FullName(const upb_MessageDef* m); +bool upb_MessageDef_HasOptions(const upb_MessageDef* m); +bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m); +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m); +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m); +const char* upb_MessageDef_Name(const upb_MessageDef* m); + +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i); +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i); +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i); + +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m); +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); + +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i); +int upb_MessageDef_OneofCount(const upb_MessageDef* m); + +const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m); +upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m); +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i); +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m); +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t size, + upb_value v, upb_Arena* a); +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f); +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m); + +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New( + upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, + const upb_MessageDef* containing_type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_MESSAGE_DEF_H_ */ diff --git a/upb/reflection/method_def.c b/upb/reflection/method_def.c new file mode 100644 index 0000000000..aa9001232a --- /dev/null +++ b/upb/reflection/method_def.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/method_def.h" + +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/service_def.h" + +// Must be last. +#include "upb/port_def.inc" + +struct upb_MethodDef { + const google_protobuf_MethodOptions* opts; + upb_ServiceDef* service; + const char* full_name; + const upb_MessageDef* input_type; + const upb_MessageDef* output_type; + int index; + bool client_streaming; + bool server_streaming; +}; + +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i) { + return (upb_MethodDef*)&m[i]; +} + +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { + return m->service; +} + +const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m) { + return m->opts; +} + +bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { + return m->opts != (void*)kUpbDefOptDefault; +} + +const char* upb_MethodDef_FullName(const upb_MethodDef* m) { + return m->full_name; +} + +const char* upb_MethodDef_Name(const upb_MethodDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); +} + +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } + +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { + return m->input_type; +} + +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { + return m->output_type; +} + +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { + return m->client_streaming; +} + +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { + return m->server_streaming; +} + +static void create_method(upb_DefBuilder* ctx, + const google_protobuf_MethodDescriptorProto* method_proto, + upb_ServiceDef* s, upb_MethodDef* m) { + upb_StringView name = google_protobuf_MethodDescriptorProto_name(method_proto); + + m->service = s; + m->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_ServiceDef_FullName(s), name); + m->client_streaming = + google_protobuf_MethodDescriptorProto_client_streaming(method_proto); + m->server_streaming = + google_protobuf_MethodDescriptorProto_server_streaming(method_proto); + m->input_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_input_type(method_proto), UPB_DEFTYPE_MSG); + m->output_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG); + + UBP_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, + method_proto); +} + +// Allocate and initialize an array of |n| method defs belonging to |s|. +upb_MethodDef* _upb_MethodDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s) { + upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); + for (int i = 0; i < n; i++) { + create_method(ctx, protos[i], s, &m[i]); + m[i].index = i; + } + return m; +} diff --git a/upb/reflection/method_def.h b/upb/reflection/method_def.h new file mode 100644 index 0000000000..3123747c52 --- /dev/null +++ b/upb/reflection/method_def.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_METHOD_DEF_H_ +#define UPB_REFLECTION_METHOD_DEF_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m); +const char* upb_MethodDef_FullName(const upb_MethodDef* m); +bool upb_MethodDef_HasOptions(const upb_MethodDef* m); +int upb_MethodDef_Index(const upb_MethodDef* m); +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); +const char* upb_MethodDef_Name(const upb_MethodDef* m); +const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m); +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i); + +// Allocate and initialize an array of |n| method defs owned by |s|. +upb_MethodDef* _upb_MethodDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_METHOD_DEF_H_ */ diff --git a/upb/internal/mini_descriptor.c b/upb/reflection/mini_descriptor_encode.c similarity index 89% rename from upb/internal/mini_descriptor.c rename to upb/reflection/mini_descriptor_encode.c index 74776e28ca..3a7a0d55ac 100644 --- a/upb/internal/mini_descriptor.c +++ b/upb/reflection/mini_descriptor_encode.c @@ -25,9 +25,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "upb/internal/mini_descriptor.h" +#include "upb/reflection/mini_descriptor_encode.h" #include "upb/mini_table.h" +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/enum_value_def.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/file_def.h" +#include "upb/reflection/message_def.h" +#include "upb/reflection/oneof_def.h" // Must be last. #include "upb/port_def.inc" @@ -233,3 +241,19 @@ const char* _upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, return s.buf; } + +/******************************************************************************/ + +const char* upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e, upb_Arena* a) { + return _upb_EnumDef_MiniDescriptor(e, a); +} + +const char* upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, + upb_Arena* a) { + return _upb_MiniDescriptor_EncodeField(f, a); +} + +const char* upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, + upb_Arena* a) { + return _upb_MiniDescriptor_EncodeMessage(m, a); +} diff --git a/upb/internal/mini_descriptor.h b/upb/reflection/mini_descriptor_encode.h similarity index 76% rename from upb/internal/mini_descriptor.h rename to upb/reflection/mini_descriptor_encode.h index 487a996bfa..f197ce7b99 100644 --- a/upb/internal/mini_descriptor.h +++ b/upb/reflection/mini_descriptor_encode.h @@ -25,10 +25,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef UPB_INTERNAL_MINI_DESCRIPTOR_H_ -#define UPB_INTERNAL_MINI_DESCRIPTOR_H_ +#ifndef UPB_REFLECTION_MINI_DESCRIPTOR_ENCODE_H_ +#define UPB_REFLECTION_MINI_DESCRIPTOR_ENCODE_H_ -#include "upb/mini_descriptor.h" +#include "upb/reflection/common.h" // Must be last. #include "upb/port_def.inc" @@ -37,6 +37,18 @@ extern "C" { #endif +// Creates and returns a mini descriptor string for an enum, or NULL on error. +const char* upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e, upb_Arena* a); + +// Creates and returns a mini descriptor string for a field, or NULL on error. +const char* upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, upb_Arena* a); + +// Creates and returns a mini descriptor string for a message, or NULL on error. +const char* upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, + upb_Arena* a); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + // Creates and returns a mini descriptor string for an enum, or NULL on error. // If the values in the enum happen to be defined in ascending order (when cast // to uint32_t) then |sorted| should be NULL. Otherwise it must point to an @@ -59,4 +71,4 @@ const char* _upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, #include "upb/port_undef.inc" -#endif /* UPB_INTERNAL_MINI_DESCRIPTOR_H_ */ +#endif /* UPB_REFLECTION_MINI_DESCRIPTOR_ENCODE_H_ */ diff --git a/upb/reflection/oneof_def.c b/upb/reflection/oneof_def.c new file mode 100644 index 0000000000..296d8f817b --- /dev/null +++ b/upb/reflection/oneof_def.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/oneof_def.h" + +#include +#include +#include + +#include "upb/mini_table.h" +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/message_def.h" + +// Must be last. +#include "upb/port_def.inc" + +struct upb_OneofDef { + const google_protobuf_OneofOptions* opts; + const upb_MessageDef* parent; + const char* full_name; + int field_count; + bool synthetic; + const upb_FieldDef** fields; + upb_strtable ntof; // lookup a field by name + upb_inttable itof; // lookup a field by number (index) +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { + return (upb_OneofDef*)&o[i]; +} + +const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o) { + return o->opts; +} + +bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { + return o->opts != (void*)kUpbDefOptDefault; +} + +const char* upb_OneofDef_FullName(const upb_OneofDef* o) { + return o->full_name; +} + +const char* upb_OneofDef_Name(const upb_OneofDef* o) { + return _upb_DefBuilder_FullToShort(o->full_name); +} + +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { + return o->parent; +} + +int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } + +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { + UPB_ASSERT(i < o->field_count); + return o->fields[i]; +} + +int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } + +uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { + // Compute index in our parent's array. + return o - upb_MessageDef_Oneof(o->parent, 0); +} + +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } + +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, size, &val) + ? upb_value_getptr(val) + : NULL; +} + +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name) { + return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); +} + +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num) { + upb_value val; + return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) + : NULL; +} + +bool _upb_OneofDef_Insert(upb_OneofDef* o, const upb_FieldDef* f, + const char* name, size_t size, upb_Arena* a) { + o->field_count++; + if (_upb_FieldDef_IsProto3Optional(f)) o->synthetic = true; + + const int number = upb_FieldDef_Number(f); + const upb_value v = upb_value_constptr(f); + return upb_inttable_insert(&o->itof, number, v, a) && + upb_strtable_insert(&o->ntof, name, size, v, a); +} + +// Returns the synthetic count. +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { + int synthetic_count = 0; + + for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { + upb_OneofDef* o = (upb_OneofDef*)upb_MessageDef_Oneof(m, i); + + if (o->synthetic && o->field_count != 1) { + _upb_DefBuilder_Errf(ctx, + "Synthetic oneofs must have one field, not %d: %s", + o->field_count, upb_OneofDef_Name(o)); + } + + if (o->synthetic) { + synthetic_count++; + } else if (synthetic_count != 0) { + _upb_DefBuilder_Errf( + ctx, "Synthetic oneofs must be after all other oneofs: %s", + upb_OneofDef_Name(o)); + } + + o->fields = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); + o->field_count = 0; + } + + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); + if (o) { + o->fields[o->field_count++] = f; + } + } + + return synthetic_count; +} + +static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, + const google_protobuf_OneofDescriptorProto* oneof_proto, + const upb_OneofDef* _o) { + upb_OneofDef* o = (upb_OneofDef*)_o; + upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); + + o->parent = m; + o->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_MessageDef_FullName(m), name); + o->field_count = 0; + o->synthetic = false; + + UBP_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + + if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); + } + + upb_value v = _upb_DefType_Pack(o, UPB_DEFTYPE_ONEOF); + bool ok = _upb_MessageDef_Insert(m, name.data, name.size, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_inttable_init(&o->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&o->ntof, 4, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +// Allocate and initialize an array of |n| oneof defs. +upb_OneofDef* _upb_OneofDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m) { + _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); + + upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); + for (int i = 0; i < n; i++) { + create_oneofdef(ctx, m, protos[i], &o[i]); + } + return o; +} diff --git a/upb/reflection/oneof_def.h b/upb/reflection/oneof_def.h new file mode 100644 index 0000000000..5116e9e4e9 --- /dev/null +++ b/upb/reflection/oneof_def.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ONEOF_DEF_H_ +#define UPB_REFLECTION_ONEOF_DEF_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o); +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i); +int upb_OneofDef_FieldCount(const upb_OneofDef* o); +const char* upb_OneofDef_FullName(const upb_OneofDef* o); +bool upb_OneofDef_HasOptions(const upb_OneofDef* o); +uint32_t upb_OneofDef_Index(const upb_OneofDef* o); +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o); +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name); +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size); +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num); +const char* upb_OneofDef_Name(const upb_OneofDef* o); +int upb_OneofDef_numfields(const upb_OneofDef* o); +const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i); +bool _upb_OneofDef_Insert(upb_OneofDef* o, const upb_FieldDef* f, + const char* name, size_t size, upb_Arena* a); + +// Allocate and initialize an array of |n| oneof defs owned by |m|. +upb_OneofDef* _upb_OneofDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m); + +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_ONEOF_DEF_H_ */ diff --git a/upb/reflection/service_def.c b/upb/reflection/service_def.c new file mode 100644 index 0000000000..6b2d69d48e --- /dev/null +++ b/upb/reflection/service_def.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/service_def.h" + +#include "upb/reflection/def_builder.h" +#include "upb/reflection/def_type.h" +#include "upb/reflection/file_def.h" +#include "upb/reflection/method_def.h" + +// Must be last. +#include "upb/port_def.inc" + +struct upb_ServiceDef { + const google_protobuf_ServiceOptions* opts; + const upb_FileDef* file; + const char* full_name; + upb_MethodDef* methods; + int method_count; + int index; +}; + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { + return (upb_ServiceDef*)&s[index]; +} + +const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s) { + return s->opts; +} + +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { + return s->opts != (void*)kUpbDefOptDefault; +} + +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { + return s->full_name; +} + +const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { + return _upb_DefBuilder_FullToShort(s->full_name); +} + +int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } + +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { + return s->file; +} + +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { + return s->method_count; +} + +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { + return (i < 0 || i >= s->method_count) ? NULL + : _upb_MethodDef_At(s->methods, i); +} + +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name) { + for (int i = 0; i < s->method_count; i++) { + const upb_MethodDef* m = _upb_MethodDef_At(s->methods, i); + if (strcmp(name, upb_MethodDef_Name(m)) == 0) { + return m; + } + } + return NULL; +} + +static void create_service(upb_DefBuilder* ctx, + const google_protobuf_ServiceDescriptorProto* svc_proto, + upb_ServiceDef* s) { + upb_StringView name; + size_t n; + + // Must happen before _upb_DefBuilder_Add() + s->file = _upb_DefBuilder_File(ctx); + + name = google_protobuf_ServiceDescriptorProto_name(svc_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + const char* package = _upb_FileDef_RawPackage(s->file); + s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); + _upb_DefBuilder_Add(ctx, s->full_name, + _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); + + const google_protobuf_MethodDescriptorProto* const* methods = + google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); + s->method_count = n; + s->methods = _upb_MethodDefs_New(ctx, n, methods, s); + + UBP_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, + svc_proto); +} + +upb_ServiceDef* _upb_ServiceDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_ServiceDescriptorProto* const* protos) { + _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); + + upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); + for (int i = 0; i < n; i++) { + create_service(ctx, protos[i], &s[i]); + s[i].index = i; + } + return s; +} diff --git a/upb/reflection/service_def.h b/upb/reflection/service_def.h new file mode 100644 index 0000000000..d265a507c0 --- /dev/null +++ b/upb/reflection/service_def.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_SERVICE_DEF_H_ +#define UPB_REFLECTION_SERVICE_DEF_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s); +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name); +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s); +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s); +int upb_ServiceDef_Index(const upb_ServiceDef* s); +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i); +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); +const char* upb_ServiceDef_Name(const upb_ServiceDef* s); +const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int i); + +// Allocate and initialize an array of |n| service defs. +upb_ServiceDef* _upb_ServiceDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_ServiceDescriptorProto* const* protos); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_SERVICE_DEF_H_ */ diff --git a/upbc/code_generator_request.c b/upbc/code_generator_request.c index cd7f5d1c72..ce6227d5a1 100644 --- a/upbc/code_generator_request.c +++ b/upbc/code_generator_request.c @@ -31,8 +31,9 @@ #include #include "google/protobuf/compiler/plugin.upb.h" -#include "upb/mini_descriptor.h" #include "upb/mini_table.h" +#include "upb/reflection/def.h" +#include "upb/reflection/mini_descriptor_encode.h" // Must be last. #include "upb/port_def.inc" diff --git a/upbc/code_generator_request.h b/upbc/code_generator_request.h index 747d98d84d..03deb29fea 100644 --- a/upbc/code_generator_request.h +++ b/upbc/code_generator_request.h @@ -28,7 +28,7 @@ #ifndef UPBC_CODE_GENERATOR_REQUEST_H_ #define UPBC_CODE_GENERATOR_REQUEST_H_ -#include "upb/def.h" +#include "upb/reflection/def.h" #include "upb/upb.h" #include "upbc/code_generator_request.upb.h" diff --git a/upbc/protoc-gen-upbdev.cc b/upbc/protoc-gen-upbdev.cc index e711ec75b5..a320c89fdc 100644 --- a/upbc/protoc-gen-upbdev.cc +++ b/upbc/protoc-gen-upbdev.cc @@ -32,7 +32,7 @@ #include "google/protobuf/compiler/plugin.upbdefs.h" #include "upb/json_decode.h" #include "upb/json_encode.h" -#include "upb/mini_descriptor.h" +#include "upb/reflection/def.h" #include "upb/upb.h" #include "upbc/code_generator_request.h" #include "upbc/code_generator_request.upb.h"