Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
287 lines
9.5 KiB
287 lines
9.5 KiB
/* |
|
* 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 "upbc/code_generator_request.h" |
|
|
|
#include <assert.h> |
|
#include <inttypes.h> |
|
#include <setjmp.h> |
|
#include <stddef.h> |
|
#include <stdint.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
|
|
#include "google/protobuf/compiler/plugin.upb.h" |
|
#include "upb/def.h" |
|
#include "upb/mini_descriptor.h" |
|
#include "upb/mini_table.h" |
|
|
|
// Must be last. |
|
#include "upb/port_def.inc" |
|
|
|
enum { |
|
kErrArenaMalloc = 1, |
|
kErrEnumName, |
|
kErrExtensionName, |
|
kErrFieldName, |
|
kErrFilePackage, |
|
kErrMapCollision, |
|
kErrMiniDescriptorsSet, |
|
kErrStateGrow, |
|
}; |
|
|
|
/* upbc_PathState *************************************************************/ |
|
|
|
// Manages the current fully qualified path name as we dig down into a proto. |
|
// Basically just a string that grows and shrinks like a stack. |
|
|
|
typedef struct { |
|
size_t len; |
|
char path[4000]; // TODO(salo): make this dynamic |
|
} upbc_PathState; |
|
|
|
static void upbc_PathState_Init(upbc_PathState* p) { p->len = 0; } |
|
|
|
static void upbc_PathState_Push(upbc_PathState* p, upb_StringView name) { |
|
if (p->len) { |
|
p->path[p->len++] = '.'; |
|
} |
|
memcpy(&p->path[p->len], name.data, name.size); |
|
p->len += name.size; |
|
} |
|
|
|
static void upbc_PathState_Pop(upbc_PathState* p, upb_StringView name) { |
|
p->len -= name.size; |
|
if (p->len) { |
|
p->len--; |
|
} |
|
} |
|
|
|
static upb_StringView upbc_PathState_String(const upbc_PathState* p) { |
|
return upb_StringView_FromDataAndSize(p->path, p->len); |
|
} |
|
|
|
/******************************************************************************/ |
|
|
|
// Kitchen sink storage for the mini descriptor state. |
|
|
|
typedef struct { |
|
upb_Arena* a; |
|
upb_Syntax syntax; |
|
|
|
upbc_CodeGeneratorRequest* out; |
|
|
|
jmp_buf err; |
|
|
|
upbc_PathState path; |
|
} upbc_ScrapeState; |
|
|
|
static void upbc_ScrapeState_Init(upbc_ScrapeState* s, upb_Arena* a) { |
|
s->a = a; |
|
|
|
upbc_PathState_Init(&s->path); |
|
|
|
s->out = upbc_CodeGeneratorRequest_new(a); |
|
if (!s->out) UPB_LONGJMP(s->err, kErrArenaMalloc); |
|
} |
|
|
|
static void upbc_ScrapeState_Push(upbc_ScrapeState* s, upb_StringView name) { |
|
upbc_PathState_Push(&s->path, name); |
|
|
|
const upb_StringView key = upbc_PathState_String(&s->path); |
|
if (upbc_CodeGeneratorRequest_mini_descriptors_get(s->out, key, NULL)) { |
|
UPB_LONGJMP(s->err, kErrMapCollision); |
|
} |
|
} |
|
|
|
static void upbc_ScrapeState_Pop(upbc_ScrapeState* s, upb_StringView name) { |
|
upbc_PathState_Pop(&s->path, name); |
|
} |
|
|
|
static void upbc_ScrapeState_String(upbc_ScrapeState* s, |
|
upb_StringView encoding) { |
|
const upb_StringView path = upbc_PathState_String(&s->path); |
|
bool ok = upbc_CodeGeneratorRequest_mini_descriptors_set(s->out, path, |
|
encoding, s->a); |
|
if (!ok) UPB_LONGJMP(s->err, kErrMiniDescriptorsSet); |
|
} |
|
|
|
/******************************************************************************/ |
|
|
|
// File accessors. |
|
|
|
static upb_Syntax upbc_File_Syntax(const google_protobuf_FileDescriptorProto* file) { |
|
if (google_protobuf_FileDescriptorProto_has_syntax(file)) { |
|
const upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file); |
|
const upb_StringView proto3 = upb_StringView_FromString("proto3"); |
|
if (upb_StringView_IsEqual(syntax, proto3)) return kUpb_Syntax_Proto3; |
|
} |
|
return kUpb_Syntax_Proto2; |
|
} |
|
|
|
/******************************************************************************/ |
|
|
|
// Forward declaration. |
|
static void upbc_Scrape_Messages(upbc_ScrapeState*, |
|
const google_protobuf_DescriptorProto* const*, size_t); |
|
|
|
static void upbc_Scrape_Enum(upbc_ScrapeState* s, |
|
const google_protobuf_EnumDescriptorProto* enum_type) { |
|
if (!google_protobuf_EnumDescriptorProto_has_name(enum_type)) { |
|
UPB_LONGJMP(s->err, kErrEnumName); |
|
} |
|
const upb_StringView name = google_protobuf_EnumDescriptorProto_name(enum_type); |
|
|
|
upbc_ScrapeState_Push(s, name); |
|
|
|
const upb_StringView encoding = |
|
upb_MiniDescriptor_EncodeEnum(enum_type, s->a); |
|
|
|
upbc_ScrapeState_String(s, encoding); |
|
upbc_ScrapeState_Pop(s, name); |
|
} |
|
|
|
static void upbc_Scrape_Enums( |
|
upbc_ScrapeState* s, const google_protobuf_EnumDescriptorProto* const* enum_types, |
|
size_t len) { |
|
for (size_t i = 0; i < len; i++) { |
|
upbc_Scrape_Enum(s, enum_types[i]); |
|
} |
|
} |
|
|
|
static void upbc_Scrape_Extension( |
|
upbc_ScrapeState* s, const google_protobuf_FieldDescriptorProto* extension_type) { |
|
if (!google_protobuf_FieldDescriptorProto_has_name(extension_type)) { |
|
UPB_LONGJMP(s->err, kErrExtensionName); |
|
} |
|
const upb_StringView name = google_protobuf_FieldDescriptorProto_name(extension_type); |
|
|
|
upbc_ScrapeState_Push(s, name); |
|
|
|
const upb_StringView encoding = |
|
upb_MiniDescriptor_EncodeExtension(extension_type, s->syntax, s->a); |
|
|
|
upbc_ScrapeState_String(s, encoding); |
|
upbc_ScrapeState_Pop(s, name); |
|
} |
|
|
|
static void upbc_Scrape_Extensions( |
|
const google_protobuf_FieldDescriptorProto* const* extension_types, size_t len, |
|
upbc_ScrapeState* s) { |
|
for (size_t i = 0; i < len; i++) { |
|
upbc_Scrape_Extension(s, extension_types[i]); |
|
} |
|
} |
|
|
|
static void upbc_Scrape_File(upbc_ScrapeState* s, |
|
const google_protobuf_FileDescriptorProto* file_type) { |
|
if (!google_protobuf_FileDescriptorProto_has_package(file_type)) { |
|
UPB_LONGJMP(s->err, kErrFilePackage); |
|
} |
|
const upb_StringView package = google_protobuf_FileDescriptorProto_package(file_type); |
|
upbc_ScrapeState_Push(s, package); |
|
|
|
s->syntax = upbc_File_Syntax(file_type); |
|
|
|
size_t len = 0; |
|
const google_protobuf_EnumDescriptorProto* const* enum_types = |
|
google_protobuf_FileDescriptorProto_enum_type(file_type, &len); |
|
upbc_Scrape_Enums(s, enum_types, len); |
|
|
|
const google_protobuf_FieldDescriptorProto* const* extension_types = |
|
google_protobuf_FileDescriptorProto_extension(file_type, &len); |
|
upbc_Scrape_Extensions(extension_types, len, s); |
|
|
|
const google_protobuf_DescriptorProto* const* message_types = |
|
google_protobuf_FileDescriptorProto_message_type(file_type, &len); |
|
upbc_Scrape_Messages(s, message_types, len); |
|
|
|
upbc_ScrapeState_Pop(s, package); |
|
} |
|
|
|
static void upbc_Scrape_Files( |
|
upbc_ScrapeState* s, const google_protobuf_FileDescriptorProto* const* file_types, |
|
size_t len) { |
|
for (size_t i = 0; i < len; i++) { |
|
upbc_Scrape_File(s, file_types[i]); |
|
} |
|
} |
|
|
|
static void upbc_Scrape_Message(upbc_ScrapeState* s, |
|
const google_protobuf_DescriptorProto* message_type) { |
|
if (!google_protobuf_DescriptorProto_has_name(message_type)) return; |
|
|
|
const upb_StringView name = google_protobuf_DescriptorProto_name(message_type); |
|
upbc_ScrapeState_Push(s, name); |
|
|
|
const upb_StringView encoding = |
|
upb_MiniDescriptor_EncodeMessage(message_type, s->syntax, s->a); |
|
upbc_ScrapeState_String(s, encoding); |
|
|
|
size_t len = 0; |
|
const google_protobuf_EnumDescriptorProto* const* enum_types = |
|
google_protobuf_DescriptorProto_enum_type(message_type, &len); |
|
upbc_Scrape_Enums(s, enum_types, len); |
|
|
|
const google_protobuf_FieldDescriptorProto* const* extension_types = |
|
google_protobuf_DescriptorProto_extension(message_type, &len); |
|
upbc_Scrape_Extensions(extension_types, len, s); |
|
|
|
const google_protobuf_DescriptorProto* const* nested_types = |
|
google_protobuf_DescriptorProto_nested_type(message_type, &len); |
|
upbc_Scrape_Messages(s, nested_types, len); |
|
|
|
upbc_ScrapeState_Pop(s, name); |
|
} |
|
|
|
static void upbc_Scrape_Messages( |
|
upbc_ScrapeState* s, const google_protobuf_DescriptorProto* const* message_types, |
|
size_t len) { |
|
for (size_t i = 0; i < len; i++) { |
|
upbc_Scrape_Message(s, message_types[i]); |
|
} |
|
} |
|
|
|
upbc_CodeGeneratorRequest* upbc_MakeCodeGeneratorRequest( |
|
google_protobuf_compiler_CodeGeneratorRequest* request, upb_Arena* a, |
|
upb_Status* status) { |
|
upbc_ScrapeState s; |
|
int err = UPB_SETJMP(s.err); |
|
if (err) { |
|
upb_Status_SetErrorFormat(status, "%s(): error %d", __func__, err); |
|
return NULL; |
|
} |
|
upbc_ScrapeState_Init(&s, a); |
|
|
|
size_t len = 0; |
|
const google_protobuf_FileDescriptorProto* const* file_types = |
|
google_protobuf_compiler_CodeGeneratorRequest_proto_file(request, &len); |
|
upbc_Scrape_Files(&s, file_types, len); |
|
|
|
upbc_CodeGeneratorRequest_set_request(s.out, request); |
|
return s.out; |
|
}
|
|
|