From 0be33b1e3c32e2feabfb295dd54fdf484a68658d Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 22 Oct 2021 13:15:00 -0700 Subject: [PATCH 1/3] WIP. --- upb/util/BUILD | 40 ++++ upb/util/def_to_proto.c | 498 ++++++++++++++++++++++++++++++++++++++++ upb/util/def_to_proto.h | 61 +++++ 3 files changed, 599 insertions(+) create mode 100644 upb/util/def_to_proto.c create mode 100644 upb/util/def_to_proto.h diff --git a/upb/util/BUILD b/upb/util/BUILD index 65a4009dae..0b8fc0be25 100644 --- a/upb/util/BUILD +++ b/upb/util/BUILD @@ -5,6 +5,46 @@ load( "upb_proto_reflection_library", ) +cc_library( + name = "def_to_proto", + srcs = ["def_to_proto.c"], + hdrs = ["def_to_proto.h"], + deps = ["//:reflection"], + visibility = ["//visibility:public"], +) + +proto_library( + name = "def_to_proto_test_proto", + srcs = [ + "def_to_proto_test.proto", + "def_to_proto_regular_import_test.proto", + "def_to_proto_public_import_test.proto", + "def_to_proto_weak_import_test.proto", + ], +) + +upb_proto_library( + name = "def_to_proto_test_upb_proto", + deps = ["def_to_proto_test_proto"], +) + +upb_proto_reflection_library( + name = "def_to_proto_test_upb_proto_reflection", + deps = ["def_to_proto_test_proto"], +) + +cc_test( + name = "def_to_proto_test", + srcs = ["def_to_proto_test.cc"], + deps = [ + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest_main", + ":def_to_proto", + ":def_to_proto_test_upb_proto", + ":def_to_proto_test_upb_proto_reflection", + ], +) + cc_library( name = "required_fields", srcs = ["required_fields.c"], diff --git a/upb/util/def_to_proto.c b/upb/util/def_to_proto.c new file mode 100644 index 0000000000..4c5c0afbf8 --- /dev/null +++ b/upb/util/def_to_proto.c @@ -0,0 +1,498 @@ +/* + * 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/util/def_to_proto.h" + +#include +#include +#include +#include "upb/reflection.h" + +/* Must be last. */ +#include "upb/port_def.inc" + +typedef struct { + upb_arena *arena; + jmp_buf err; +} toproto_ctx; + +#define CHK_OOM(val) if (!(val)) UPB_LONGJMP(ctx->err, 1); + +// We want to copy the options verbatim into the destination options proto. +// We use serialize+parse as our deep copy. +#define SET_OPTIONS(proto, desc_type, options_type, src) \ + { \ + size_t size; \ + /* MEM: could use a temporary arena here instead. */ \ + char *pb = \ + google_protobuf_##options_type##_serialize(src, ctx->arena, &size); \ + CHK_OOM(pb); \ + google_protobuf_##options_type *dst = \ + google_protobuf_##options_type##_parse(pb, size, ctx->arena); \ + CHK_OOM(dst); \ + google_protobuf_##desc_type##_set_options(proto, dst); \ + } + +static upb_strview strviewdup2(toproto_ctx *ctx, upb_strview str) { + char *p = upb_arena_malloc(ctx->arena, str.size); + CHK_OOM(p); + memcpy(p, str.data, str.size); + return (upb_strview){.data = p, .size = str.size}; +} + +static upb_strview strviewdup(toproto_ctx *ctx, const char *s) { + return strviewdup2(ctx, (upb_strview){.data = s, .size = strlen(s)}); +} + +static upb_strview qual_dup(toproto_ctx *ctx, const char *s) { + size_t n = strlen(s); + char *p = upb_arena_malloc(ctx->arena, n + 1); + CHK_OOM(p); + p[0] = '.'; + memcpy(p + 1, s, n); + return (upb_strview){.data = p, .size = n + 1}; +} + +UPB_PRINTF(2, 3) +static upb_strview printf_dup(toproto_ctx *ctx, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + size_t n = vsnprintf(NULL, 0, fmt, args); + va_end(args); + + char *p = upb_arena_malloc(ctx->arena, n + 1); + CHK_OOM(p); + + va_start(args, fmt); + vsnprintf(p, n, fmt, args); + va_end(args); + return (upb_strview){.data = p, .size = n}; +} + +static upb_strview default_string(toproto_ctx *ctx, const upb_fielddef *f) { + upb_msgval d = upb_fielddef_default(f); + switch (upb_fielddef_type(f)) { + case UPB_TYPE_BOOL: + return strviewdup(ctx, d.bool_val ? "true" : "false"); + case UPB_TYPE_ENUM: // TODO: encode as string? + case UPB_TYPE_INT64: + return printf_dup(ctx, "%" PRId64, d.int64_val); + case UPB_TYPE_UINT64: + return printf_dup(ctx, "%" PRIu64, d.uint64_val); + case UPB_TYPE_INT32: + return printf_dup(ctx, "%" PRId32, d.int32_val); + case UPB_TYPE_UINT32: + return printf_dup(ctx, "%" PRIu32, d.uint32_val); + case UPB_TYPE_FLOAT: + return printf_dup(ctx, "%.9g", d.float_val); + case UPB_TYPE_DOUBLE: + return printf_dup(ctx, "%.17g", d.double_val); + case UPB_TYPE_STRING: + return strviewdup2(ctx, d.str_val); + case UPB_TYPE_BYTES: + return strviewdup2(ctx, d.str_val); // XXX C-escape + default: + UPB_UNREACHABLE(); + } +} + +static google_protobuf_FieldDescriptorProto *fielddef_toproto( + toproto_ctx *ctx, const upb_fielddef *f) { + google_protobuf_FieldDescriptorProto *proto = + google_protobuf_FieldDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_FieldDescriptorProto_set_name( + proto, strviewdup(ctx, upb_fielddef_name(f))); + google_protobuf_FieldDescriptorProto_set_number(proto, + upb_fielddef_number(f)); + google_protobuf_FieldDescriptorProto_set_label(proto, upb_fielddef_label(f)); + google_protobuf_FieldDescriptorProto_set_type(proto, + upb_fielddef_descriptortype(f)); + + // TODO: json_name (needs has_json_name from fielddef). + + if (upb_fielddef_issubmsg(f)) { + google_protobuf_FieldDescriptorProto_set_type_name( + proto, qual_dup(ctx, upb_msgdef_fullname(upb_fielddef_msgsubdef(f)))); + } else if (upb_fielddef_type(f) == UPB_TYPE_ENUM) { + google_protobuf_FieldDescriptorProto_set_type_name( + proto, qual_dup(ctx, upb_enumdef_fullname(upb_fielddef_enumsubdef(f)))); + } + + if (upb_fielddef_isextension(f)) { + google_protobuf_FieldDescriptorProto_set_extendee( + proto, qual_dup(ctx, upb_msgdef_fullname(upb_fielddef_containingtype(f)))); + } + + if (upb_fielddef_hasdefault(f)) { + google_protobuf_FieldDescriptorProto_set_default_value( + proto, default_string(ctx, f)); + } + + const upb_oneofdef *o = upb_fielddef_containingoneof(f); + if (o) { + google_protobuf_FieldDescriptorProto_set_oneof_index(proto, + upb_oneofdef_index(o)); + } + + if (_upb_fielddef_proto3optional(f)) { + google_protobuf_FieldDescriptorProto_set_proto3_optional(proto, true); + } + + if (upb_fielddef_hasoptions(f)) { + SET_OPTIONS(proto, FieldDescriptorProto, FieldOptions, + upb_fielddef_options(f)); + } + + return proto; +} + +static google_protobuf_OneofDescriptorProto *oneofdef_toproto( + toproto_ctx *ctx, const upb_oneofdef *o) { + google_protobuf_OneofDescriptorProto *proto = + google_protobuf_OneofDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_OneofDescriptorProto_set_name( + proto, strviewdup(ctx, upb_oneofdef_name(o))); + + if (upb_oneofdef_hasoptions(o)) { + SET_OPTIONS(proto, OneofDescriptorProto, OneofOptions, + upb_oneofdef_options(o)); + } + + return proto; +} + +static google_protobuf_EnumValueDescriptorProto *enumvaldef_toproto( + toproto_ctx *ctx, const upb_enumvaldef *e) { + google_protobuf_EnumValueDescriptorProto *proto = + google_protobuf_EnumValueDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_EnumValueDescriptorProto_set_name( + proto, strviewdup(ctx, upb_enumvaldef_name(e))); + google_protobuf_EnumValueDescriptorProto_set_number(proto, + upb_enumvaldef_number(e)); + + if (upb_enumvaldef_hasoptions(e)) { + SET_OPTIONS(proto, EnumValueDescriptorProto, EnumValueOptions, + upb_enumvaldef_options(e)); + } + + return proto; +} + +static google_protobuf_EnumDescriptorProto *enumdef_toproto( + toproto_ctx *ctx, const upb_enumdef *e) { + google_protobuf_EnumDescriptorProto *proto = + google_protobuf_EnumDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_EnumDescriptorProto_set_name( + proto, strviewdup(ctx, upb_enumdef_name(e))); + + int n; + + n = upb_enumdef_valuecount(e); + google_protobuf_EnumValueDescriptorProto **vals = + google_protobuf_EnumDescriptorProto_resize_value(proto, n, ctx->arena); + CHK_OOM(vals); + for (int i = 0; i < n; i++) { + vals[i] = enumvaldef_toproto(ctx, upb_enumdef_value(e, i)); + } + + // TODO: reserved range, reserved name + + if (upb_enumdef_hasoptions(e)) { + SET_OPTIONS(proto, EnumDescriptorProto, EnumOptions, + upb_enumdef_options(e)); + } + + return proto; +} + +static google_protobuf_DescriptorProto_ExtensionRange *extrange_toproto( + toproto_ctx *ctx, const upb_extrange *e) { + google_protobuf_DescriptorProto_ExtensionRange *proto = + google_protobuf_DescriptorProto_ExtensionRange_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_DescriptorProto_ExtensionRange_set_start( + proto, upb_extrange_start(e)); + google_protobuf_DescriptorProto_ExtensionRange_set_end(proto, + upb_extrange_end(e)); + + if (upb_extrange_hasoptions(e)) { + SET_OPTIONS(proto, DescriptorProto_ExtensionRange, ExtensionRangeOptions, + upb_extrange_options(e)); + } + + return proto; +} + +static google_protobuf_DescriptorProto *msgdef_toproto(toproto_ctx *ctx, + const upb_msgdef *m) { + google_protobuf_DescriptorProto *proto = + google_protobuf_DescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_DescriptorProto_set_name( + proto, strviewdup(ctx, upb_msgdef_name(m))); + + int n; + + n = upb_msgdef_fieldcount(m); + google_protobuf_FieldDescriptorProto **fields = + google_protobuf_DescriptorProto_resize_field(proto, n, ctx->arena); + CHK_OOM(fields); + for (int i = 0; i < n; i++) { + fields[i] = fielddef_toproto(ctx, upb_msgdef_field(m, i)); + } + + n = upb_msgdef_oneofcount(m); + google_protobuf_OneofDescriptorProto **oneofs = + google_protobuf_DescriptorProto_resize_oneof_decl(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + oneofs[i] = oneofdef_toproto(ctx, upb_msgdef_oneof(m, i)); + } + + n = upb_msgdef_nestedmsgcount(m); + google_protobuf_DescriptorProto **nested_msgs = + google_protobuf_DescriptorProto_resize_nested_type(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + nested_msgs[i] = msgdef_toproto(ctx, upb_msgdef_nestedmsg(m, i)); + } + + n = upb_msgdef_nestedenumcount(m); + google_protobuf_EnumDescriptorProto **nested_enums = + google_protobuf_DescriptorProto_resize_enum_type(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + nested_enums[i] = enumdef_toproto(ctx, upb_msgdef_nestedenum(m, i)); + } + + n = upb_msgdef_nestedextcount(m); + google_protobuf_FieldDescriptorProto **nested_exts = + google_protobuf_DescriptorProto_resize_extension(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + nested_exts[i] = fielddef_toproto(ctx, upb_msgdef_nestedext(m, i)); + } + + n = upb_msgdef_extrangecount(m); + google_protobuf_DescriptorProto_ExtensionRange **ext_ranges = + google_protobuf_DescriptorProto_resize_extension_range(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + ext_ranges[i] = extrange_toproto(ctx, upb_msgdef_extrange(m, i)); + } + + // TODO: reserved ranges and reserved names + + if (upb_msgdef_hasoptions(m)) { + SET_OPTIONS(proto, DescriptorProto, MessageOptions, upb_msgdef_options(m)); + } + + return proto; +} + +static google_protobuf_MethodDescriptorProto *methoddef_toproto( + toproto_ctx *ctx, const upb_methoddef *m) { + google_protobuf_MethodDescriptorProto *proto = + google_protobuf_MethodDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_MethodDescriptorProto_set_name( + proto, strviewdup(ctx, upb_methoddef_name(m))); + + google_protobuf_MethodDescriptorProto_set_input_type( + proto, qual_dup(ctx, upb_msgdef_fullname(upb_methoddef_inputtype(m)))); + google_protobuf_MethodDescriptorProto_set_output_type( + proto, qual_dup(ctx, upb_msgdef_fullname(upb_methoddef_outputtype(m)))); + + if (upb_methoddef_clientstreaming(m)) { + google_protobuf_MethodDescriptorProto_set_client_streaming(proto, true); + } + + if (upb_methoddef_serverstreaming(m)) { + google_protobuf_MethodDescriptorProto_set_server_streaming(proto, true); + } + + if (upb_methoddef_hasoptions(m)) { + SET_OPTIONS(proto, MethodDescriptorProto, MethodOptions, + upb_methoddef_options(m)); + } + + return proto; +} + +static google_protobuf_ServiceDescriptorProto *servicedef_toproto( + toproto_ctx *ctx, const upb_servicedef *s) { + google_protobuf_ServiceDescriptorProto *proto = + google_protobuf_ServiceDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_ServiceDescriptorProto_set_name( + proto, strviewdup(ctx, upb_servicedef_name(s))); + + size_t n = upb_servicedef_methodcount(s); + google_protobuf_MethodDescriptorProto **methods = + google_protobuf_ServiceDescriptorProto_resize_method(proto, n, + ctx->arena); + for (int i = 0; i < n; i++) { + methods[i] = methoddef_toproto(ctx, upb_servicedef_method(s, i)); + } + + if (upb_servicedef_hasoptions(s)) { + SET_OPTIONS(proto, ServiceDescriptorProto, ServiceOptions, + upb_servicedef_options(s)); + } + + return proto; +} + +static google_protobuf_FileDescriptorProto *filedef_toproto( + toproto_ctx *ctx, const upb_filedef *f) { + google_protobuf_FileDescriptorProto *proto = + google_protobuf_FileDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_FileDescriptorProto_set_name( + proto, strviewdup(ctx, upb_filedef_name(f))); + + size_t n = strlen(upb_filedef_package(f)); + if (n) { + google_protobuf_FileDescriptorProto_set_package( + proto, strviewdup(ctx, upb_filedef_package(f))); + } + + if (upb_filedef_syntax(f) == UPB_SYNTAX_PROTO3) { + google_protobuf_FileDescriptorProto_set_syntax(proto, + strviewdup(ctx, "proto3")); + } + + n = upb_filedef_depcount(f); + upb_strview *deps = + google_protobuf_FileDescriptorProto_resize_dependency(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + deps[i] = strviewdup(ctx, upb_filedef_name(upb_filedef_dep(f, i))); + } + + n = upb_filedef_publicdepcount(f); + int32_t *public_deps = + google_protobuf_FileDescriptorProto_resize_public_dependency(proto, n, + ctx->arena); + const int32_t *proto_deps = _upb_filedef_publicdepnums(f); + memcpy(public_deps, proto_deps, n * sizeof(int32_t)); + + n = upb_filedef_toplvlmsgcount(f); + google_protobuf_DescriptorProto **msgs = + google_protobuf_FileDescriptorProto_resize_message_type(proto, n, + ctx->arena); + for (int i = 0; i < n; i++) { + msgs[i] = msgdef_toproto(ctx, upb_filedef_toplvlmsg(f, i)); + } + + n = upb_filedef_toplvlenumcount(f); + google_protobuf_EnumDescriptorProto **enums = + google_protobuf_FileDescriptorProto_resize_enum_type(proto, n, + ctx->arena); + for (int i = 0; i < n; i++) { + enums[i] = enumdef_toproto(ctx, upb_filedef_toplvlenum(f, i)); + } + + n = upb_filedef_servicecount(f); + google_protobuf_ServiceDescriptorProto **services = + google_protobuf_FileDescriptorProto_resize_service(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + services[i] = servicedef_toproto(ctx, upb_filedef_service(f, i)); + } + + n = upb_filedef_toplvlextcount(f); + google_protobuf_FieldDescriptorProto **exts = + google_protobuf_FileDescriptorProto_resize_extension(proto, n, + ctx->arena); + for (int i = 0; i < n; i++) { + exts[i] = fielddef_toproto(ctx, upb_filedef_toplvlext(f, i)); + } + + if (upb_filedef_hasoptions(f)) { + SET_OPTIONS(proto, FileDescriptorProto, FileOptions, + upb_filedef_options(f)); + } + + // TODO: public & weak dependencies. + + return proto; +} + +google_protobuf_DescriptorProto *upb_MessageDef_ToProto(const upb_msgdef *m, + upb_arena *a) { + toproto_ctx ctx = {a}; + return UPB_SETJMP(ctx.err) ? NULL : msgdef_toproto(&ctx, m); +} + +google_protobuf_EnumDescriptorProto *upb_EnumDef_ToProto(const upb_enumdef *e, + upb_arena *a) { + toproto_ctx ctx = {a}; + return UPB_SETJMP(ctx.err) ? NULL : enumdef_toproto(&ctx, e); +} + +google_protobuf_EnumValueDescriptorProto *upb_EnumValueDef_ToProto( + const upb_enumvaldef *e, upb_arena *a) { + toproto_ctx ctx = {a}; + return UPB_SETJMP(ctx.err) ? NULL : enumvaldef_toproto(&ctx, e); +} + +google_protobuf_FieldDescriptorProto *upb_FieldDef_ToProto( + const upb_fielddef *f, upb_arena *a) { + toproto_ctx ctx = {a}; + return UPB_SETJMP(ctx.err) ? NULL : fielddef_toproto(&ctx, f); +} + +google_protobuf_OneofDescriptorProto *upb_OneofDef_ToProto( + const upb_oneofdef *o, upb_arena *a) { + toproto_ctx ctx = {a}; + return UPB_SETJMP(ctx.err) ? NULL : oneofdef_toproto(&ctx, o); +} + +google_protobuf_FileDescriptorProto *upb_FileDef_ToProto(const upb_filedef *f, + upb_arena *a) { + toproto_ctx ctx = {a}; + return UPB_SETJMP(ctx.err) ? NULL : filedef_toproto(&ctx, f); +} + +google_protobuf_MethodDescriptorProto *upb_MethodDef_ToProto( + const upb_methoddef *m, upb_arena *a) { + toproto_ctx ctx = {a}; + return UPB_SETJMP(ctx.err) ? NULL : methoddef_toproto(&ctx, m); +} + +google_protobuf_ServiceDescriptorProto *upb_ServiceDef_ToProto( + const upb_servicedef *s, upb_arena *a) { + toproto_ctx ctx = {a}; + return UPB_SETJMP(ctx.err) ? NULL : servicedef_toproto(&ctx, s); +} diff --git a/upb/util/def_to_proto.h b/upb/util/def_to_proto.h new file mode 100644 index 0000000000..20c8ab4c13 --- /dev/null +++ b/upb/util/def_to_proto.h @@ -0,0 +1,61 @@ +/* + * 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_UTIL_DEF_TO_PROTO_H_ +#define UPB_UTIL_DEF_TO_PROTO_H_ + +#include "upb/def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Functions for converting defs back to the equivalent descriptor proto. +// Ultimately the goal is that a round-trip proto->def->proto is lossless. +// Each function creates a +google_protobuf_DescriptorProto* upb_MessageDef_ToProto(const upb_msgdef* m, + upb_arena* a); +google_protobuf_EnumDescriptorProto* upb_EnumDef_ToProto(const upb_enumdef* e, + upb_arena* a); +google_protobuf_EnumValueDescriptorProto* upb_EnumValueDef_ToProto( + const upb_enumvaldef* e, upb_arena* a); +google_protobuf_FieldDescriptorProto* upb_FieldDef_ToProto( + const upb_fielddef* f, upb_arena* a); +google_protobuf_OneofDescriptorProto* upb_OneofDef_ToProto( + const upb_oneofdef* o, upb_arena* a); +google_protobuf_FileDescriptorProto* upb_FileDef_ToProto(const upb_filedef* f, + upb_arena* a); +google_protobuf_MethodDescriptorProto* upb_MethodDef_ToProto( + const upb_methoddef* m, upb_arena* a); +google_protobuf_ServiceDescriptorProto* upb_ServiceDef_ToProto( + const upb_servicedef* s, upb_arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_UTIL_DEF_TO_PROTO_H_ */ From d0795a29d97b87efb832223f9f631d5d9adc8676 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sun, 31 Oct 2021 20:28:37 -0700 Subject: [PATCH 2/3] Test for def_to_proto is working. --- upb/def.c | 35 +++++ upb/def.h | 4 + upb/def.hpp | 7 + upb/util/BUILD | 2 + upb/util/def_to_proto.c | 37 +++-- .../def_to_proto_public_import_test.proto | 28 ++++ .../def_to_proto_regular_import_test.proto | 28 ++++ upb/util/def_to_proto_test.cc | 127 ++++++++++++++++++ upb/util/def_to_proto_test.proto | 76 +++++++++++ upb/util/def_to_proto_weak_import_test.proto | 28 ++++ upb/util/def_to_proto_wweak_import_test.proto | 28 ++++ upbc/protoc-gen-upb.cc | 7 - 12 files changed, 386 insertions(+), 21 deletions(-) create mode 100644 upb/util/def_to_proto_public_import_test.proto create mode 100644 upb/util/def_to_proto_regular_import_test.proto create mode 100644 upb/util/def_to_proto_test.cc create mode 100644 upb/util/def_to_proto_test.proto create mode 100644 upb/util/def_to_proto_weak_import_test.proto create mode 100644 upb/util/def_to_proto_wweak_import_test.proto diff --git a/upb/def.c b/upb/def.c index e05af59047..233d7d9eb3 100644 --- a/upb/def.c +++ b/upb/def.c @@ -77,6 +77,7 @@ struct upb_fielddef { bool is_extension_; bool packed_; bool proto3_optional_; + bool has_json_name_; upb_descriptortype_t type_; upb_label_t label_; }; @@ -156,6 +157,7 @@ struct upb_filedef { const upb_filedef **deps; const int32_t* public_deps; + const int32_t* weak_deps; const upb_msgdef *top_lvl_msgs; const upb_enumdef *top_lvl_enums; const upb_fielddef *top_lvl_exts; @@ -165,6 +167,7 @@ struct upb_filedef { 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; @@ -547,6 +550,10 @@ 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; } @@ -1047,10 +1054,18 @@ int upb_filedef_publicdepcount(const upb_filedef *f) { return f->public_dep_count; } +int upb_filedef_weakdepcount(const upb_filedef *f) { + return f->weak_dep_count; +} + const int32_t *_upb_filedef_publicdepnums(const upb_filedef *f) { return f->public_deps; } +const int32_t *_upb_filedef_weakdepnums(const upb_filedef *f) { + return f->weak_deps; +} + int upb_filedef_toplvlenumcount(const upb_filedef *f) { return f->top_lvl_enum_count; } @@ -1073,6 +1088,11 @@ const upb_filedef *upb_filedef_publicdep(const upb_filedef *f, int i) { return f->deps[f->public_deps[i]]; } +const upb_filedef *upb_filedef_weakdep(const upb_filedef *f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->weak_deps[i]]; +} + const upb_msgdef *upb_filedef_toplvlmsg(const upb_filedef *f, int i) { UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); return &f->top_lvl_msgs[i]; @@ -2152,8 +2172,10 @@ static void create_fielddef( 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); @@ -2751,6 +2773,7 @@ static void build_filedef( const google_protobuf_ServiceDescriptorProto *const *services; const upb_strview *strs; const int32_t *public_deps; + const int32_t *weak_deps; size_t i, n; file->symtab = ctx->symtab; @@ -2843,6 +2866,18 @@ static void build_filedef( 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 = symtab_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) { + symtab_errf(ctx, "public_dep %d is out of range", (int)public_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; diff --git a/upb/def.h b/upb/def.h index 141affd830..7d379dc88a 100644 --- a/upb/def.h +++ b/upb/def.h @@ -121,6 +121,7 @@ upb_label_t 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_packed(const upb_fielddef *f); const upb_filedef *upb_fielddef_file(const upb_fielddef *f); @@ -354,18 +355,21 @@ const char *upb_filedef_phpnamespace(const upb_filedef *f); upb_syntax_t upb_filedef_syntax(const upb_filedef *f); int upb_filedef_depcount(const upb_filedef *f); int upb_filedef_publicdepcount(const upb_filedef *f); +int upb_filedef_weakdepcount(const upb_filedef *f); int upb_filedef_toplvlmsgcount(const upb_filedef *f); int upb_filedef_toplvlenumcount(const upb_filedef *f); int upb_filedef_toplvlextcount(const upb_filedef *f); int upb_filedef_servicecount(const upb_filedef *f); const upb_filedef *upb_filedef_dep(const upb_filedef *f, int i); const upb_filedef *upb_filedef_publicdep(const upb_filedef *f, int i); +const upb_filedef *upb_filedef_weakdep(const upb_filedef *f, int i); const upb_msgdef *upb_filedef_toplvlmsg(const upb_filedef *f, int i); const upb_enumdef *upb_filedef_toplvlenum(const upb_filedef *f, int i); const upb_fielddef *upb_filedef_toplvlext(const upb_filedef *f, int i); const upb_servicedef *upb_filedef_service(const upb_filedef *f, int i); const upb_symtab *upb_filedef_symtab(const upb_filedef *f); const int32_t *_upb_filedef_publicdepnums(const upb_filedef *f); +const int32_t *_upb_filedef_weakdepnums(const upb_filedef *f); /* upb_methoddef **************************************************************/ diff --git a/upb/def.hpp b/upb/def.hpp index cc4c16b9df..c6db8e684e 100644 --- a/upb/def.hpp +++ b/upb/def.hpp @@ -40,6 +40,7 @@ namespace upb { typedef upb_msgval MessageValue; class EnumDefPtr; +class FileDefPtr; class MessageDefPtr; class OneofDefPtr; @@ -192,6 +193,8 @@ class MessageDefPtr { const upb_msgdef* ptr() const { return ptr_; } explicit operator bool() const { return ptr_ != nullptr; } + FileDefPtr file() const; + const char* full_name() const { return upb_msgdef_fullname(ptr_); } const char* name() const { return upb_msgdef_name(ptr_); } @@ -447,6 +450,10 @@ class SymbolTable { std::unique_ptr ptr_; }; +inline FileDefPtr MessageDefPtr::file() const { + return FileDefPtr(upb_msgdef_file(ptr_)); +} + inline MessageDefPtr FieldDefPtr::message_subdef() const { return MessageDefPtr(upb_fielddef_msgsubdef(ptr_)); } diff --git a/upb/util/BUILD b/upb/util/BUILD index 0b8fc0be25..94eb9d86c0 100644 --- a/upb/util/BUILD +++ b/upb/util/BUILD @@ -39,6 +39,8 @@ cc_test( deps = [ "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_main", + "//:descriptor_upb_proto_reflection", + "@com_google_protobuf//:protobuf", ":def_to_proto", ":def_to_proto_test_upb_proto", ":def_to_proto_test_upb_proto_reflection", diff --git a/upb/util/def_to_proto.c b/upb/util/def_to_proto.c index 4c5c0afbf8..addab03397 100644 --- a/upb/util/def_to_proto.c +++ b/upb/util/def_to_proto.c @@ -79,17 +79,14 @@ static upb_strview qual_dup(toproto_ctx *ctx, const char *s) { UPB_PRINTF(2, 3) static upb_strview printf_dup(toproto_ctx *ctx, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - size_t n = vsnprintf(NULL, 0, fmt, args); - va_end(args); - - char *p = upb_arena_malloc(ctx->arena, n + 1); + const size_t max = 32; + char *p = upb_arena_malloc(ctx->arena, max); CHK_OOM(p); - + va_list args; va_start(args, fmt); - vsnprintf(p, n, fmt, args); + size_t n = vsnprintf(p, max, fmt, args); va_end(args); + UPB_ASSERT(n < max); return (upb_strview){.data = p, .size = n}; } @@ -98,7 +95,11 @@ static upb_strview default_string(toproto_ctx *ctx, const upb_fielddef *f) { switch (upb_fielddef_type(f)) { case UPB_TYPE_BOOL: return strviewdup(ctx, d.bool_val ? "true" : "false"); - case UPB_TYPE_ENUM: // TODO: encode as string? + case UPB_TYPE_ENUM: { + const upb_enumdef *e = upb_fielddef_enumsubdef(f); + const upb_enumvaldef *ev = upb_enumdef_lookupnum(e, d.int32_val); + return strviewdup(ctx, upb_enumvaldef_name(ev)); + } case UPB_TYPE_INT64: return printf_dup(ctx, "%" PRId64, d.int64_val); case UPB_TYPE_UINT64: @@ -134,7 +135,10 @@ static google_protobuf_FieldDescriptorProto *fielddef_toproto( google_protobuf_FieldDescriptorProto_set_type(proto, upb_fielddef_descriptortype(f)); - // TODO: json_name (needs has_json_name from fielddef). + if (upb_fielddef_hasjsonname(f)) { + google_protobuf_FieldDescriptorProto_set_json_name( + proto, strviewdup(ctx, upb_fielddef_jsonname(f))); + } if (upb_fielddef_issubmsg(f)) { google_protobuf_FieldDescriptorProto_set_type_name( @@ -405,8 +409,15 @@ static google_protobuf_FileDescriptorProto *filedef_toproto( int32_t *public_deps = google_protobuf_FileDescriptorProto_resize_public_dependency(proto, n, ctx->arena); - const int32_t *proto_deps = _upb_filedef_publicdepnums(f); - memcpy(public_deps, proto_deps, n * sizeof(int32_t)); + const int32_t *public_dep_nums = _upb_filedef_publicdepnums(f); + memcpy(public_deps, public_dep_nums, n * sizeof(int32_t)); + + n = upb_filedef_weakdepcount(f); + int32_t *weak_deps = + google_protobuf_FileDescriptorProto_resize_weak_dependency(proto, n, + ctx->arena); + const int32_t *weak_dep_nums = _upb_filedef_weakdepnums(f); + memcpy(weak_deps, weak_dep_nums, n * sizeof(int32_t)); n = upb_filedef_toplvlmsgcount(f); google_protobuf_DescriptorProto **msgs = @@ -444,8 +455,6 @@ static google_protobuf_FileDescriptorProto *filedef_toproto( upb_filedef_options(f)); } - // TODO: public & weak dependencies. - return proto; } diff --git a/upb/util/def_to_proto_public_import_test.proto b/upb/util/def_to_proto_public_import_test.proto new file mode 100644 index 0000000000..10f1c11733 --- /dev/null +++ b/upb/util/def_to_proto_public_import_test.proto @@ -0,0 +1,28 @@ +/* + * 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. + */ + +syntax = "proto3"; diff --git a/upb/util/def_to_proto_regular_import_test.proto b/upb/util/def_to_proto_regular_import_test.proto new file mode 100644 index 0000000000..10f1c11733 --- /dev/null +++ b/upb/util/def_to_proto_regular_import_test.proto @@ -0,0 +1,28 @@ +/* + * 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. + */ + +syntax = "proto3"; diff --git a/upb/util/def_to_proto_test.cc b/upb/util/def_to_proto_test.cc new file mode 100644 index 0000000000..9d70d3e779 --- /dev/null +++ b/upb/util/def_to_proto_test.cc @@ -0,0 +1,127 @@ +/* + * 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/util/def_to_proto.h" + +#include "gmock/gmock.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/descriptor.upbdefs.h" +#include "google/protobuf/dynamic_message.h" +#include "google/protobuf/util/message_differencer.h" +#include "gtest/gtest.h" +#include "upb/def.hpp" +#include "upb/upb.hpp" +#include "upb/util/def_to_proto_test.upbdefs.h" + +// Loads and retrieves a descriptor for `msgdef` into the given `pool`. +const google::protobuf::Descriptor* AddMessageDescriptor( + upb::MessageDefPtr msgdef, google::protobuf::DescriptorPool* pool) { + upb::Arena tmp_arena; + upb::FileDefPtr file = msgdef.file(); + google_protobuf_FileDescriptorProto* upb_proto = + upb_FileDef_ToProto(file.ptr(), tmp_arena.ptr()); + size_t size; + const char* buf = google_protobuf_FileDescriptorProto_serialize( + upb_proto, tmp_arena.ptr(), &size); + google::protobuf::FileDescriptorProto google_proto; + google_proto.ParseFromArray(buf, size); + const google::protobuf::FileDescriptor* file_desc = + pool->BuildFile(google_proto); + EXPECT_TRUE(file_desc != nullptr); + return pool->FindMessageTypeByName(msgdef.full_name()); +} + +// Converts a upb `msg` (with type `msgdef`) into a protobuf Message object from +// the given factory and descriptor. +std::unique_ptr ToProto( + const upb_msg* msg, const upb_msgdef* msgdef, + const google::protobuf::Descriptor* desc, + google::protobuf::MessageFactory* factory) { + upb::Arena arena; + EXPECT_TRUE(desc != nullptr); + std::unique_ptr google_msg( + factory->GetPrototype(desc)->New()); + size_t size; + const char* buf = + upb_encode(msg, upb_msgdef_layout(msgdef), arena.ptr(), &size); + google_msg->ParseFromArray(buf, size); + return google_msg; +} + +// A gtest matcher that verifies that a proto is equal to `proto`. Both `proto` +// and `arg` must be messages of type `msgdef_func` (a .upbdefs.h function that +// loads a known msgdef into the given symtab). +MATCHER_P2(EqualsUpbProto, proto, msgdef_func, + negation ? "are not equal" : "are equal") { + upb::SymbolTable symtab; + google::protobuf::DescriptorPool pool; + google::protobuf::DynamicMessageFactory factory; + upb::MessageDefPtr msgdef(msgdef_func(symtab.ptr())); + EXPECT_TRUE(msgdef.ptr() != nullptr); + const google::protobuf::Descriptor* desc = + AddMessageDescriptor(msgdef, &pool); + EXPECT_TRUE(desc != nullptr); + std::unique_ptr m1( + ToProto(proto, msgdef.ptr(), desc, &factory)); + std::unique_ptr m2( + ToProto(arg, msgdef.ptr(), desc, &factory)); + std::string differences; + google::protobuf::util::MessageDifferencer differencer; + differencer.ReportDifferencesToString(&differences); + bool eq = differencer.Compare(*m2, *m1); + if (!eq) { + *result_listener << differences; + } + return eq; +} + +// Verifies that the given upb FileDef can be converted to a proto that matches +// `proto`. +void CheckFile(const upb::FileDefPtr file, + const google_protobuf_FileDescriptorProto* proto) { + upb::Arena arena; + google_protobuf_FileDescriptorProto* proto2 = + upb_FileDef_ToProto(file.ptr(), arena.ptr()); + ASSERT_THAT( + proto, + EqualsUpbProto(proto2, google_protobuf_FileDescriptorProto_getmsgdef)); +} + +// Verifies that upb/util/def_to_proto_test.proto can round-trip: +// serialized descriptor -> upb def -> serialized descriptor +TEST(DefToProto, Test) { + upb::Arena arena; + upb::SymbolTable symtab; + upb_strview test_file_desc = + upb_util_def_to_proto_test_proto_upbdefinit.descriptor; + const auto* file_desc = google_protobuf_FileDescriptorProto_parse( + test_file_desc.data, test_file_desc.size, arena.ptr()); + + upb::MessageDefPtr msgdef(pkg_Message_getmsgdef(symtab.ptr())); + upb::FileDefPtr file = msgdef.file(); + CheckFile(file, file_desc); +} diff --git a/upb/util/def_to_proto_test.proto b/upb/util/def_to_proto_test.proto new file mode 100644 index 0000000000..d7171934d6 --- /dev/null +++ b/upb/util/def_to_proto_test.proto @@ -0,0 +1,76 @@ +/* + * 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. + */ + +syntax = "proto2"; + +import "upb/util/def_to_proto_regular_import_test.proto"; +import public "upb/util/def_to_proto_public_import_test.proto"; +import weak "upb/util/def_to_proto_weak_import_test.proto"; + +package pkg; + +option optimize_for = CODE_SIZE; +option go_package = "foo_go_package"; +option java_package = "bar_java_package"; +option java_outer_classname = "baz_java_outer_classname"; +option csharp_namespace = "quux_csharp_namespace"; +option objc_class_prefix = "the_objc_prefix"; +option cc_enable_arenas = true; + +message Message { + optional int32 a = 1 [default = 3]; + oneof foo { + string oneof_string = 2 [default = "abc\n"]; + string oneof_bool = 3 [default = "true"]; + bytes oneof_bytes = 4 [default = "abc\xef\xfe"]; + } + extensions 1000 to max; + extend Message { + optional int32 ext = 1000; + } + + message NestedMessage {} + message NestedEnum {} + + // TODO: support reserved ranges in defs. + // (At the moment they are ignored and will not round-trip through defs). + // reserved 4, 6 to 8; +} + +enum Enum { + ZERO = 0; + ONE = 1; + NEGATIVE_ONE = -1; +} + +service Service { + rpc Bar(Message) returns (Message); +} + +extend Message { + optional int32 ext = 1001; +} diff --git a/upb/util/def_to_proto_weak_import_test.proto b/upb/util/def_to_proto_weak_import_test.proto new file mode 100644 index 0000000000..10f1c11733 --- /dev/null +++ b/upb/util/def_to_proto_weak_import_test.proto @@ -0,0 +1,28 @@ +/* + * 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. + */ + +syntax = "proto3"; diff --git a/upb/util/def_to_proto_wweak_import_test.proto b/upb/util/def_to_proto_wweak_import_test.proto new file mode 100644 index 0000000000..10f1c11733 --- /dev/null +++ b/upb/util/def_to_proto_wweak_import_test.proto @@ -0,0 +1,28 @@ +/* + * 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. + */ + +syntax = "proto3"; diff --git a/upbc/protoc-gen-upb.cc b/upbc/protoc-gen-upb.cc index 9c23647016..8933cff861 100644 --- a/upbc/protoc-gen-upb.cc +++ b/upbc/protoc-gen-upb.cc @@ -83,12 +83,6 @@ void AddEnums(const protobuf::Descriptor* message, } } -template -void SortDefs(std::vector* defs) { - std::sort(defs->begin(), defs->end(), - [](T a, T b) { return a->full_name() < b->full_name(); }); -} - std::vector SortedEnums( const protobuf::FileDescriptor* file) { std::vector enums; @@ -98,7 +92,6 @@ std::vector SortedEnums( for (int i = 0; i < file->message_type_count(); i++) { AddEnums(file->message_type(i), &enums); } - SortDefs(&enums); return enums; } From c59d8f8eb7e3d6e4a87e067a67db5bf5a318d81c Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Mon, 1 Nov 2021 00:08:38 -0700 Subject: [PATCH 3/3] Addressed PR comments and fixed the broken test. --- cmake/google/protobuf/descriptor.upb.c | 20 ++--- upb/util/def_to_proto.c | 107 ++++++++++++++----------- upb/util/def_to_proto.h | 5 +- upbc/protoc-gen-upb.cc | 5 ++ 4 files changed, 78 insertions(+), 59 deletions(-) diff --git a/cmake/google/protobuf/descriptor.upb.c b/cmake/google/protobuf/descriptor.upb.c index 3782fb4456..d7eaa7c02d 100644 --- a/cmake/google/protobuf/descriptor.upb.c +++ b/cmake/google/protobuf/descriptor.upb.c @@ -518,15 +518,21 @@ static const upb_msglayout *messages_layout[27] = { &google_protobuf_GeneratedCodeInfo_Annotation_msginit, }; +const upb_enumlayout google_protobuf_FieldDescriptorProto_Type_enuminit = { + NULL, + 0x7fffeULL, + 0, +}; + const upb_enumlayout google_protobuf_FieldDescriptorProto_Label_enuminit = { NULL, 0xeULL, 0, }; -const upb_enumlayout google_protobuf_FieldDescriptorProto_Type_enuminit = { +const upb_enumlayout google_protobuf_FileOptions_OptimizeMode_enuminit = { NULL, - 0x7fffeULL, + 0xeULL, 0, }; @@ -542,12 +548,6 @@ const upb_enumlayout google_protobuf_FieldOptions_JSType_enuminit = { 0, }; -const upb_enumlayout google_protobuf_FileOptions_OptimizeMode_enuminit = { - NULL, - 0xeULL, - 0, -}; - const upb_enumlayout google_protobuf_MethodOptions_IdempotencyLevel_enuminit = { NULL, 0x7ULL, @@ -555,11 +555,11 @@ const upb_enumlayout google_protobuf_MethodOptions_IdempotencyLevel_enuminit = { }; static const upb_enumlayout *enums_layout[6] = { - &google_protobuf_FieldDescriptorProto_Label_enuminit, &google_protobuf_FieldDescriptorProto_Type_enuminit, + &google_protobuf_FieldDescriptorProto_Label_enuminit, + &google_protobuf_FileOptions_OptimizeMode_enuminit, &google_protobuf_FieldOptions_CType_enuminit, &google_protobuf_FieldOptions_JSType_enuminit, - &google_protobuf_FileOptions_OptimizeMode_enuminit, &google_protobuf_MethodOptions_IdempotencyLevel_enuminit, }; diff --git a/upb/util/def_to_proto.c b/upb/util/def_to_proto.c index addab03397..fdde5cc062 100644 --- a/upb/util/def_to_proto.c +++ b/upb/util/def_to_proto.c @@ -13,11 +13,11 @@ * 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 + * 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 @@ -27,9 +27,10 @@ #include "upb/util/def_to_proto.h" +#include #include #include -#include + #include "upb/reflection.h" /* Must be last. */ @@ -38,9 +39,10 @@ typedef struct { upb_arena *arena; jmp_buf err; -} toproto_ctx; +} upb_ToProto_Context; -#define CHK_OOM(val) if (!(val)) UPB_LONGJMP(ctx->err, 1); +#define CHK_OOM(val) \ + if (!(val)) UPB_LONGJMP(ctx->err, 1); // We want to copy the options verbatim into the destination options proto. // We use serialize+parse as our deep copy. @@ -57,18 +59,18 @@ typedef struct { google_protobuf_##desc_type##_set_options(proto, dst); \ } -static upb_strview strviewdup2(toproto_ctx *ctx, upb_strview str) { +static upb_strview strviewdup2(upb_ToProto_Context *ctx, upb_strview str) { char *p = upb_arena_malloc(ctx->arena, str.size); CHK_OOM(p); memcpy(p, str.data, str.size); return (upb_strview){.data = p, .size = str.size}; } -static upb_strview strviewdup(toproto_ctx *ctx, const char *s) { +static upb_strview strviewdup(upb_ToProto_Context *ctx, const char *s) { return strviewdup2(ctx, (upb_strview){.data = s, .size = strlen(s)}); } -static upb_strview qual_dup(toproto_ctx *ctx, const char *s) { +static upb_strview qual_dup(upb_ToProto_Context *ctx, const char *s) { size_t n = strlen(s); char *p = upb_arena_malloc(ctx->arena, n + 1); CHK_OOM(p); @@ -78,7 +80,7 @@ static upb_strview qual_dup(toproto_ctx *ctx, const char *s) { } UPB_PRINTF(2, 3) -static upb_strview printf_dup(toproto_ctx *ctx, const char *fmt, ...) { +static upb_strview printf_dup(upb_ToProto_Context *ctx, const char *fmt, ...) { const size_t max = 32; char *p = upb_arena_malloc(ctx->arena, max); CHK_OOM(p); @@ -90,7 +92,8 @@ static upb_strview printf_dup(toproto_ctx *ctx, const char *fmt, ...) { return (upb_strview){.data = p, .size = n}; } -static upb_strview default_string(toproto_ctx *ctx, const upb_fielddef *f) { +static upb_strview default_string(upb_ToProto_Context *ctx, + const upb_fielddef *f) { upb_msgval d = upb_fielddef_default(f); switch (upb_fielddef_type(f)) { case UPB_TYPE_BOOL: @@ -122,7 +125,7 @@ static upb_strview default_string(toproto_ctx *ctx, const upb_fielddef *f) { } static google_protobuf_FieldDescriptorProto *fielddef_toproto( - toproto_ctx *ctx, const upb_fielddef *f) { + upb_ToProto_Context *ctx, const upb_fielddef *f) { google_protobuf_FieldDescriptorProto *proto = google_protobuf_FieldDescriptorProto_new(ctx->arena); CHK_OOM(proto); @@ -150,7 +153,8 @@ static google_protobuf_FieldDescriptorProto *fielddef_toproto( if (upb_fielddef_isextension(f)) { google_protobuf_FieldDescriptorProto_set_extendee( - proto, qual_dup(ctx, upb_msgdef_fullname(upb_fielddef_containingtype(f)))); + proto, + qual_dup(ctx, upb_msgdef_fullname(upb_fielddef_containingtype(f)))); } if (upb_fielddef_hasdefault(f)) { @@ -177,7 +181,7 @@ static google_protobuf_FieldDescriptorProto *fielddef_toproto( } static google_protobuf_OneofDescriptorProto *oneofdef_toproto( - toproto_ctx *ctx, const upb_oneofdef *o) { + upb_ToProto_Context *ctx, const upb_oneofdef *o) { google_protobuf_OneofDescriptorProto *proto = google_protobuf_OneofDescriptorProto_new(ctx->arena); CHK_OOM(proto); @@ -194,7 +198,7 @@ static google_protobuf_OneofDescriptorProto *oneofdef_toproto( } static google_protobuf_EnumValueDescriptorProto *enumvaldef_toproto( - toproto_ctx *ctx, const upb_enumvaldef *e) { + upb_ToProto_Context *ctx, const upb_enumvaldef *e) { google_protobuf_EnumValueDescriptorProto *proto = google_protobuf_EnumValueDescriptorProto_new(ctx->arena); CHK_OOM(proto); @@ -213,7 +217,7 @@ static google_protobuf_EnumValueDescriptorProto *enumvaldef_toproto( } static google_protobuf_EnumDescriptorProto *enumdef_toproto( - toproto_ctx *ctx, const upb_enumdef *e) { + upb_ToProto_Context *ctx, const upb_enumdef *e) { google_protobuf_EnumDescriptorProto *proto = google_protobuf_EnumDescriptorProto_new(ctx->arena); CHK_OOM(proto); @@ -222,7 +226,7 @@ static google_protobuf_EnumDescriptorProto *enumdef_toproto( proto, strviewdup(ctx, upb_enumdef_name(e))); int n; - + n = upb_enumdef_valuecount(e); google_protobuf_EnumValueDescriptorProto **vals = google_protobuf_EnumDescriptorProto_resize_value(proto, n, ctx->arena); @@ -230,7 +234,7 @@ static google_protobuf_EnumDescriptorProto *enumdef_toproto( for (int i = 0; i < n; i++) { vals[i] = enumvaldef_toproto(ctx, upb_enumdef_value(e, i)); } - + // TODO: reserved range, reserved name if (upb_enumdef_hasoptions(e)) { @@ -242,7 +246,7 @@ static google_protobuf_EnumDescriptorProto *enumdef_toproto( } static google_protobuf_DescriptorProto_ExtensionRange *extrange_toproto( - toproto_ctx *ctx, const upb_extrange *e) { + upb_ToProto_Context *ctx, const upb_extrange *e) { google_protobuf_DescriptorProto_ExtensionRange *proto = google_protobuf_DescriptorProto_ExtensionRange_new(ctx->arena); CHK_OOM(proto); @@ -260,17 +264,17 @@ static google_protobuf_DescriptorProto_ExtensionRange *extrange_toproto( return proto; } -static google_protobuf_DescriptorProto *msgdef_toproto(toproto_ctx *ctx, +static google_protobuf_DescriptorProto *msgdef_toproto(upb_ToProto_Context *ctx, const upb_msgdef *m) { google_protobuf_DescriptorProto *proto = google_protobuf_DescriptorProto_new(ctx->arena); CHK_OOM(proto); - google_protobuf_DescriptorProto_set_name( - proto, strviewdup(ctx, upb_msgdef_name(m))); + google_protobuf_DescriptorProto_set_name(proto, + strviewdup(ctx, upb_msgdef_name(m))); int n; - + n = upb_msgdef_fieldcount(m); google_protobuf_FieldDescriptorProto **fields = google_protobuf_DescriptorProto_resize_field(proto, n, ctx->arena); @@ -309,7 +313,8 @@ static google_protobuf_DescriptorProto *msgdef_toproto(toproto_ctx *ctx, n = upb_msgdef_extrangecount(m); google_protobuf_DescriptorProto_ExtensionRange **ext_ranges = - google_protobuf_DescriptorProto_resize_extension_range(proto, n, ctx->arena); + google_protobuf_DescriptorProto_resize_extension_range(proto, n, + ctx->arena); for (int i = 0; i < n; i++) { ext_ranges[i] = extrange_toproto(ctx, upb_msgdef_extrange(m, i)); } @@ -324,7 +329,7 @@ static google_protobuf_DescriptorProto *msgdef_toproto(toproto_ctx *ctx, } static google_protobuf_MethodDescriptorProto *methoddef_toproto( - toproto_ctx *ctx, const upb_methoddef *m) { + upb_ToProto_Context *ctx, const upb_methoddef *m) { google_protobuf_MethodDescriptorProto *proto = google_protobuf_MethodDescriptorProto_new(ctx->arena); CHK_OOM(proto); @@ -354,7 +359,7 @@ static google_protobuf_MethodDescriptorProto *methoddef_toproto( } static google_protobuf_ServiceDescriptorProto *servicedef_toproto( - toproto_ctx *ctx, const upb_servicedef *s) { + upb_ToProto_Context *ctx, const upb_servicedef *s) { google_protobuf_ServiceDescriptorProto *proto = google_protobuf_ServiceDescriptorProto_new(ctx->arena); CHK_OOM(proto); @@ -379,7 +384,7 @@ static google_protobuf_ServiceDescriptorProto *servicedef_toproto( } static google_protobuf_FileDescriptorProto *filedef_toproto( - toproto_ctx *ctx, const upb_filedef *f) { + upb_ToProto_Context *ctx, const upb_filedef *f) { google_protobuf_FileDescriptorProto *proto = google_protobuf_FileDescriptorProto_new(ctx->arena); CHK_OOM(proto); @@ -399,8 +404,8 @@ static google_protobuf_FileDescriptorProto *filedef_toproto( } n = upb_filedef_depcount(f); - upb_strview *deps = - google_protobuf_FileDescriptorProto_resize_dependency(proto, n, ctx->arena); + upb_strview *deps = google_protobuf_FileDescriptorProto_resize_dependency( + proto, n, ctx->arena); for (int i = 0; i < n; i++) { deps[i] = strviewdup(ctx, upb_filedef_name(upb_filedef_dep(f, i))); } @@ -460,48 +465,56 @@ static google_protobuf_FileDescriptorProto *filedef_toproto( google_protobuf_DescriptorProto *upb_MessageDef_ToProto(const upb_msgdef *m, upb_arena *a) { - toproto_ctx ctx = {a}; - return UPB_SETJMP(ctx.err) ? NULL : msgdef_toproto(&ctx, m); + upb_ToProto_Context ctx = {a}; + if (UPB_SETJMP(ctx.err)) return NULL; + return msgdef_toproto(&ctx, m); } google_protobuf_EnumDescriptorProto *upb_EnumDef_ToProto(const upb_enumdef *e, upb_arena *a) { - toproto_ctx ctx = {a}; - return UPB_SETJMP(ctx.err) ? NULL : enumdef_toproto(&ctx, e); + upb_ToProto_Context ctx = {a}; + if (UPB_SETJMP(ctx.err)) return NULL; + return enumdef_toproto(&ctx, e); } google_protobuf_EnumValueDescriptorProto *upb_EnumValueDef_ToProto( const upb_enumvaldef *e, upb_arena *a) { - toproto_ctx ctx = {a}; - return UPB_SETJMP(ctx.err) ? NULL : enumvaldef_toproto(&ctx, e); + upb_ToProto_Context ctx = {a}; + if (UPB_SETJMP(ctx.err)) return NULL; + return enumvaldef_toproto(&ctx, e); } google_protobuf_FieldDescriptorProto *upb_FieldDef_ToProto( const upb_fielddef *f, upb_arena *a) { - toproto_ctx ctx = {a}; - return UPB_SETJMP(ctx.err) ? NULL : fielddef_toproto(&ctx, f); + upb_ToProto_Context ctx = {a}; + if (UPB_SETJMP(ctx.err)) return NULL; + return fielddef_toproto(&ctx, f); } google_protobuf_OneofDescriptorProto *upb_OneofDef_ToProto( const upb_oneofdef *o, upb_arena *a) { - toproto_ctx ctx = {a}; - return UPB_SETJMP(ctx.err) ? NULL : oneofdef_toproto(&ctx, o); + upb_ToProto_Context ctx = {a}; + if (UPB_SETJMP(ctx.err)) return NULL; + return oneofdef_toproto(&ctx, o); } google_protobuf_FileDescriptorProto *upb_FileDef_ToProto(const upb_filedef *f, upb_arena *a) { - toproto_ctx ctx = {a}; - return UPB_SETJMP(ctx.err) ? NULL : filedef_toproto(&ctx, f); + upb_ToProto_Context ctx = {a}; + if (UPB_SETJMP(ctx.err)) return NULL; + return filedef_toproto(&ctx, f); } google_protobuf_MethodDescriptorProto *upb_MethodDef_ToProto( const upb_methoddef *m, upb_arena *a) { - toproto_ctx ctx = {a}; - return UPB_SETJMP(ctx.err) ? NULL : methoddef_toproto(&ctx, m); + upb_ToProto_Context ctx = {a}; + if (UPB_SETJMP(ctx.err)) return NULL; + return methoddef_toproto(&ctx, m); } google_protobuf_ServiceDescriptorProto *upb_ServiceDef_ToProto( const upb_servicedef *s, upb_arena *a) { - toproto_ctx ctx = {a}; - return UPB_SETJMP(ctx.err) ? NULL : servicedef_toproto(&ctx, s); + upb_ToProto_Context ctx = {a}; + if (UPB_SETJMP(ctx.err)) return NULL; + return servicedef_toproto(&ctx, s); } diff --git a/upb/util/def_to_proto.h b/upb/util/def_to_proto.h index 20c8ab4c13..7332f3ca2f 100644 --- a/upb/util/def_to_proto.h +++ b/upb/util/def_to_proto.h @@ -35,8 +35,9 @@ extern "C" { #endif // Functions for converting defs back to the equivalent descriptor proto. -// Ultimately the goal is that a round-trip proto->def->proto is lossless. -// Each function creates a +// Ultimately the goal is that a round-trip proto->def->proto is lossless. Each +// function returns a new proto created in arena `a`, or NULL if memory +// allocation failed. google_protobuf_DescriptorProto* upb_MessageDef_ToProto(const upb_msgdef* m, upb_arena* a); google_protobuf_EnumDescriptorProto* upb_EnumDef_ToProto(const upb_enumdef* e, diff --git a/upbc/protoc-gen-upb.cc b/upbc/protoc-gen-upb.cc index 8933cff861..ef88363b7d 100644 --- a/upbc/protoc-gen-upb.cc +++ b/upbc/protoc-gen-upb.cc @@ -773,6 +773,11 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) { std::vector this_file_enums = SortedEnums(file); + std::sort( + this_file_enums.begin(), this_file_enums.end(), + [](const protobuf::EnumDescriptor* a, const protobuf::EnumDescriptor* b) { + return a->full_name() < b->full_name(); + }); for (auto enumdesc : this_file_enums) { output("typedef enum {\n");