Updated upb from defcleanup branch and modified Ruby to use it (#5539)

This commit is contained in:
Joshua Haberman 2019-03-06 10:20:18 -08:00 committed by GitHub
parent a1b286e21a
commit 37581380fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 7194 additions and 13628 deletions

File diff suppressed because it is too large Load Diff

View File

@ -117,18 +117,18 @@ static const void* newhandlerdata(upb_handlers* h, uint32_t ofs, int32_t hasbit)
typedef struct {
size_t ofs;
int32_t hasbit;
const upb_msgdef *md;
VALUE subklass;
} submsg_handlerdata_t;
// Creates a handlerdata that contains offset and submessage type information.
static const void *newsubmsghandlerdata(upb_handlers* h,
uint32_t ofs,
int32_t hasbit,
const upb_fielddef* f) {
VALUE subklass) {
submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t);
hd->ofs = ofs;
hd->hasbit = hasbit;
hd->md = upb_fielddef_msgsubdef(f);
hd->subklass = subklass;
upb_handlers_addcleanup(h, hd, xfree);
return hd;
}
@ -137,13 +137,14 @@ typedef struct {
size_t ofs; // union data slot
size_t case_ofs; // oneof_case field
uint32_t oneof_case_num; // oneof-case number to place in oneof_case field
const upb_msgdef *md; // msgdef, for oneof submessage handler
VALUE subklass;
} oneof_handlerdata_t;
static const void *newoneofhandlerdata(upb_handlers *h,
uint32_t ofs,
uint32_t case_ofs,
const upb_fielddef *f) {
const upb_fielddef *f,
const Descriptor* desc) {
oneof_handlerdata_t *hd = ALLOC(oneof_handlerdata_t);
hd->ofs = ofs;
hd->case_ofs = case_ofs;
@ -154,11 +155,7 @@ static const void *newoneofhandlerdata(upb_handlers *h,
// create a separate ID space. In addition, using the field tag number here
// lets us easily look up the field in the oneof accessor.
hd->oneof_case_num = upb_fielddef_number(f);
if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) {
hd->md = upb_fielddef_msgsubdef(f);
} else {
hd->md = NULL;
}
hd->subklass = field_type_class(desc->layout, f);
upb_handlers_addcleanup(h, hd, xfree);
return hd;
}
@ -254,13 +251,13 @@ static size_t stringdata_handler(void* closure, const void* hd,
}
static bool stringdata_end_handler(void* closure, const void* hd) {
VALUE rb_str = closure;
VALUE rb_str = (VALUE)closure;
rb_obj_freeze(rb_str);
return true;
}
static bool appendstring_end_handler(void* closure, const void* hd) {
VALUE rb_str = closure;
VALUE rb_str = (VALUE)closure;
rb_obj_freeze(rb_str);
return true;
}
@ -269,12 +266,9 @@ static bool appendstring_end_handler(void* closure, const void* hd) {
static void *appendsubmsg_handler(void *closure, const void *hd) {
VALUE ary = (VALUE)closure;
const submsg_handlerdata_t *submsgdata = hd;
VALUE subdesc =
get_def_obj((void*)submsgdata->md);
VALUE subklass = Descriptor_msgclass(subdesc);
MessageHeader* submsg;
VALUE submsg_rb = rb_class_new_instance(0, NULL, subklass);
VALUE submsg_rb = rb_class_new_instance(0, NULL, submsgdata->subklass);
RepeatedField_push(ary, submsg_rb);
TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
@ -285,15 +279,12 @@ static void *appendsubmsg_handler(void *closure, const void *hd) {
static void *submsg_handler(void *closure, const void *hd) {
MessageHeader* msg = closure;
const submsg_handlerdata_t* submsgdata = hd;
VALUE subdesc =
get_def_obj((void*)submsgdata->md);
VALUE subklass = Descriptor_msgclass(subdesc);
VALUE submsg_rb;
MessageHeader* submsg;
if (DEREF(msg, submsgdata->ofs, VALUE) == Qnil) {
DEREF(msg, submsgdata->ofs, VALUE) =
rb_class_new_instance(0, NULL, subklass);
rb_class_new_instance(0, NULL, submsgdata->subklass);
}
set_hasbit(closure, submsgdata->hasbit);
@ -309,11 +300,7 @@ typedef struct {
size_t ofs;
upb_fieldtype_t key_field_type;
upb_fieldtype_t value_field_type;
// We know that we can hold this reference because the handlerdata has the
// same lifetime as the upb_handlers struct, and the upb_handlers struct holds
// a reference to the upb_msgdef, which in turn has references to its subdefs.
const upb_def* value_field_subdef;
VALUE subklass;
} map_handlerdata_t;
// Temporary frame for map parsing: at the beginning of a map entry message, a
@ -388,7 +375,7 @@ static bool endmap_handler(void *closure, const void *hd, upb_status* s) {
if (mapdata->value_field_type == UPB_TYPE_MESSAGE ||
mapdata->value_field_type == UPB_TYPE_ENUM) {
value_field_typeclass = get_def_obj(mapdata->value_field_subdef);
value_field_typeclass = mapdata->subklass;
}
value = native_slot_get(
@ -411,7 +398,7 @@ static bool endmap_handler(void *closure, const void *hd, upb_status* s) {
static map_handlerdata_t* new_map_handlerdata(
size_t ofs,
const upb_msgdef* mapentry_def,
Descriptor* desc) {
const Descriptor* desc) {
const upb_fielddef* key_field;
const upb_fielddef* value_field;
map_handlerdata_t* hd = ALLOC(map_handlerdata_t);
@ -422,7 +409,7 @@ static map_handlerdata_t* new_map_handlerdata(
value_field = upb_msgdef_itof(mapentry_def, MAP_VALUE_FIELD);
assert(value_field != NULL);
hd->value_field_type = upb_fielddef_type(value_field);
hd->value_field_subdef = upb_fielddef_subdef(value_field);
hd->subklass = field_type_class(desc->layout, value_field);
return hd;
}
@ -488,16 +475,13 @@ static void *oneofsubmsg_handler(void *closure,
const oneof_handlerdata_t *oneofdata = hd;
uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t);
VALUE subdesc =
get_def_obj((void*)oneofdata->md);
VALUE subklass = Descriptor_msgclass(subdesc);
VALUE submsg_rb;
MessageHeader* submsg;
if (oldcase != oneofdata->oneof_case_num ||
DEREF(msg, oneofdata->ofs, VALUE) == Qnil) {
DEREF(msg, oneofdata->ofs, VALUE) =
rb_class_new_instance(0, NULL, subklass);
rb_class_new_instance(0, NULL, oneofdata->subklass);
}
// Set the oneof case *after* allocating the new class instance -- otherwise,
// if the Ruby GC is invoked as part of a call into the VM, it might invoke
@ -515,12 +499,12 @@ static void *oneofsubmsg_handler(void *closure,
// Set up handlers for a repeated field.
static void add_handlers_for_repeated_field(upb_handlers *h,
const Descriptor* desc,
const upb_fielddef *f,
size_t offset) {
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset, -1));
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
attr.handler_data = newhandlerdata(h, offset, -1);
upb_handlers_setstartseq(h, f, startseq_handler, &attr);
upb_handlerattr_uninit(&attr);
switch (upb_fielddef_type(f)) {
@ -551,20 +535,20 @@ static void add_handlers_for_repeated_field(upb_handlers *h,
break;
}
case UPB_TYPE_MESSAGE: {
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, -1, f));
VALUE subklass = field_type_class(desc->layout, f);
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
attr.handler_data = newsubmsghandlerdata(h, 0, -1, subklass);
upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr);
upb_handlerattr_uninit(&attr);
break;
}
}
}
// Set up handlers for a singular field.
static void add_handlers_for_singular_field(upb_handlers *h,
const upb_fielddef *f,
size_t offset,
size_t hasbit_off) {
static void add_handlers_for_singular_field(const Descriptor* desc,
upb_handlers* h,
const upb_fielddef* f,
size_t offset, size_t hasbit_off) {
// The offset we pass to UPB points to the start of the Message,
// rather than the start of where our data is stored.
int32_t hasbit = -1;
@ -586,23 +570,20 @@ static void add_handlers_for_singular_field(upb_handlers *h,
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES: {
bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset, hasbit));
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
attr.handler_data = newhandlerdata(h, offset, hasbit);
upb_handlers_setstartstr(h, f,
is_bytes ? bytes_handler : str_handler,
&attr);
upb_handlers_setstring(h, f, stringdata_handler, &attr);
upb_handlers_setendstr(h, f, stringdata_end_handler, &attr);
upb_handlerattr_uninit(&attr);
break;
}
case UPB_TYPE_MESSAGE: {
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
upb_handlerattr_sethandlerdata(&attr,
newsubmsghandlerdata(h, offset,
hasbit, f));
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
attr.handler_data = newsubmsghandlerdata(
h, offset, hasbit, field_type_class(desc->layout, f));
upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
upb_handlerattr_uninit(&attr);
break;
}
}
@ -612,36 +593,34 @@ static void add_handlers_for_singular_field(upb_handlers *h,
static void add_handlers_for_mapfield(upb_handlers* h,
const upb_fielddef* fielddef,
size_t offset,
Descriptor* desc) {
const Descriptor* desc) {
const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef);
map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc);
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
upb_handlers_addcleanup(h, hd, xfree);
upb_handlerattr_sethandlerdata(&attr, hd);
attr.handler_data = hd;
upb_handlers_setstartsubmsg(h, fielddef, startmapentry_handler, &attr);
upb_handlerattr_uninit(&attr);
}
// Adds handlers to a map-entry msgdef.
static void add_handlers_for_mapentry(const upb_msgdef* msgdef,
upb_handlers* h,
Descriptor* desc) {
static void add_handlers_for_mapentry(const upb_msgdef* msgdef, upb_handlers* h,
const Descriptor* desc) {
const upb_fielddef* key_field = map_entry_key(msgdef);
const upb_fielddef* value_field = map_entry_value(msgdef);
map_handlerdata_t* hd = new_map_handlerdata(0, msgdef, desc);
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
upb_handlers_addcleanup(h, hd, xfree);
upb_handlerattr_sethandlerdata(&attr, hd);
attr.handler_data = hd;
upb_handlers_setendmsg(h, endmap_handler, &attr);
add_handlers_for_singular_field(
h, key_field,
desc, h, key_field,
offsetof(map_parse_frame_t, key_storage),
MESSAGE_FIELD_NO_HASBIT);
add_handlers_for_singular_field(
h, value_field,
desc, h, value_field,
offsetof(map_parse_frame_t, value_storage),
MESSAGE_FIELD_NO_HASBIT);
}
@ -650,11 +629,11 @@ static void add_handlers_for_mapentry(const upb_msgdef* msgdef,
static void add_handlers_for_oneof_field(upb_handlers *h,
const upb_fielddef *f,
size_t offset,
size_t oneof_case_offset) {
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
upb_handlerattr_sethandlerdata(
&attr, newoneofhandlerdata(h, offset, oneof_case_offset, f));
size_t oneof_case_offset,
const Descriptor* desc) {
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
attr.handler_data =
newoneofhandlerdata(h, offset, oneof_case_offset, f, desc);
switch (upb_fielddef_type(f)) {
@ -689,8 +668,6 @@ static void add_handlers_for_oneof_field(upb_handlers *h,
break;
}
}
upb_handlerattr_uninit(&attr);
}
static bool unknown_field_handler(void* closure, const void* hd,
@ -708,11 +685,21 @@ static bool unknown_field_handler(void* closure, const void* hd,
return true;
}
static void add_handlers_for_message(const void *closure, upb_handlers *h) {
void add_handlers_for_message(const void *closure, upb_handlers *h) {
const VALUE descriptor_pool = (VALUE)closure;
const upb_msgdef* msgdef = upb_handlers_msgdef(h);
Descriptor* desc = ruby_to_Descriptor(get_def_obj((void*)msgdef));
Descriptor* desc =
ruby_to_Descriptor(get_msgdef_obj(descriptor_pool, msgdef));
upb_msg_field_iter i;
// Ensure layout exists. We may be invoked to create handlers for a given
// message if we are included as a submsg of another message type before our
// class is actually built, so to work around this, we just create the layout
// (and handlers, in the class-building function) on-demand.
if (desc->layout == NULL) {
desc->layout = create_layout(desc);
}
// If this is a mapentry message type, set up a special set of handlers and
// bail out of the normal (user-defined) message type handling.
if (upb_msgdef_mapentry(msgdef)) {
@ -720,15 +707,7 @@ static void add_handlers_for_message(const void *closure, upb_handlers *h) {
return;
}
// Ensure layout exists. We may be invoked to create handlers for a given
// message if we are included as a submsg of another message type before our
// class is actually built, so to work around this, we just create the layout
// (and handlers, in the class-building function) on-demand.
if (desc->layout == NULL) {
desc->layout = create_layout(desc->msgdef);
}
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
upb_handlers_setunknown(h, unknown_field_handler, &attr);
for (upb_msg_field_begin(&i, desc->msgdef);
@ -742,64 +721,51 @@ static void add_handlers_for_message(const void *closure, upb_handlers *h) {
size_t oneof_case_offset =
desc->layout->fields[upb_fielddef_index(f)].case_offset +
sizeof(MessageHeader);
add_handlers_for_oneof_field(h, f, offset, oneof_case_offset);
add_handlers_for_oneof_field(h, f, offset, oneof_case_offset, desc);
} else if (is_map_field(f)) {
add_handlers_for_mapfield(h, f, offset, desc);
} else if (upb_fielddef_isseq(f)) {
add_handlers_for_repeated_field(h, f, offset);
add_handlers_for_repeated_field(h, desc, f, offset);
} else {
add_handlers_for_singular_field(
h, f, offset, desc->layout->fields[upb_fielddef_index(f)].hasbit);
desc, h, f, offset,
desc->layout->fields[upb_fielddef_index(f)].hasbit);
}
}
}
// Creates upb handlers for populating a message.
static const upb_handlers *new_fill_handlers(Descriptor* desc,
const void* owner) {
// TODO(cfallin, haberman): once upb gets a caching/memoization layer for
// handlers, reuse subdef handlers so that e.g. if we already parse
// B-with-field-of-type-C, we don't have to rebuild the whole hierarchy to
// parse A-with-field-of-type-B-with-field-of-type-C.
return upb_handlers_newfrozen(desc->msgdef, owner,
add_handlers_for_message, NULL);
}
// Constructs the handlers for filling a message's data into an in-memory
// object.
const upb_handlers* get_fill_handlers(Descriptor* desc) {
if (!desc->fill_handlers) {
desc->fill_handlers =
new_fill_handlers(desc, &desc->fill_handlers);
}
return desc->fill_handlers;
}
// Constructs the upb decoder method for parsing messages of this type.
// This is called from the message class creation code.
const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor* desc,
const void* owner) {
const upb_handlers* handlers = get_fill_handlers(desc);
upb_pbdecodermethodopts opts;
upb_pbdecodermethodopts_init(&opts, handlers);
return upb_pbdecodermethod_new(&opts, owner);
DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
return upb_handlercache_get(pool->fill_handler_cache, desc->msgdef);
}
static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
if (desc->fill_method == NULL) {
desc->fill_method = new_fillmsg_decodermethod(
desc, &desc->fill_method);
}
return desc->fill_method;
DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
return upb_pbcodecache_get(pool->fill_method_cache, desc->msgdef);
}
static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
if (desc->json_fill_method == NULL) {
desc->json_fill_method =
upb_json_parsermethod_new(desc->msgdef, &desc->json_fill_method);
DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
return upb_json_codecache_get(pool->json_fill_method_cache, desc->msgdef);
}
static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
return upb_handlercache_get(pool->pb_serialize_handler_cache, desc->msgdef);
}
static const upb_handlers* msgdef_json_serialize_handlers(
Descriptor* desc, bool preserve_proto_fieldnames) {
DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
if (preserve_proto_fieldnames) {
return upb_handlercache_get(pool->json_serialize_handler_preserve_cache,
desc->msgdef);
} else {
return upb_handlercache_get(pool->json_serialize_handler_cache,
desc->msgdef);
}
return desc->json_fill_method;
}
@ -809,7 +775,8 @@ static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
// if any error occurs.
#define STACK_ENV_STACKBYTES 4096
typedef struct {
upb_env env;
upb_arena *arena;
upb_status status;
const char* ruby_error_template;
char allocbuf[STACK_ENV_STACKBYTES];
} stackenv;
@ -817,29 +784,22 @@ typedef struct {
static void stackenv_init(stackenv* se, const char* errmsg);
static void stackenv_uninit(stackenv* se);
// Callback invoked by upb if any error occurs during parsing or serialization.
static bool env_error_func(void* ud, const upb_status* status) {
stackenv* se = ud;
// Free the env -- rb_raise will longjmp up the stack past the encode/decode
// function so it would not otherwise have been freed.
stackenv_uninit(se);
// TODO(haberman): have a way to verify that this is actually a parse error,
// instead of just throwing "parse error" unconditionally.
rb_raise(cParseError, se->ruby_error_template, upb_status_errmsg(status));
// Never reached: rb_raise() always longjmp()s up the stack, past all of our
// code, back to Ruby.
return false;
}
static void stackenv_init(stackenv* se, const char* errmsg) {
se->ruby_error_template = errmsg;
upb_env_init2(&se->env, se->allocbuf, sizeof(se->allocbuf), NULL);
upb_env_seterrorfunc(&se->env, env_error_func, se);
se->arena =
upb_arena_init(se->allocbuf, sizeof(se->allocbuf), &upb_alloc_global);
upb_status_clear(&se->status);
}
static void stackenv_uninit(stackenv* se) {
upb_env_uninit(&se->env);
upb_arena_free(se->arena);
if (!upb_ok(&se->status)) {
// TODO(haberman): have a way to verify that this is actually a parse error,
// instead of just throwing "parse error" unconditionally.
VALUE errmsg = rb_str_new2(upb_status_errmsg(&se->status));
rb_raise(cParseError, se->ruby_error_template, errmsg);
}
}
/*
@ -870,10 +830,10 @@ VALUE Message_decode(VALUE klass, VALUE data) {
stackenv se;
upb_sink sink;
upb_pbdecoder* decoder;
stackenv_init(&se, "Error occurred during parsing: %s");
stackenv_init(&se, "Error occurred during parsing: %" PRIsVALUE);
upb_sink_reset(&sink, h, msg);
decoder = upb_pbdecoder_create(&se.env, method, &sink);
decoder = upb_pbdecoder_create(se.arena, method, sink, &se.status);
upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
upb_pbdecoder_input(decoder));
@ -891,8 +851,9 @@ VALUE Message_decode(VALUE klass, VALUE data) {
* format) under the interpretration given by this message class's definition
* and returns a message object with the corresponding field values.
*
* @param options [Hash] options for the decoder
* ignore_unknown_fields: set true to ignore unknown fields (default is to raise an error)
* @param options [Hash] options for the decoder
* ignore_unknown_fields: set true to ignore unknown fields (default is to
* raise an error)
*/
VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
@ -920,6 +881,7 @@ VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
if (TYPE(data) != T_STRING) {
rb_raise(rb_eArgError, "Expected string for JSON data.");
}
// TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
// convert, because string handlers pass data directly to message string
// fields.
@ -933,11 +895,11 @@ VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
upb_sink sink;
upb_json_parser* parser;
DescriptorPool* pool = ruby_to_DescriptorPool(generated_pool);
stackenv_init(&se, "Error occurred during parsing: %s");
stackenv_init(&se, "Error occurred during parsing: %" PRIsVALUE);
upb_sink_reset(&sink, get_fill_handlers(desc), msg);
parser = upb_json_parser_create(&se.env, method, pool->symtab,
&sink, ignore_unknown_fields);
parser = upb_json_parser_create(se.arena, method, pool->symtab, sink,
&se.status, RTEST(ignore_unknown_fields));
upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
upb_json_parser_input(parser));
@ -953,9 +915,8 @@ VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
/* msgvisitor *****************************************************************/
static void putmsg(VALUE msg, const Descriptor* desc,
upb_sink *sink, int depth, bool emit_defaults,
bool is_json, bool open_msg);
static void putmsg(VALUE msg, const Descriptor* desc, upb_sink sink, int depth,
bool emit_defaults, bool is_json, bool open_msg);
static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
upb_selector_t ret;
@ -964,7 +925,7 @@ static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
return ret;
}
static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) {
static void putstr(VALUE str, const upb_fielddef *f, upb_sink sink) {
upb_sink subsink;
if (str == Qnil) return;
@ -981,12 +942,12 @@ static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) {
upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str),
&subsink);
upb_sink_putstring(&subsink, getsel(f, UPB_HANDLER_STRING), RSTRING_PTR(str),
upb_sink_putstring(subsink, getsel(f, UPB_HANDLER_STRING), RSTRING_PTR(str),
RSTRING_LEN(str), NULL);
upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR));
}
static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink sink,
int depth, bool emit_defaults, bool is_json) {
upb_sink subsink;
VALUE descriptor;
@ -998,12 +959,12 @@ static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
subdesc = ruby_to_Descriptor(descriptor);
upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
putmsg(submsg, subdesc, &subsink, depth + 1, emit_defaults, is_json, true);
putmsg(submsg, subdesc, subsink, depth + 1, emit_defaults, is_json, true);
upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
}
static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
int depth, bool emit_defaults, bool is_json) {
static void putary(VALUE ary, const upb_fielddef* f, upb_sink sink, int depth,
bool emit_defaults, bool is_json) {
upb_sink subsink;
upb_fieldtype_t type = upb_fielddef_type(f);
upb_selector_t sel = 0;
@ -1024,9 +985,9 @@ static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
for (int i = 0; i < size; i++) {
void* memory = RepeatedField_index_native(ary, i);
switch (type) {
#define T(upbtypeconst, upbtype, ctype) \
case upbtypeconst: \
upb_sink_put##upbtype(&subsink, sel, *((ctype *)memory)); \
#define T(upbtypeconst, upbtype, ctype) \
case upbtypeconst: \
upb_sink_put##upbtype(subsink, sel, *((ctype*)memory)); \
break;
T(UPB_TYPE_FLOAT, float, float)
@ -1040,11 +1001,10 @@ static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
putstr(*((VALUE *)memory), f, &subsink);
putstr(*((VALUE *)memory), f, subsink);
break;
case UPB_TYPE_MESSAGE:
putsubmsg(*((VALUE *)memory), f, &subsink, depth,
emit_defaults, is_json);
putsubmsg(*((VALUE*)memory), f, subsink, depth, emit_defaults, is_json);
break;
#undef T
@ -1054,12 +1014,8 @@ static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
}
static void put_ruby_value(VALUE value,
const upb_fielddef *f,
VALUE type_class,
int depth,
upb_sink *sink,
bool emit_defaults,
static void put_ruby_value(VALUE value, const upb_fielddef* f, VALUE type_class,
int depth, upb_sink sink, bool emit_defaults,
bool is_json) {
if (depth > ENCODE_MAX_NESTING) {
rb_raise(rb_eRuntimeError,
@ -1109,8 +1065,8 @@ static void put_ruby_value(VALUE value,
}
}
static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
int depth, bool emit_defaults, bool is_json) {
static void putmap(VALUE map, const upb_fielddef* f, upb_sink sink, int depth,
bool emit_defaults, bool is_json) {
Map* self;
upb_sink subsink;
const upb_fielddef* key_field;
@ -1134,17 +1090,17 @@ static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
upb_status status;
upb_sink entry_sink;
upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
upb_sink_startsubmsg(subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
&entry_sink);
upb_sink_startmsg(&entry_sink);
upb_sink_startmsg(entry_sink);
put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink,
emit_defaults, is_json);
put_ruby_value(key, key_field, Qnil, depth + 1, entry_sink, emit_defaults,
is_json);
put_ruby_value(value, value_field, self->value_type_class, depth + 1,
&entry_sink, emit_defaults, is_json);
entry_sink, emit_defaults, is_json);
upb_sink_endmsg(&entry_sink, &status);
upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
upb_sink_endmsg(entry_sink, &status);
upb_sink_endsubmsg(subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
}
upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
@ -1153,8 +1109,8 @@ static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
static const upb_handlers* msgdef_json_serialize_handlers(
Descriptor* desc, bool preserve_proto_fieldnames);
static void putjsonany(VALUE msg_rb, const Descriptor* desc,
upb_sink* sink, int depth, bool emit_defaults) {
static void putjsonany(VALUE msg_rb, const Descriptor* desc, upb_sink sink,
int depth, bool emit_defaults) {
upb_status status;
MessageHeader* msg = NULL;
const upb_fielddef* type_field = upb_msgdef_itof(desc->msgdef, UPB_ANY_TYPE);
@ -1210,7 +1166,7 @@ static void putjsonany(VALUE msg_rb, const Descriptor* desc,
value_len = RSTRING_LEN(value_str_rb);
if (value_len > 0) {
VALUE payload_desc_rb = get_def_obj(payload_type);
VALUE payload_desc_rb = get_msgdef_obj(generated_pool, payload_type);
Descriptor* payload_desc = ruby_to_Descriptor(payload_desc_rb);
VALUE payload_class = Descriptor_msgclass(payload_desc_rb);
upb_sink subsink;
@ -1228,8 +1184,8 @@ static void putjsonany(VALUE msg_rb, const Descriptor* desc,
subsink.handlers =
msgdef_json_serialize_handlers(payload_desc, true);
subsink.closure = sink->closure;
putmsg(payload_msg_rb, payload_desc, &subsink, depth, emit_defaults, true,
subsink.closure = sink.closure;
putmsg(payload_msg_rb, payload_desc, subsink, depth, emit_defaults, true,
is_wellknown);
}
}
@ -1237,9 +1193,8 @@ static void putjsonany(VALUE msg_rb, const Descriptor* desc,
upb_sink_endmsg(sink, &status);
}
static void putmsg(VALUE msg_rb, const Descriptor* desc,
upb_sink *sink, int depth, bool emit_defaults,
bool is_json, bool open_msg) {
static void putmsg(VALUE msg_rb, const Descriptor* desc, upb_sink sink,
int depth, bool emit_defaults, bool is_json, bool open_msg) {
MessageHeader* msg;
upb_msg_field_iter i;
upb_status status;
@ -1322,20 +1277,19 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
} else {
upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
#define T(upbtypeconst, upbtype, ctype, default_value) \
case upbtypeconst: { \
ctype value = DEREF(msg, offset, ctype); \
bool is_default = false; \
if (upb_fielddef_haspresence(f)) { \
is_default = layout_has(desc->layout, Message_data(msg), f) == Qfalse; \
} else if (upb_msgdef_syntax(desc->msgdef) == UPB_SYNTAX_PROTO3) { \
is_default = default_value == value; \
} \
if (is_matching_oneof || emit_defaults || !is_default) { \
upb_sink_put##upbtype(sink, sel, value); \
} \
} \
break;
#define T(upbtypeconst, upbtype, ctype, default_value) \
case upbtypeconst: { \
ctype value = DEREF(msg, offset, ctype); \
bool is_default = false; \
if (upb_fielddef_haspresence(f)) { \
is_default = layout_has(desc->layout, Message_data(msg), f) == Qfalse; \
} else if (upb_msgdef_syntax(desc->msgdef) == UPB_SYNTAX_PROTO3) { \
is_default = default_value == value; \
} \
if (is_matching_oneof || emit_defaults || !is_default) { \
upb_sink_put##upbtype(sink, sel, value); \
} \
} break;
switch (upb_fielddef_type(f)) {
T(UPB_TYPE_FLOAT, float, float, 0.0)
@ -1367,33 +1321,6 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
}
}
static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
if (desc->pb_serialize_handlers == NULL) {
desc->pb_serialize_handlers =
upb_pb_encoder_newhandlers(desc->msgdef, &desc->pb_serialize_handlers);
}
return desc->pb_serialize_handlers;
}
static const upb_handlers* msgdef_json_serialize_handlers(
Descriptor* desc, bool preserve_proto_fieldnames) {
if (preserve_proto_fieldnames) {
if (desc->json_serialize_handlers == NULL) {
desc->json_serialize_handlers =
upb_json_printer_newhandlers(
desc->msgdef, true, &desc->json_serialize_handlers);
}
return desc->json_serialize_handlers;
} else {
if (desc->json_serialize_handlers_preserve == NULL) {
desc->json_serialize_handlers_preserve =
upb_json_printer_newhandlers(
desc->msgdef, false, &desc->json_serialize_handlers_preserve);
}
return desc->json_serialize_handlers_preserve;
}
}
/*
* call-seq:
* MessageClass.encode(msg) => bytes
@ -1416,8 +1343,8 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) {
upb_pb_encoder* encoder;
VALUE ret;
stackenv_init(&se, "Error occurred during encoding: %s");
encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
stackenv_init(&se, "Error occurred during encoding: %" PRIsVALUE);
encoder = upb_pb_encoder_create(se.arena, serialize_handlers, sink.sink);
putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0, false, false, true);
@ -1474,8 +1401,8 @@ VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
stackenv se;
VALUE ret;
stackenv_init(&se, "Error occurred during encoding: %s");
printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink);
stackenv_init(&se, "Error occurred during encoding: %" PRIsVALUE);
printer = upb_json_printer_create(se.arena, serialize_handlers, sink.sink);
putmsg(msg_rb, desc, upb_json_printer_input(printer), 0,
RTEST(emit_defaults), true, true);

View File

@ -60,6 +60,11 @@ rb_data_type_t Message_type = {
VALUE Message_alloc(VALUE klass) {
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
Descriptor* desc = ruby_to_Descriptor(descriptor);
if (desc->layout == NULL) {
desc->layout = create_layout(desc);
}
MessageHeader* msg = (MessageHeader*)ALLOC_N(
uint8_t, sizeof(MessageHeader) + desc->layout->size);
VALUE ret;
@ -276,7 +281,7 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
} else if (accessor_type == METHOD_PRESENCE) {
return layout_has(self->descriptor->layout, Message_data(self), f);
} else if (accessor_type == METHOD_ENUM_GETTER) {
VALUE enum_type = field_type_class(f);
VALUE enum_type = field_type_class(self->descriptor->layout, f);
VALUE method = rb_intern("const_get");
VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
@ -320,15 +325,13 @@ VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
}
}
VALUE create_submsg_from_hash(const upb_fielddef *f, VALUE hash) {
const upb_def *d = upb_fielddef_subdef(f);
VALUE create_submsg_from_hash(const MessageLayout* layout,
const upb_fielddef* f, VALUE hash) {
const upb_msgdef *d = upb_fielddef_msgsubdef(f);
assert(d != NULL);
VALUE descriptor = get_def_obj(d);
VALUE msgclass = rb_funcall(descriptor, rb_intern("msgclass"), 0, NULL);
VALUE args[1] = { hash };
return rb_class_new_instance(1, args, msgclass);
return rb_class_new_instance(1, args, field_type_class(layout, f));
}
int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
@ -378,14 +381,14 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
for (int i = 0; i < RARRAY_LEN(val); i++) {
VALUE entry = rb_ary_entry(val, i);
if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
entry = create_submsg_from_hash(f, entry);
entry = create_submsg_from_hash(self->descriptor->layout, f, entry);
}
RepeatedField_push(ary, entry);
}
} else {
if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
val = create_submsg_from_hash(f, val);
val = create_submsg_from_hash(self->descriptor->layout, f, val);
}
layout_set(self->descriptor->layout, Message_data(self), f, val);
@ -630,17 +633,11 @@ VALUE Message_descriptor(VALUE klass) {
return rb_ivar_get(klass, descriptor_instancevar_interned);
}
VALUE build_class_from_descriptor(Descriptor* desc) {
VALUE build_class_from_descriptor(VALUE descriptor) {
Descriptor* desc = ruby_to_Descriptor(descriptor);
const char *name;
VALUE klass;
if (desc->layout == NULL) {
desc->layout = create_layout(desc->msgdef);
}
if (desc->fill_method == NULL) {
desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
}
name = upb_msgdef_fullname(desc->msgdef);
if (name == NULL) {
rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
@ -651,8 +648,7 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
// their own toplevel constant class name.
rb_intern("Message"),
rb_cObject);
rb_ivar_set(klass, descriptor_instancevar_interned,
get_def_obj(desc->msgdef));
rb_ivar_set(klass, descriptor_instancevar_interned, descriptor);
rb_define_alloc_func(klass, Message_alloc);
rb_require("google/protobuf/message_exts");
rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
@ -737,7 +733,8 @@ VALUE enum_descriptor(VALUE self) {
return rb_ivar_get(self, descriptor_instancevar_interned);
}
VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
VALUE build_module_from_enumdesc(VALUE _enumdesc) {
EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(_enumdesc);
VALUE mod = rb_define_module_id(
rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
@ -758,8 +755,7 @@ VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
rb_ivar_set(mod, descriptor_instancevar_interned,
get_def_obj(enumdesc->enumdef));
rb_ivar_set(mod, descriptor_instancevar_interned, _enumdesc);
return mod;
}

View File

@ -30,26 +30,10 @@
#include "protobuf.h"
// -----------------------------------------------------------------------------
// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
// instances.
// -----------------------------------------------------------------------------
// This is a hash table from def objects (encoded by converting pointers to
// Ruby integers) to MessageDef/EnumDef instances (as Ruby values).
VALUE upb_def_to_ruby_obj_map;
VALUE cError;
VALUE cParseError;
VALUE cTypeError;
void add_def_obj(const void* def, VALUE value) {
rb_hash_aset(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def), value);
}
VALUE get_def_obj(const void* def) {
return rb_hash_aref(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def));
}
VALUE c_only_cookie;
// -----------------------------------------------------------------------------
// Utilities.
@ -116,6 +100,6 @@ void Init_protobuf_c() {
kRubyStringASCIIEncoding = rb_usascii_encoding();
kRubyString8bitEncoding = rb_ascii8bit_encoding();
rb_gc_register_address(&upb_def_to_ruby_obj_map);
upb_def_to_ruby_obj_map = rb_hash_new();
rb_gc_register_address(&c_only_cookie);
c_only_cookie = rb_class_new_instance(0, NULL, rb_cObject);
}

View File

@ -107,62 +107,68 @@ typedef struct Builder Builder;
// -----------------------------------------------------------------------------
struct DescriptorPool {
VALUE def_to_descriptor; // Hash table of def* -> Ruby descriptor.
upb_symtab* symtab;
upb_handlercache* fill_handler_cache;
upb_handlercache* pb_serialize_handler_cache;
upb_handlercache* json_serialize_handler_cache;
upb_handlercache* json_serialize_handler_preserve_cache;
upb_pbcodecache* fill_method_cache;
upb_json_codecache* json_fill_method_cache;
};
struct Descriptor {
const upb_msgdef* msgdef;
MessageLayout* layout;
VALUE klass; // begins as nil
const upb_handlers* fill_handlers;
const upb_pbdecodermethod* fill_method;
const upb_json_parsermethod* json_fill_method;
const upb_handlers* pb_serialize_handlers;
const upb_handlers* json_serialize_handlers;
const upb_handlers* json_serialize_handlers_preserve;
VALUE klass;
VALUE descriptor_pool;
};
struct FileDescriptor {
const upb_filedef* filedef;
VALUE descriptor_pool; // Owns the upb_filedef.
};
struct FieldDescriptor {
const upb_fielddef* fielddef;
VALUE descriptor_pool; // Owns the upb_fielddef.
};
struct OneofDescriptor {
const upb_oneofdef* oneofdef;
VALUE descriptor_pool; // Owns the upb_oneofdef.
};
struct EnumDescriptor {
const upb_enumdef* enumdef;
VALUE module; // begins as nil
VALUE descriptor_pool; // Owns the upb_enumdef.
};
struct MessageBuilderContext {
VALUE descriptor;
VALUE builder;
google_protobuf_DescriptorProto* msg_proto;
VALUE file_builder;
};
struct OneofBuilderContext {
VALUE descriptor;
VALUE builder;
int oneof_index;
VALUE message_builder;
};
struct EnumBuilderContext {
VALUE enumdesc;
google_protobuf_EnumDescriptorProto* enum_proto;
VALUE file_builder;
};
struct FileBuilderContext {
VALUE pending_list;
VALUE file_descriptor;
VALUE builder;
upb_arena *arena;
google_protobuf_FileDescriptorProto* file_proto;
VALUE descriptor_pool;
};
struct Builder {
VALUE pending_list;
VALUE default_file_descriptor;
upb_def** defs; // used only while finalizing
VALUE descriptor_pool;
VALUE default_file_builder;
};
extern VALUE cDescriptorPool;
@ -191,7 +197,6 @@ void DescriptorPool_free(void* _self);
VALUE DescriptorPool_alloc(VALUE klass);
void DescriptorPool_register(VALUE module);
DescriptorPool* ruby_to_DescriptorPool(VALUE value);
VALUE DescriptorPool_add(VALUE _self, VALUE def);
VALUE DescriptorPool_build(int argc, VALUE* argv, VALUE _self);
VALUE DescriptorPool_lookup(VALUE _self, VALUE name);
VALUE DescriptorPool_generated_pool(VALUE _self);
@ -203,13 +208,11 @@ void Descriptor_free(void* _self);
VALUE Descriptor_alloc(VALUE klass);
void Descriptor_register(VALUE module);
Descriptor* ruby_to_Descriptor(VALUE value);
VALUE Descriptor_initialize(VALUE _self, VALUE file_descriptor_rb);
VALUE Descriptor_initialize(VALUE _self, VALUE cookie, VALUE descriptor_pool,
VALUE ptr);
VALUE Descriptor_name(VALUE _self);
VALUE Descriptor_name_set(VALUE _self, VALUE str);
VALUE Descriptor_each(VALUE _self);
VALUE Descriptor_lookup(VALUE _self, VALUE name);
VALUE Descriptor_add_field(VALUE _self, VALUE obj);
VALUE Descriptor_add_oneof(VALUE _self, VALUE obj);
VALUE Descriptor_each_oneof(VALUE _self);
VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name);
VALUE Descriptor_msgclass(VALUE _self);
@ -221,28 +224,24 @@ void FileDescriptor_free(void* _self);
VALUE FileDescriptor_alloc(VALUE klass);
void FileDescriptor_register(VALUE module);
FileDescriptor* ruby_to_FileDescriptor(VALUE value);
VALUE FileDescriptor_initialize(int argc, VALUE* argv, VALUE _self);
VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie,
VALUE descriptor_pool, VALUE ptr);
VALUE FileDescriptor_name(VALUE _self);
VALUE FileDescriptor_syntax(VALUE _self);
VALUE FileDescriptor_syntax_set(VALUE _self, VALUE syntax);
void FieldDescriptor_mark(void* _self);
void FieldDescriptor_free(void* _self);
VALUE FieldDescriptor_alloc(VALUE klass);
void FieldDescriptor_register(VALUE module);
FieldDescriptor* ruby_to_FieldDescriptor(VALUE value);
VALUE FieldDescriptor_initialize(VALUE _self, VALUE cookie,
VALUE descriptor_pool, VALUE ptr);
VALUE FieldDescriptor_name(VALUE _self);
VALUE FieldDescriptor_name_set(VALUE _self, VALUE str);
VALUE FieldDescriptor_type(VALUE _self);
VALUE FieldDescriptor_type_set(VALUE _self, VALUE type);
VALUE FieldDescriptor_default(VALUE _self);
VALUE FieldDescriptor_default_set(VALUE _self, VALUE default_value);
VALUE FieldDescriptor_label(VALUE _self);
VALUE FieldDescriptor_label_set(VALUE _self, VALUE label);
VALUE FieldDescriptor_number(VALUE _self);
VALUE FieldDescriptor_number_set(VALUE _self, VALUE number);
VALUE FieldDescriptor_submsg_name(VALUE _self);
VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value);
VALUE FieldDescriptor_subtype(VALUE _self);
VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb);
VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb);
@ -256,21 +255,20 @@ void OneofDescriptor_free(void* _self);
VALUE OneofDescriptor_alloc(VALUE klass);
void OneofDescriptor_register(VALUE module);
OneofDescriptor* ruby_to_OneofDescriptor(VALUE value);
VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie,
VALUE descriptor_pool, VALUE ptr);
VALUE OneofDescriptor_name(VALUE _self);
VALUE OneofDescriptor_name_set(VALUE _self, VALUE value);
VALUE OneofDescriptor_add_field(VALUE _self, VALUE field);
VALUE OneofDescriptor_each(VALUE _self, VALUE field);
void EnumDescriptor_mark(void* _self);
void EnumDescriptor_free(void* _self);
VALUE EnumDescriptor_alloc(VALUE klass);
VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie,
VALUE descriptor_pool, VALUE ptr);
void EnumDescriptor_register(VALUE module);
EnumDescriptor* ruby_to_EnumDescriptor(VALUE value);
VALUE EnumDescriptor_initialize(VALUE _self, VALUE file_descriptor_rb);
VALUE EnumDescriptor_file_descriptor(VALUE _self);
VALUE EnumDescriptor_name(VALUE _self);
VALUE EnumDescriptor_name_set(VALUE _self, VALUE str);
VALUE EnumDescriptor_add_value(VALUE _self, VALUE name, VALUE number);
VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name);
VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number);
VALUE EnumDescriptor_each(VALUE _self);
@ -283,8 +281,8 @@ VALUE MessageBuilderContext_alloc(VALUE klass);
void MessageBuilderContext_register(VALUE module);
MessageBuilderContext* ruby_to_MessageBuilderContext(VALUE value);
VALUE MessageBuilderContext_initialize(VALUE _self,
VALUE descriptor,
VALUE builder);
VALUE _file_builder,
VALUE name);
VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self);
VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self);
VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self);
@ -306,15 +304,19 @@ void EnumBuilderContext_free(void* _self);
VALUE EnumBuilderContext_alloc(VALUE klass);
void EnumBuilderContext_register(VALUE module);
EnumBuilderContext* ruby_to_EnumBuilderContext(VALUE value);
VALUE EnumBuilderContext_initialize(VALUE _self, VALUE enumdesc);
VALUE EnumBuilderContext_initialize(VALUE _self, VALUE _file_builder,
VALUE name);
VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number);
void FileBuilderContext_mark(void* _self);
void FileBuilderContext_free(void* _self);
VALUE FileBuilderContext_alloc(VALUE klass);
void FileBuilderContext_register(VALUE module);
VALUE FileBuilderContext_initialize(VALUE _self, VALUE file_descriptor,
VALUE builder);
FileBuilderContext* ruby_to_FileBuilderContext(VALUE _self);
upb_strview FileBuilderContext_strdup(VALUE _self, VALUE rb_str);
upb_strview FileBuilderContext_strdup_name(VALUE _self, VALUE rb_str);
VALUE FileBuilderContext_initialize(VALUE _self, VALUE descriptor_pool,
VALUE name, VALUE options);
VALUE FileBuilderContext_add_message(VALUE _self, VALUE name);
VALUE FileBuilderContext_add_enum(VALUE _self, VALUE name);
VALUE FileBuilderContext_pending_descriptors(VALUE _self);
@ -324,7 +326,8 @@ void Builder_free(void* _self);
VALUE Builder_alloc(VALUE klass);
void Builder_register(VALUE module);
Builder* ruby_to_Builder(VALUE value);
VALUE Builder_initialize(VALUE _self);
VALUE Builder_build(VALUE _self);
VALUE Builder_initialize(VALUE _self, VALUE descriptor_pool);
VALUE Builder_add_file(int argc, VALUE *argv, VALUE _self);
VALUE Builder_add_message(VALUE _self, VALUE name);
VALUE Builder_add_enum(VALUE _self, VALUE name);
@ -368,7 +371,7 @@ extern rb_encoding* kRubyStringUtf8Encoding;
extern rb_encoding* kRubyStringASCIIEncoding;
extern rb_encoding* kRubyString8bitEncoding;
VALUE field_type_class(const upb_fielddef* field);
VALUE field_type_class(const MessageLayout* layout, const upb_fielddef* field);
#define MAP_KEY_FIELD 1
#define MAP_VALUE_FIELD 2
@ -501,13 +504,15 @@ struct MessageField {
size_t hasbit;
};
// MessageLayout is owned by the enclosing Descriptor, which must outlive us.
struct MessageLayout {
const Descriptor* desc;
const upb_msgdef* msgdef;
MessageField* fields;
size_t size;
};
MessageLayout* create_layout(const upb_msgdef* msgdef);
MessageLayout* create_layout(const Descriptor* desc);
void free_layout(MessageLayout* layout);
bool field_contains_hasbit(MessageLayout* layout,
const upb_fielddef* field);
@ -556,7 +561,7 @@ struct MessageHeader {
extern rb_data_type_t Message_type;
VALUE build_class_from_descriptor(Descriptor* descriptor);
VALUE build_class_from_descriptor(VALUE descriptor);
void* Message_data(void* msg);
void Message_mark(void* self);
void Message_free(void* self);
@ -580,12 +585,13 @@ VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass);
VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb);
VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj);
VALUE build_module_from_enumdesc(EnumDescriptor* enumdef);
VALUE build_module_from_enumdesc(VALUE _enumdesc);
VALUE enum_lookup(VALUE self, VALUE number);
VALUE enum_resolve(VALUE self, VALUE sym);
const upb_pbdecodermethod *new_fillmsg_decodermethod(
Descriptor* descriptor, const void *owner);
void add_handlers_for_message(const void *closure, upb_handlers *h);
// Maximum depth allowed during encoding, to avoid stack overflows due to
// cycles.
@ -595,8 +601,11 @@ const upb_pbdecodermethod *new_fillmsg_decodermethod(
// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
// instances.
// -----------------------------------------------------------------------------
void add_def_obj(const void* def, VALUE value);
VALUE get_def_obj(const void* def);
VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def);
VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def);
VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def);
VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def);
VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def);
// -----------------------------------------------------------------------------
// Utilities.
@ -612,4 +621,9 @@ void check_upb_status(const upb_status* status, const char* msg);
extern ID descriptor_instancevar_interned;
// A distinct object that is not accessible from Ruby. We use this as a
// constructor argument to enforce that certain objects cannot be created from
// Ruby.
extern VALUE c_only_cookie;
#endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__

View File

@ -430,8 +430,10 @@ static size_t align_up_to(size_t offset, size_t granularity) {
return (offset + granularity - 1) & ~(granularity - 1);
}
MessageLayout* create_layout(const upb_msgdef* msgdef) {
MessageLayout* create_layout(const Descriptor* desc) {
const upb_msgdef *msgdef = desc->msgdef;
MessageLayout* layout = ALLOC(MessageLayout);
layout->desc = desc;
int nfields = upb_msgdef_numfields(msgdef);
upb_msg_field_iter it;
upb_msg_oneof_iter oit;
@ -448,7 +450,7 @@ MessageLayout* create_layout(const upb_msgdef* msgdef) {
layout->fields[upb_fielddef_index(field)].hasbit = hasbit++;
} else {
layout->fields[upb_fielddef_index(field)].hasbit =
MESSAGE_FIELD_NO_HASBIT;
MESSAGE_FIELD_NO_HASBIT;
}
}
@ -537,28 +539,25 @@ MessageLayout* create_layout(const upb_msgdef* msgdef) {
}
layout->size = off;
layout->msgdef = msgdef;
upb_msgdef_ref(layout->msgdef, &layout->msgdef);
return layout;
}
void free_layout(MessageLayout* layout) {
xfree(layout->fields);
upb_msgdef_unref(layout->msgdef, &layout->msgdef);
xfree(layout);
}
VALUE field_type_class(const upb_fielddef* field) {
VALUE field_type_class(const MessageLayout* layout, const upb_fielddef* field) {
VALUE type_class = Qnil;
if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
VALUE submsgdesc =
get_def_obj(upb_fielddef_subdef(field));
VALUE submsgdesc = get_msgdef_obj(layout->desc->descriptor_pool,
upb_fielddef_msgsubdef(field));
type_class = Descriptor_msgclass(submsgdesc);
} else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
VALUE subenumdesc =
get_def_obj(upb_fielddef_subdef(field));
VALUE subenumdesc = get_enumdef_obj(layout->desc->descriptor_pool,
upb_fielddef_enumsubdef(field));
type_class = EnumDescriptor_enummodule(subenumdesc);
}
return type_class;
@ -632,7 +631,7 @@ void layout_clear(MessageLayout* layout,
const upb_fielddef* key_field = map_field_key(field);
const upb_fielddef* value_field = map_field_value(field);
VALUE type_class = field_type_class(value_field);
VALUE type_class = field_type_class(layout, value_field);
if (type_class != Qnil) {
VALUE args[3] = {
@ -653,7 +652,7 @@ void layout_clear(MessageLayout* layout,
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
VALUE ary = Qnil;
VALUE type_class = field_type_class(field);
VALUE type_class = field_type_class(layout, field);
if (type_class != Qnil) {
VALUE args[2] = {
@ -668,9 +667,9 @@ void layout_clear(MessageLayout* layout,
DEREF(memory, VALUE) = ary;
} else {
native_slot_set(upb_fielddef_name(field),
upb_fielddef_type(field), field_type_class(field),
memory, layout_get_default(field));
native_slot_set(upb_fielddef_name(field), upb_fielddef_type(field),
field_type_class(layout, field), memory,
layout_get_default(field));
}
}
@ -728,20 +727,19 @@ VALUE layout_get(MessageLayout* layout,
return layout_get_default(field);
}
return native_slot_get(upb_fielddef_type(field),
field_type_class(field),
memory);
field_type_class(layout, field), memory);
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
return *((VALUE *)memory);
} else if (!field_set) {
return layout_get_default(field);
} else {
return native_slot_get(upb_fielddef_type(field),
field_type_class(field),
memory);
field_type_class(layout, field), memory);
}
}
static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
static void check_repeated_field_type(const MessageLayout* layout, VALUE val,
const upb_fielddef* field) {
RepeatedField* self;
assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED);
@ -755,25 +753,13 @@ static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
rb_raise(cTypeError, "Repeated field array has wrong element type");
}
if (self->field_type == UPB_TYPE_MESSAGE) {
if (self->field_type_class !=
Descriptor_msgclass(get_def_obj(upb_fielddef_subdef(field)))) {
rb_raise(cTypeError,
"Repeated field array has wrong message class");
}
}
if (self->field_type == UPB_TYPE_ENUM) {
if (self->field_type_class !=
EnumDescriptor_enummodule(get_def_obj(upb_fielddef_subdef(field)))) {
rb_raise(cTypeError,
"Repeated field array has wrong enum class");
}
if (self->field_type_class != field_type_class(layout, field)) {
rb_raise(cTypeError, "Repeated field array has wrong message/enum class");
}
}
static void check_map_field_type(VALUE val, const upb_fielddef* field) {
static void check_map_field_type(const MessageLayout* layout, VALUE val,
const upb_fielddef* field) {
const upb_fielddef* key_field = map_field_key(field);
const upb_fielddef* value_field = map_field_value(field);
Map* self;
@ -790,17 +776,11 @@ static void check_map_field_type(VALUE val, const upb_fielddef* field) {
if (self->value_type != upb_fielddef_type(value_field)) {
rb_raise(cTypeError, "Map value type does not match field's value type");
}
if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE ||
upb_fielddef_type(value_field) == UPB_TYPE_ENUM) {
if (self->value_type_class !=
get_def_obj(upb_fielddef_subdef(value_field))) {
rb_raise(cTypeError,
"Map value type has wrong message/enum class");
}
if (self->value_type_class != field_type_class(layout, value_field)) {
rb_raise(cTypeError, "Map value type has wrong message/enum class");
}
}
void layout_set(MessageLayout* layout,
void* storage,
const upb_fielddef* field,
@ -828,20 +808,19 @@ void layout_set(MessageLayout* layout,
// and case number are altered atomically (w.r.t. the Ruby VM).
native_slot_set_value_and_case(
upb_fielddef_name(field),
upb_fielddef_type(field), field_type_class(field),
upb_fielddef_type(field), field_type_class(layout, field),
memory, val,
oneof_case, upb_fielddef_number(field));
}
} else if (is_map_field(field)) {
check_map_field_type(val, field);
check_map_field_type(layout, val, field);
DEREF(memory, VALUE) = val;
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
check_repeated_field_type(val, field);
check_repeated_field_type(layout, val, field);
DEREF(memory, VALUE) = val;
} else {
native_slot_set(upb_fielddef_name(field),
upb_fielddef_type(field), field_type_class(field),
memory, val);
native_slot_set(upb_fielddef_name(field), upb_fielddef_type(field),
field_type_class(layout, field), memory, val);
}
if (layout->fields[upb_fielddef_index(field)].hasbit !=

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -50,6 +50,72 @@ else
rescue LoadError
require 'google/protobuf_c'
end
module Google
module Protobuf
module Internal
def self.infer_package(names)
# Package is longest common prefix ending in '.', if any.
min, max = names.minmax
last_common_dot = nil
min.size.times { |i|
if min[i] != max[i] then break end
if min[i] == ?. then last_common_dot = i end
}
if last_common_dot
return min.slice(0, last_common_dot)
end
end
class NestingBuilder
def initialize(msg_names, enum_names)
@to_pos = {nil=>nil}
@msg_children = Hash.new { |hash, key| hash[key] = [] }
@enum_children = Hash.new { |hash, key| hash[key] = [] }
msg_names.each_with_index { |name, idx| @to_pos[name] = idx }
enum_names.each_with_index { |name, idx| @to_pos[name] = idx }
msg_names.each { |name| @msg_children[parent(name)] << name }
enum_names.each { |name| @enum_children[parent(name)] << name }
end
def build(package)
return build_msg(package)
end
private
def build_msg(msg)
return {
:pos => @to_pos[msg],
:msgs => @msg_children[msg].map { |child| build_msg(child) },
:enums => @enum_children[msg].map { |child| @to_pos[child] },
}
end
private
def parent(name)
idx = name.rindex(?.)
if idx
return name.slice(0, idx)
else
return nil
end
end
end
def self.fixup_descriptor(package, msg_names, enum_names)
if package.nil?
package = self.infer_package(msg_names + enum_names)
end
nesting = NestingBuilder.new(msg_names, enum_names).build(package)
return package, nesting
end
end
end
end
end
require 'google/protobuf/repeated_field'

View File

@ -17,7 +17,6 @@ module BasicTest
add_message "BadFieldNames" do
optional :dup, :int32, 1
optional :class, :int32, 2
optional :"a.b", :int32, 3
end
end
@ -351,11 +350,6 @@ module BasicTest
assert nil != file_descriptor
assert_equal "tests/basic_test.proto", file_descriptor.name
assert_equal :proto3, file_descriptor.syntax
file_descriptor = BadFieldNames.descriptor.file_descriptor
assert nil != file_descriptor
assert_equal nil, file_descriptor.name
assert_equal :proto3, file_descriptor.syntax
end
def test_map_freeze

View File

@ -18,7 +18,6 @@ module BasicTestProto2
add_message "BadFieldNames" do
optional :dup, :int32, 1
optional :class, :int32, 2
optional :"a.b", :int32, 3
end
end
end

View File

@ -807,7 +807,7 @@ module CommonTests
proto_module::TestMessage2.new(:foo => 2)])
data = proto_module::TestMessage.encode m
m2 = proto_module::TestMessage.decode data
assert m == m2
assert_equal m, m2
data = Google::Protobuf.encode m
m2 = Google::Protobuf.decode(proto_module::TestMessage, data)
@ -902,8 +902,6 @@ module CommonTests
assert m['class'] == 2
m['dup'] = 3
assert m['dup'] == 3
m['a.b'] = 4
assert m['a.b'] == 4
end
def test_int_ranges
@ -1084,9 +1082,7 @@ module CommonTests
json_text = proto_module::TestMessage.encode_json(m)
m2 = proto_module::TestMessage.decode_json(json_text)
puts m.inspect
puts m2.inspect
assert m == m2
assert_equal m, m2
# Crash case from GitHub issue 283.
bar = proto_module::Bar.new(msg: "bar")
@ -1132,7 +1128,7 @@ module CommonTests
actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
assert JSON.parse(actual, :symbolize_names => true) == expected
assert_equal expected, JSON.parse(actual, :symbolize_names => true)
end
def test_json_emit_defaults_submsg
@ -1167,7 +1163,7 @@ module CommonTests
actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
assert JSON.parse(actual, :symbolize_names => true) == expected
assert_equal expected, JSON.parse(actual, :symbolize_names => true)
end
def test_json_emit_defaults_repeated_submsg
@ -1201,7 +1197,7 @@ module CommonTests
actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
assert JSON.parse(actual, :symbolize_names => true) == expected
assert_equal expected, JSON.parse(actual, :symbolize_names => true)
end
def value_from_ruby(value)

View File

@ -10,11 +10,11 @@ require 'generated_code_pb'
class TestTypeErrors < Test::Unit::TestCase
def test_bad_string
check_error Google::Protobuf::TypeError,
"Invalid argument for string field 'optional_string' (given Integer)." do
"Invalid argument for string field 'optional_string' (given Fixnum)." do
A::B::C::TestMessage.new(optional_string: 4)
end
check_error Google::Protobuf::TypeError,
"Invalid argument for string field 'oneof_string' (given Integer)." do
"Invalid argument for string field 'oneof_string' (given Fixnum)." do
A::B::C::TestMessage.new(oneof_string: 4)
end
check_error ArgumentError,
@ -151,7 +151,7 @@ class TestTypeErrors < Test::Unit::TestCase
def test_bad_msg
check_error Google::Protobuf::TypeError,
"Invalid type Integer to assign to submessage field 'optional_msg'." do
"Invalid type Fixnum to assign to submessage field 'optional_msg'." do
A::B::C::TestMessage.new(optional_msg: 2)
end
check_error Google::Protobuf::TypeError,