Support oneofs in MRI Ruby C extension.
This commit is contained in:
parent
5446deaea7
commit
fcd8889d5b
8 changed files with 1836 additions and 229 deletions
|
@ -65,6 +65,10 @@ static upb_fielddef* check_field_notfrozen(const upb_fielddef* def) {
|
|||
return (upb_fielddef*)check_notfrozen((const upb_def*)def);
|
||||
}
|
||||
|
||||
static upb_oneofdef* check_oneof_notfrozen(const upb_oneofdef* def) {
|
||||
return (upb_oneofdef*)check_notfrozen((const upb_def*)def);
|
||||
}
|
||||
|
||||
static upb_enumdef* check_enum_notfrozen(const upb_enumdef* def) {
|
||||
return (upb_enumdef*)check_notfrozen((const upb_def*)def);
|
||||
}
|
||||
|
@ -282,6 +286,9 @@ void Descriptor_register(VALUE module) {
|
|||
rb_define_method(klass, "each", Descriptor_each, 0);
|
||||
rb_define_method(klass, "lookup", Descriptor_lookup, 1);
|
||||
rb_define_method(klass, "add_field", Descriptor_add_field, 1);
|
||||
rb_define_method(klass, "add_oneof", Descriptor_add_oneof, 1);
|
||||
rb_define_method(klass, "oneofs", Descriptor_oneofs, 0);
|
||||
rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1);
|
||||
rb_define_method(klass, "msgclass", Descriptor_msgclass, 0);
|
||||
rb_define_method(klass, "name", Descriptor_name, 0);
|
||||
rb_define_method(klass, "name=", Descriptor_name_set, 1);
|
||||
|
@ -328,10 +335,10 @@ VALUE Descriptor_name_set(VALUE _self, VALUE str) {
|
|||
VALUE Descriptor_each(VALUE _self) {
|
||||
DEFINE_SELF(Descriptor, self, _self);
|
||||
|
||||
upb_msg_iter it;
|
||||
for (upb_msg_begin(&it, self->msgdef);
|
||||
!upb_msg_done(&it);
|
||||
upb_msg_next(&it)) {
|
||||
upb_msg_field_iter it;
|
||||
for (upb_msg_field_begin(&it, self->msgdef);
|
||||
!upb_msg_field_done(&it);
|
||||
upb_msg_field_next(&it)) {
|
||||
const upb_fielddef* field = upb_msg_iter_field(&it);
|
||||
VALUE obj = get_def_obj(field);
|
||||
rb_yield(obj);
|
||||
|
@ -360,7 +367,7 @@ VALUE Descriptor_lookup(VALUE _self, VALUE name) {
|
|||
* call-seq:
|
||||
* Descriptor.add_field(field) => nil
|
||||
*
|
||||
* Adds the given FieldDescriptor to this message type. The descriptor must not
|
||||
* Adds the given FieldDescriptor to this message type. This descriptor must not
|
||||
* have been added to a pool yet. Raises an exception if a field with the same
|
||||
* name or number already exists. Sub-type references (e.g. for fields of type
|
||||
* message) are not resolved at this point.
|
||||
|
@ -377,6 +384,67 @@ VALUE Descriptor_add_field(VALUE _self, VALUE obj) {
|
|||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.add_oneof(oneof) => nil
|
||||
*
|
||||
* Adds the given OneofDescriptor to this message type. This descriptor must not
|
||||
* have been added to a pool yet. Raises an exception if a oneof with the same
|
||||
* name already exists, or if any of the oneof's fields' names or numbers
|
||||
* conflict with an existing field in this message type. All fields in the oneof
|
||||
* are added to the message descriptor. Sub-type references (e.g. for fields of
|
||||
* type message) are not resolved at this point.
|
||||
*/
|
||||
VALUE Descriptor_add_oneof(VALUE _self, VALUE obj) {
|
||||
DEFINE_SELF(Descriptor, self, _self);
|
||||
upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef);
|
||||
OneofDescriptor* def = ruby_to_OneofDescriptor(obj);
|
||||
upb_oneofdef* mut_oneof_def = check_oneof_notfrozen(def->oneofdef);
|
||||
CHECK_UPB(
|
||||
upb_msgdef_addoneof(mut_def, mut_oneof_def, NULL, &status),
|
||||
"Adding oneof to Descriptor failed");
|
||||
add_def_obj(def->oneofdef, obj);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.oneofs => list of OneofDescriptors
|
||||
*
|
||||
* Returns a list of OneofDescriptors that are part of this message type.
|
||||
*/
|
||||
VALUE Descriptor_oneofs(VALUE _self) {
|
||||
DEFINE_SELF(Descriptor, self, _self);
|
||||
|
||||
VALUE ret = rb_ary_new();
|
||||
upb_msg_oneof_iter it;
|
||||
for (upb_msg_oneof_begin(&it, self->msgdef);
|
||||
!upb_msg_oneof_done(&it);
|
||||
upb_msg_oneof_next(&it)) {
|
||||
const upb_oneofdef* oneof = upb_msg_iter_oneof(&it);
|
||||
VALUE obj = get_def_obj(oneof);
|
||||
rb_ary_push(ret, obj);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.lookup_oneof(name) => OneofDescriptor
|
||||
*
|
||||
* Returns the oneof descriptor for the oneof with the given name, if present,
|
||||
* or nil if none.
|
||||
*/
|
||||
VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) {
|
||||
DEFINE_SELF(Descriptor, self, _self);
|
||||
const char* s = get_str(name);
|
||||
const upb_oneofdef* oneof = upb_msgdef_ntooz(self->msgdef, s);
|
||||
if (oneof == NULL) {
|
||||
return Qnil;
|
||||
}
|
||||
return get_def_obj(oneof);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.msgclass => message_klass
|
||||
|
@ -743,6 +811,120 @@ VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
|
|||
return Qnil;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// OneofDescriptor.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
DEFINE_CLASS(OneofDescriptor, "Google::Protobuf::OneofDescriptor");
|
||||
|
||||
void OneofDescriptor_mark(void* _self) {
|
||||
}
|
||||
|
||||
void OneofDescriptor_free(void* _self) {
|
||||
OneofDescriptor* self = _self;
|
||||
upb_oneofdef_unref(self->oneofdef, &self->oneofdef);
|
||||
xfree(self);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.new => oneof_descriptor
|
||||
*
|
||||
* Creates a new, empty, oneof descriptor. The oneof may only be modified prior
|
||||
* to being added to a message descriptor which is subsequently added to a pool.
|
||||
*/
|
||||
VALUE OneofDescriptor_alloc(VALUE klass) {
|
||||
OneofDescriptor* self = ALLOC(OneofDescriptor);
|
||||
VALUE ret = TypedData_Wrap_Struct(klass, &_OneofDescriptor_type, self);
|
||||
self->oneofdef = upb_oneofdef_new(&self->oneofdef);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void OneofDescriptor_register(VALUE module) {
|
||||
VALUE klass = rb_define_class_under(
|
||||
module, "OneofDescriptor", rb_cObject);
|
||||
rb_define_alloc_func(klass, OneofDescriptor_alloc);
|
||||
rb_define_method(klass, "name", OneofDescriptor_name, 0);
|
||||
rb_define_method(klass, "name=", OneofDescriptor_name_set, 1);
|
||||
rb_define_method(klass, "add_field", OneofDescriptor_add_field, 1);
|
||||
rb_define_method(klass, "each", OneofDescriptor_each, 0);
|
||||
rb_include_module(klass, rb_mEnumerable);
|
||||
cOneofDescriptor = klass;
|
||||
rb_gc_register_address(&cOneofDescriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.name => name
|
||||
*
|
||||
* Returns the name of this oneof.
|
||||
*/
|
||||
VALUE OneofDescriptor_name(VALUE _self) {
|
||||
DEFINE_SELF(OneofDescriptor, self, _self);
|
||||
return rb_str_maybe_null(upb_oneofdef_name(self->oneofdef));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.name = name
|
||||
*
|
||||
* Sets a new name for this oneof. The oneof must not have been added to a
|
||||
* message descriptor yet.
|
||||
*/
|
||||
VALUE OneofDescriptor_name_set(VALUE _self, VALUE value) {
|
||||
DEFINE_SELF(OneofDescriptor, self, _self);
|
||||
upb_oneofdef* mut_def = check_oneof_notfrozen(self->oneofdef);
|
||||
const char* str = get_str(value);
|
||||
CHECK_UPB(upb_oneofdef_setname(mut_def, str, &status),
|
||||
"Error setting oneof name");
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.add_field(field) => nil
|
||||
*
|
||||
* Adds a field to this oneof. The field may have been added to this oneof in
|
||||
* the past, or the message to which this oneof belongs (if any), but may not
|
||||
* have already been added to any other oneof or message. Otherwise, an
|
||||
* exception is raised.
|
||||
*
|
||||
* All fields added to the oneof via this method will be automatically added to
|
||||
* the message to which this oneof belongs, if it belongs to one currently, or
|
||||
* else will be added to any message to which the oneof is later added at the
|
||||
* time that it is added.
|
||||
*/
|
||||
VALUE OneofDescriptor_add_field(VALUE _self, VALUE obj) {
|
||||
DEFINE_SELF(OneofDescriptor, self, _self);
|
||||
upb_oneofdef* mut_def = check_oneof_notfrozen(self->oneofdef);
|
||||
FieldDescriptor* def = ruby_to_FieldDescriptor(obj);
|
||||
upb_fielddef* mut_field_def = check_field_notfrozen(def->fielddef);
|
||||
CHECK_UPB(
|
||||
upb_oneofdef_addfield(mut_def, mut_field_def, NULL, &status),
|
||||
"Adding field to OneofDescriptor failed");
|
||||
add_def_obj(def->fielddef, obj);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.each(&block) => nil
|
||||
*
|
||||
* Iterates through fields in this oneof, yielding to the block on each one.
|
||||
*/
|
||||
VALUE OneofDescriptor_each(VALUE _self, VALUE field) {
|
||||
DEFINE_SELF(OneofDescriptor, self, _self);
|
||||
upb_oneof_iter it;
|
||||
for (upb_oneof_begin(&it, self->oneofdef);
|
||||
!upb_oneof_done(&it);
|
||||
upb_oneof_next(&it)) {
|
||||
const upb_fielddef* f = upb_oneof_iter_field(&it);
|
||||
VALUE obj = get_def_obj(f);
|
||||
rb_yield(obj);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// EnumDescriptor.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -952,6 +1134,7 @@ void MessageBuilderContext_register(VALUE module) {
|
|||
rb_define_method(klass, "required", MessageBuilderContext_required, -1);
|
||||
rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1);
|
||||
rb_define_method(klass, "map", MessageBuilderContext_map, -1);
|
||||
rb_define_method(klass, "oneof", MessageBuilderContext_oneof, 1);
|
||||
cMessageBuilderContext = klass;
|
||||
rb_gc_register_address(&cMessageBuilderContext);
|
||||
}
|
||||
|
@ -1165,6 +1348,110 @@ VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
|
|||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* MessageBuilderContext.oneof(name, &block) => nil
|
||||
*
|
||||
* Creates a new OneofDescriptor with the given name, creates a
|
||||
* OneofBuilderContext attached to that OneofDescriptor, evaluates the given
|
||||
* block in the context of that OneofBuilderContext with #instance_eval, and
|
||||
* then adds the oneof to the message.
|
||||
*
|
||||
* This is the recommended, idiomatic way to build oneof definitions.
|
||||
*/
|
||||
VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name) {
|
||||
DEFINE_SELF(MessageBuilderContext, self, _self);
|
||||
VALUE oneofdef = rb_class_new_instance(0, NULL, cOneofDescriptor);
|
||||
VALUE args[2] = { oneofdef, self->builder };
|
||||
VALUE ctx = rb_class_new_instance(2, args, cOneofBuilderContext);
|
||||
VALUE block = rb_block_proc();
|
||||
VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name)));
|
||||
rb_funcall(oneofdef, rb_intern("name="), 1, name_str);
|
||||
rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
|
||||
Descriptor_add_oneof(self->descriptor, oneofdef);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// OneofBuilderContext.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
DEFINE_CLASS(OneofBuilderContext,
|
||||
"Google::Protobuf::Internal::OneofBuilderContext");
|
||||
|
||||
void OneofBuilderContext_mark(void* _self) {
|
||||
OneofBuilderContext* self = _self;
|
||||
rb_gc_mark(self->descriptor);
|
||||
rb_gc_mark(self->builder);
|
||||
}
|
||||
|
||||
void OneofBuilderContext_free(void* _self) {
|
||||
OneofBuilderContext* self = _self;
|
||||
xfree(self);
|
||||
}
|
||||
|
||||
VALUE OneofBuilderContext_alloc(VALUE klass) {
|
||||
OneofBuilderContext* self = ALLOC(OneofBuilderContext);
|
||||
VALUE ret = TypedData_Wrap_Struct(
|
||||
klass, &_OneofBuilderContext_type, self);
|
||||
self->descriptor = Qnil;
|
||||
self->builder = Qnil;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void OneofBuilderContext_register(VALUE module) {
|
||||
VALUE klass = rb_define_class_under(
|
||||
module, "OneofBuilderContext", rb_cObject);
|
||||
rb_define_alloc_func(klass, OneofBuilderContext_alloc);
|
||||
rb_define_method(klass, "initialize",
|
||||
OneofBuilderContext_initialize, 2);
|
||||
rb_define_method(klass, "optional", OneofBuilderContext_optional, -1);
|
||||
cOneofBuilderContext = klass;
|
||||
rb_gc_register_address(&cOneofBuilderContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofBuilderContext.new(desc, builder) => context
|
||||
*
|
||||
* Create a new oneof builder context around the given oneof descriptor and
|
||||
* builder context. This class is intended to serve as a DSL context to be used
|
||||
* with #instance_eval.
|
||||
*/
|
||||
VALUE OneofBuilderContext_initialize(VALUE _self,
|
||||
VALUE oneofdef,
|
||||
VALUE builder) {
|
||||
DEFINE_SELF(OneofBuilderContext, self, _self);
|
||||
self->descriptor = oneofdef;
|
||||
self->builder = builder;
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofBuilderContext.optional(name, type, number, type_class = nil)
|
||||
*
|
||||
* Defines a new optional field in this oneof with the given type, tag number,
|
||||
* and type class (for message and enum fields). The type must be a Ruby symbol
|
||||
* (as accepted by FieldDescriptor#type=) and the type_class must be a string,
|
||||
* if present (as accepted by FieldDescriptor#submsg_name=).
|
||||
*/
|
||||
VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
|
||||
DEFINE_SELF(OneofBuilderContext, self, _self);
|
||||
|
||||
if (argc < 3) {
|
||||
rb_raise(rb_eArgError, "Expected at least 3 arguments.");
|
||||
}
|
||||
VALUE name = argv[0];
|
||||
VALUE type = argv[1];
|
||||
VALUE number = argv[2];
|
||||
VALUE type_class = (argc > 3) ? argv[3] : Qnil;
|
||||
|
||||
return msgdef_add_field(self->descriptor, "optional",
|
||||
name, type, number, type_class);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// EnumBuilderContext.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -1322,8 +1609,10 @@ VALUE Builder_add_enum(VALUE _self, VALUE name) {
|
|||
|
||||
static void validate_msgdef(const upb_msgdef* msgdef) {
|
||||
// Verify that no required fields exist. proto3 does not support these.
|
||||
upb_msg_iter it;
|
||||
for (upb_msg_begin(&it, msgdef); !upb_msg_done(&it); upb_msg_next(&it)) {
|
||||
upb_msg_field_iter it;
|
||||
for (upb_msg_field_begin(&it, msgdef);
|
||||
!upb_msg_field_done(&it);
|
||||
upb_msg_field_next(&it)) {
|
||||
const upb_fielddef* field = upb_msg_iter_field(&it);
|
||||
if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) {
|
||||
rb_raise(rb_eTypeError, "Required fields are unsupported in proto3.");
|
||||
|
|
|
@ -59,6 +59,30 @@ static const void *newsubmsghandlerdata(upb_handlers* h, uint32_t ofs,
|
|||
return hd;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
size_t ofs; // union data slot
|
||||
size_t case_ofs; // oneof_case field
|
||||
uint32_t tag; // tag number to place in data slot
|
||||
const upb_msgdef *md; // msgdef, for oneof submessage handler
|
||||
} oneof_handlerdata_t;
|
||||
|
||||
static const void *newoneofhandlerdata(upb_handlers *h,
|
||||
uint32_t ofs,
|
||||
uint32_t case_ofs,
|
||||
const upb_fielddef *f) {
|
||||
oneof_handlerdata_t *hd = ALLOC(oneof_handlerdata_t);
|
||||
hd->ofs = ofs;
|
||||
hd->case_ofs = case_ofs;
|
||||
hd->tag = upb_fielddef_number(f);
|
||||
if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) {
|
||||
hd->md = upb_fielddef_msgsubdef(f);
|
||||
} else {
|
||||
hd->md = NULL;
|
||||
}
|
||||
upb_handlers_addcleanup(h, hd, free);
|
||||
return hd;
|
||||
}
|
||||
|
||||
// A handler that starts a repeated field. Gets the Repeated*Field instance for
|
||||
// this field (such an instance always exists even in an empty message).
|
||||
static void *startseq_handler(void* closure, const void* hd) {
|
||||
|
@ -67,8 +91,7 @@ static void *startseq_handler(void* closure, const void* hd) {
|
|||
return (void*)DEREF(msg, *ofs, VALUE);
|
||||
}
|
||||
|
||||
// Handlers that append primitive values to a repeated field (a regular Ruby
|
||||
// array for now).
|
||||
// Handlers that append primitive values to a repeated field.
|
||||
#define DEFINE_APPEND_HANDLER(type, ctype) \
|
||||
static bool append##type##_handler(void *closure, const void *hd, \
|
||||
ctype val) { \
|
||||
|
@ -85,7 +108,7 @@ DEFINE_APPEND_HANDLER(int64, int64_t)
|
|||
DEFINE_APPEND_HANDLER(uint64, uint64_t)
|
||||
DEFINE_APPEND_HANDLER(double, double)
|
||||
|
||||
// Appends a string to a repeated field (a regular Ruby array for now).
|
||||
// Appends a string to a repeated field.
|
||||
static void* appendstr_handler(void *closure,
|
||||
const void *hd,
|
||||
size_t size_hint) {
|
||||
|
@ -96,7 +119,7 @@ static void* appendstr_handler(void *closure,
|
|||
return (void*)str;
|
||||
}
|
||||
|
||||
// Appends a 'bytes' string to a repeated field (a regular Ruby array for now).
|
||||
// Appends a 'bytes' string to a repeated field.
|
||||
static void* appendbytes_handler(void *closure,
|
||||
const void *hd,
|
||||
size_t size_hint) {
|
||||
|
@ -266,6 +289,75 @@ static map_handlerdata_t* new_map_handlerdata(
|
|||
return hd;
|
||||
}
|
||||
|
||||
// Handlers that set primitive values in oneofs.
|
||||
#define DEFINE_ONEOF_HANDLER(type, ctype) \
|
||||
static bool oneof##type##_handler(void *closure, const void *hd, \
|
||||
ctype val) { \
|
||||
const oneof_handlerdata_t *oneofdata = hd; \
|
||||
DEREF(closure, oneofdata->case_ofs, uint32_t) = oneofdata->tag; \
|
||||
DEREF(closure, oneofdata->ofs, ctype) = val; \
|
||||
return true; \
|
||||
}
|
||||
|
||||
DEFINE_ONEOF_HANDLER(bool, bool)
|
||||
DEFINE_ONEOF_HANDLER(int32, int32_t)
|
||||
DEFINE_ONEOF_HANDLER(uint32, uint32_t)
|
||||
DEFINE_ONEOF_HANDLER(float, float)
|
||||
DEFINE_ONEOF_HANDLER(int64, int64_t)
|
||||
DEFINE_ONEOF_HANDLER(uint64, uint64_t)
|
||||
DEFINE_ONEOF_HANDLER(double, double)
|
||||
|
||||
#undef DEFINE_ONEOF_HANDLER
|
||||
|
||||
// Handlers for strings in a oneof.
|
||||
static void *oneofstr_handler(void *closure,
|
||||
const void *hd,
|
||||
size_t size_hint) {
|
||||
MessageHeader* msg = closure;
|
||||
const oneof_handlerdata_t *oneofdata = hd;
|
||||
VALUE str = rb_str_new2("");
|
||||
rb_enc_associate(str, kRubyStringUtf8Encoding);
|
||||
DEREF(msg, oneofdata->case_ofs, uint32_t) = oneofdata->tag;
|
||||
DEREF(msg, oneofdata->ofs, VALUE) = str;
|
||||
return (void*)str;
|
||||
}
|
||||
|
||||
static void *oneofbytes_handler(void *closure,
|
||||
const void *hd,
|
||||
size_t size_hint) {
|
||||
MessageHeader* msg = closure;
|
||||
const oneof_handlerdata_t *oneofdata = hd;
|
||||
VALUE str = rb_str_new2("");
|
||||
rb_enc_associate(str, kRubyString8bitEncoding);
|
||||
DEREF(msg, oneofdata->case_ofs, uint32_t) = oneofdata->tag;
|
||||
DEREF(msg, oneofdata->ofs, VALUE) = str;
|
||||
return (void*)str;
|
||||
}
|
||||
|
||||
// Handler for a submessage field in a oneof.
|
||||
static void *oneofsubmsg_handler(void *closure,
|
||||
const void *hd) {
|
||||
MessageHeader* msg = closure;
|
||||
const oneof_handlerdata_t *oneofdata = hd;
|
||||
uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t);
|
||||
DEREF(msg, oneofdata->case_ofs, uint32_t) = oneofdata->tag;
|
||||
|
||||
VALUE subdesc =
|
||||
get_def_obj((void*)oneofdata->md);
|
||||
VALUE subklass = Descriptor_msgclass(subdesc);
|
||||
|
||||
if (oldcase != oneofdata->tag ||
|
||||
DEREF(msg, oneofdata->ofs, VALUE) == Qnil) {
|
||||
DEREF(msg, oneofdata->ofs, VALUE) =
|
||||
rb_class_new_instance(0, NULL, subklass);
|
||||
}
|
||||
|
||||
VALUE submsg_rb = DEREF(msg, oneofdata->ofs, VALUE);
|
||||
MessageHeader* submsg;
|
||||
TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
|
||||
return submsg;
|
||||
}
|
||||
|
||||
// Set up handlers for a repeated field.
|
||||
static void add_handlers_for_repeated_field(upb_handlers *h,
|
||||
const upb_fielddef *f,
|
||||
|
@ -383,6 +475,53 @@ static void add_handlers_for_mapentry(const upb_msgdef* msgdef,
|
|||
offsetof(map_parse_frame_t, value_storage));
|
||||
}
|
||||
|
||||
// Set up handlers for a oneof field.
|
||||
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));
|
||||
|
||||
switch (upb_fielddef_type(f)) {
|
||||
|
||||
#define SET_HANDLER(utype, ltype) \
|
||||
case utype: \
|
||||
upb_handlers_set##ltype(h, f, oneof##ltype##_handler, &attr); \
|
||||
break;
|
||||
|
||||
SET_HANDLER(UPB_TYPE_BOOL, bool);
|
||||
SET_HANDLER(UPB_TYPE_INT32, int32);
|
||||
SET_HANDLER(UPB_TYPE_UINT32, uint32);
|
||||
SET_HANDLER(UPB_TYPE_ENUM, int32);
|
||||
SET_HANDLER(UPB_TYPE_FLOAT, float);
|
||||
SET_HANDLER(UPB_TYPE_INT64, int64);
|
||||
SET_HANDLER(UPB_TYPE_UINT64, uint64);
|
||||
SET_HANDLER(UPB_TYPE_DOUBLE, double);
|
||||
|
||||
#undef SET_HANDLER
|
||||
|
||||
case UPB_TYPE_STRING:
|
||||
case UPB_TYPE_BYTES: {
|
||||
bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
|
||||
upb_handlers_setstartstr(h, f, is_bytes ?
|
||||
oneofbytes_handler : oneofstr_handler,
|
||||
&attr);
|
||||
upb_handlers_setstring(h, f, stringdata_handler, NULL);
|
||||
break;
|
||||
}
|
||||
case UPB_TYPE_MESSAGE: {
|
||||
upb_handlers_setstartsubmsg(h, f, oneofsubmsg_handler, &attr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
upb_handlerattr_uninit(&attr);
|
||||
}
|
||||
|
||||
|
||||
static void add_handlers_for_message(const void *closure, upb_handlers *h) {
|
||||
const upb_msgdef* msgdef = upb_handlers_msgdef(h);
|
||||
Descriptor* desc = ruby_to_Descriptor(get_def_obj((void*)msgdef));
|
||||
|
@ -402,16 +541,20 @@ static void add_handlers_for_message(const void *closure, upb_handlers *h) {
|
|||
desc->layout = create_layout(desc->msgdef);
|
||||
}
|
||||
|
||||
upb_msg_iter i;
|
||||
|
||||
for (upb_msg_begin(&i, desc->msgdef);
|
||||
!upb_msg_done(&i);
|
||||
upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
for (upb_msg_field_begin(&i, desc->msgdef);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
const upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
size_t offset = desc->layout->offsets[upb_fielddef_index(f)] +
|
||||
size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset +
|
||||
sizeof(MessageHeader);
|
||||
size_t oneof_case_offset =
|
||||
desc->layout->fields[upb_fielddef_index(f)].case_offset +
|
||||
sizeof(MessageHeader);
|
||||
|
||||
if (is_map_field(f)) {
|
||||
if (upb_fielddef_containingoneof(f)) {
|
||||
add_handlers_for_oneof_field(h, f, offset, oneof_case_offset);
|
||||
} 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);
|
||||
|
@ -804,13 +947,28 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
|
|||
MessageHeader* msg;
|
||||
TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
|
||||
|
||||
upb_msg_iter i;
|
||||
for (upb_msg_begin(&i, desc->msgdef);
|
||||
!upb_msg_done(&i);
|
||||
upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
for (upb_msg_field_begin(&i, desc->msgdef);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
uint32_t offset =
|
||||
desc->layout->offsets[upb_fielddef_index(f)] + sizeof(MessageHeader);
|
||||
desc->layout->fields[upb_fielddef_index(f)].offset +
|
||||
sizeof(MessageHeader);
|
||||
uint32_t oneof_case_offset =
|
||||
desc->layout->fields[upb_fielddef_index(f)].case_offset +
|
||||
sizeof(MessageHeader);
|
||||
|
||||
if (upb_fielddef_containingoneof(f)) {
|
||||
// For a oneof, check that this field is actually present -- skip all the
|
||||
// below if not.
|
||||
if (DEREF(msg, oneof_case_offset, uint32_t) !=
|
||||
upb_fielddef_number(f)) {
|
||||
continue;
|
||||
}
|
||||
// Otherwise, fall through to the appropriate singular-field handler
|
||||
// below.
|
||||
}
|
||||
|
||||
if (is_map_field(f)) {
|
||||
VALUE map = DEREF(msg, offset, VALUE);
|
||||
|
|
|
@ -77,8 +77,10 @@ void Init_protobuf_c() {
|
|||
DescriptorPool_register(protobuf);
|
||||
Descriptor_register(protobuf);
|
||||
FieldDescriptor_register(protobuf);
|
||||
OneofDescriptor_register(protobuf);
|
||||
EnumDescriptor_register(protobuf);
|
||||
MessageBuilderContext_register(internal);
|
||||
OneofBuilderContext_register(internal);
|
||||
EnumBuilderContext_register(internal);
|
||||
Builder_register(internal);
|
||||
RepeatedField_register(protobuf);
|
||||
|
|
|
@ -43,6 +43,7 @@ struct Descriptor;
|
|||
struct FieldDescriptor;
|
||||
struct EnumDescriptor;
|
||||
struct MessageLayout;
|
||||
struct MessageField;
|
||||
struct MessageHeader;
|
||||
struct MessageBuilderContext;
|
||||
struct EnumBuilderContext;
|
||||
|
@ -51,10 +52,13 @@ struct Builder;
|
|||
typedef struct DescriptorPool DescriptorPool;
|
||||
typedef struct Descriptor Descriptor;
|
||||
typedef struct FieldDescriptor FieldDescriptor;
|
||||
typedef struct OneofDescriptor OneofDescriptor;
|
||||
typedef struct EnumDescriptor EnumDescriptor;
|
||||
typedef struct MessageLayout MessageLayout;
|
||||
typedef struct MessageField MessageField;
|
||||
typedef struct MessageHeader MessageHeader;
|
||||
typedef struct MessageBuilderContext MessageBuilderContext;
|
||||
typedef struct OneofBuilderContext OneofBuilderContext;
|
||||
typedef struct EnumBuilderContext EnumBuilderContext;
|
||||
typedef struct Builder Builder;
|
||||
|
||||
|
@ -120,6 +124,10 @@ struct FieldDescriptor {
|
|||
const upb_fielddef* fielddef;
|
||||
};
|
||||
|
||||
struct OneofDescriptor {
|
||||
const upb_oneofdef* oneofdef;
|
||||
};
|
||||
|
||||
struct EnumDescriptor {
|
||||
const upb_enumdef* enumdef;
|
||||
VALUE module; // begins as nil
|
||||
|
@ -130,6 +138,11 @@ struct MessageBuilderContext {
|
|||
VALUE builder;
|
||||
};
|
||||
|
||||
struct OneofBuilderContext {
|
||||
VALUE descriptor;
|
||||
VALUE builder;
|
||||
};
|
||||
|
||||
struct EnumBuilderContext {
|
||||
VALUE enumdesc;
|
||||
};
|
||||
|
@ -144,6 +157,7 @@ extern VALUE cDescriptor;
|
|||
extern VALUE cFieldDescriptor;
|
||||
extern VALUE cEnumDescriptor;
|
||||
extern VALUE cMessageBuilderContext;
|
||||
extern VALUE cOneofBuilderContext;
|
||||
extern VALUE cEnumBuilderContext;
|
||||
extern VALUE cBuilder;
|
||||
|
||||
|
@ -175,6 +189,9 @@ 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_oneofs(VALUE _self);
|
||||
VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name);
|
||||
VALUE Descriptor_msgclass(VALUE _self);
|
||||
extern const rb_data_type_t _Descriptor_type;
|
||||
|
||||
|
@ -199,6 +216,16 @@ VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value);
|
|||
upb_fieldtype_t ruby_to_fieldtype(VALUE type);
|
||||
VALUE fieldtype_to_ruby(upb_fieldtype_t type);
|
||||
|
||||
void OneofDescriptor_mark(void* _self);
|
||||
void OneofDescriptor_free(void* _self);
|
||||
VALUE OneofDescriptor_alloc(VALUE klass);
|
||||
void OneofDescriptor_register(VALUE module);
|
||||
OneofDescriptor* ruby_to_OneofDescriptor(VALUE value);
|
||||
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);
|
||||
|
@ -225,6 +252,17 @@ 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);
|
||||
VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self);
|
||||
VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name);
|
||||
|
||||
void OneofBuilderContext_mark(void* _self);
|
||||
void OneofBuilderContext_free(void* _self);
|
||||
VALUE OneofBuilderContext_alloc(VALUE klass);
|
||||
void OneofBuilderContext_register(VALUE module);
|
||||
OneofBuilderContext* ruby_to_OneofBuilderContext(VALUE value);
|
||||
VALUE OneofBuilderContext_initialize(VALUE _self,
|
||||
VALUE descriptor,
|
||||
VALUE builder);
|
||||
VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self);
|
||||
|
||||
void EnumBuilderContext_mark(void* _self);
|
||||
void EnumBuilderContext_free(void* _self);
|
||||
|
@ -247,7 +285,7 @@ VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb);
|
|||
// Native slot storage abstraction.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define NATIVE_SLOT_MAX_SIZE sizeof(void*)
|
||||
#define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t)
|
||||
|
||||
size_t native_slot_size(upb_fieldtype_t type);
|
||||
void native_slot_set(upb_fieldtype_t type,
|
||||
|
@ -384,9 +422,16 @@ VALUE Map_iter_value(Map_iter* iter);
|
|||
// Message layout / storage.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define MESSAGE_FIELD_NO_CASE ((size_t)-1)
|
||||
|
||||
struct MessageField {
|
||||
size_t offset;
|
||||
size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE.
|
||||
};
|
||||
|
||||
struct MessageLayout {
|
||||
const upb_msgdef* msgdef;
|
||||
size_t* offsets;
|
||||
MessageField* fields;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
|
|
|
@ -369,21 +369,79 @@ const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) {
|
|||
MessageLayout* create_layout(const upb_msgdef* msgdef) {
|
||||
MessageLayout* layout = ALLOC(MessageLayout);
|
||||
int nfields = upb_msgdef_numfields(msgdef);
|
||||
layout->offsets = ALLOC_N(size_t, nfields);
|
||||
layout->fields = ALLOC_N(MessageField, nfields);
|
||||
|
||||
upb_msg_iter it;
|
||||
upb_msg_field_iter it;
|
||||
size_t off = 0;
|
||||
for (upb_msg_begin(&it, msgdef); !upb_msg_done(&it); upb_msg_next(&it)) {
|
||||
for (upb_msg_field_begin(&it, msgdef);
|
||||
!upb_msg_field_done(&it);
|
||||
upb_msg_field_next(&it)) {
|
||||
const upb_fielddef* field = upb_msg_iter_field(&it);
|
||||
|
||||
if (upb_fielddef_containingoneof(field)) {
|
||||
// Oneofs are handled separately below.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allocate |field_size| bytes for this field in the layout.
|
||||
size_t field_size = 0;
|
||||
if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
field_size = sizeof(VALUE);
|
||||
} else {
|
||||
field_size = native_slot_size(upb_fielddef_type(field));
|
||||
}
|
||||
// align current offset
|
||||
// Align current offset up to |size| granularity.
|
||||
off = (off + field_size - 1) & ~(field_size - 1);
|
||||
layout->offsets[upb_fielddef_index(field)] = off;
|
||||
layout->fields[upb_fielddef_index(field)].offset = off;
|
||||
layout->fields[upb_fielddef_index(field)].case_offset = MESSAGE_FIELD_NO_CASE;
|
||||
off += field_size;
|
||||
}
|
||||
|
||||
// Handle oneofs now -- we iterate over oneofs specifically and allocate only
|
||||
// one slot per oneof.
|
||||
//
|
||||
// We assign all value slots first, then pack the 'case' fields at the end,
|
||||
// since in the common case (modern 64-bit platform) these are 8 bytes and 4
|
||||
// bytes respectively and we want to avoid alignment overhead.
|
||||
upb_msg_oneof_iter oit;
|
||||
for (upb_msg_oneof_begin(&oit, msgdef);
|
||||
!upb_msg_oneof_done(&oit);
|
||||
upb_msg_oneof_next(&oit)) {
|
||||
const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
|
||||
|
||||
// Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between
|
||||
// all fields.
|
||||
size_t field_size = NATIVE_SLOT_MAX_SIZE;
|
||||
// Align the offset.
|
||||
off = (off + field_size - 1) & ~(field_size - 1);
|
||||
// Assign all fields in the oneof this same offset.
|
||||
upb_oneof_iter fit;
|
||||
for (upb_oneof_begin(&fit, oneof);
|
||||
!upb_oneof_done(&fit);
|
||||
upb_oneof_next(&fit)) {
|
||||
const upb_fielddef* field = upb_oneof_iter_field(&fit);
|
||||
layout->fields[upb_fielddef_index(field)].offset = off;
|
||||
}
|
||||
off += field_size;
|
||||
}
|
||||
|
||||
// Now the case fields.
|
||||
for (upb_msg_oneof_begin(&oit, msgdef);
|
||||
!upb_msg_oneof_done(&oit);
|
||||
upb_msg_oneof_next(&oit)) {
|
||||
const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
|
||||
|
||||
size_t field_size = sizeof(uint32_t);
|
||||
// Align the offset.
|
||||
off = (off + field_size - 1) & ~(field_size - 1);
|
||||
// Assign all fields in the oneof this same offset.
|
||||
upb_oneof_iter fit;
|
||||
for (upb_oneof_begin(&fit, oneof);
|
||||
!upb_oneof_done(&fit);
|
||||
upb_oneof_next(&fit)) {
|
||||
const upb_fielddef* field = upb_oneof_iter_field(&fit);
|
||||
layout->fields[upb_fielddef_index(field)].case_offset = off;
|
||||
}
|
||||
off += field_size;
|
||||
}
|
||||
|
||||
|
@ -396,7 +454,7 @@ MessageLayout* create_layout(const upb_msgdef* msgdef) {
|
|||
}
|
||||
|
||||
void free_layout(MessageLayout* layout) {
|
||||
xfree(layout->offsets);
|
||||
xfree(layout->fields);
|
||||
upb_msgdef_unref(layout->msgdef, &layout->msgdef);
|
||||
xfree(layout);
|
||||
}
|
||||
|
@ -419,8 +477,18 @@ VALUE layout_get(MessageLayout* layout,
|
|||
const void* storage,
|
||||
const upb_fielddef* field) {
|
||||
void* memory = ((uint8_t *)storage) +
|
||||
layout->offsets[upb_fielddef_index(field)];
|
||||
if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
layout->fields[upb_fielddef_index(field)].offset;
|
||||
uint32_t* oneof_case = (uint32_t *)(((uint8_t *)storage) +
|
||||
layout->fields[upb_fielddef_index(field)].case_offset);
|
||||
|
||||
if (upb_fielddef_containingoneof(field)) {
|
||||
if (*oneof_case != upb_fielddef_number(field)) {
|
||||
return Qnil;
|
||||
}
|
||||
return native_slot_get(upb_fielddef_type(field),
|
||||
field_type_class(field),
|
||||
memory);
|
||||
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
return *((VALUE *)memory);
|
||||
} else {
|
||||
return native_slot_get(upb_fielddef_type(field),
|
||||
|
@ -485,8 +553,27 @@ void layout_set(MessageLayout* layout,
|
|||
const upb_fielddef* field,
|
||||
VALUE val) {
|
||||
void* memory = ((uint8_t *)storage) +
|
||||
layout->offsets[upb_fielddef_index(field)];
|
||||
if (is_map_field(field)) {
|
||||
layout->fields[upb_fielddef_index(field)].offset;
|
||||
uint32_t* oneof_case = (uint32_t *)(((uint8_t *)storage) +
|
||||
layout->fields[upb_fielddef_index(field)].case_offset);
|
||||
|
||||
if (upb_fielddef_containingoneof(field)) {
|
||||
if (val == Qnil) {
|
||||
// Assigning nil to a oneof field clears the oneof completely.
|
||||
*oneof_case = 0;
|
||||
memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
|
||||
} else {
|
||||
// Set the oneof case *first* in case a GC is triggered during
|
||||
// native_slot_set(): layout_mark() depends on oneof_case to know whether
|
||||
// the slot may be a Ruby VALUE and so we need that lifetime to start
|
||||
// before we could possibly stick a VALUE in it.
|
||||
*oneof_case = upb_fielddef_number(field);
|
||||
// We just overwrite the value directly if we changed oneof cases:
|
||||
// native_slot_set() does not depend on the old value in memory.
|
||||
native_slot_set(upb_fielddef_type(field), field_type_class(field),
|
||||
memory, val);
|
||||
}
|
||||
} else if (is_map_field(field)) {
|
||||
check_map_field_type(val, field);
|
||||
DEREF(memory, VALUE) = val;
|
||||
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
|
@ -500,15 +587,20 @@ void layout_set(MessageLayout* layout,
|
|||
|
||||
void layout_init(MessageLayout* layout,
|
||||
void* storage) {
|
||||
upb_msg_iter it;
|
||||
for (upb_msg_begin(&it, layout->msgdef);
|
||||
!upb_msg_done(&it);
|
||||
upb_msg_next(&it)) {
|
||||
upb_msg_field_iter it;
|
||||
for (upb_msg_field_begin(&it, layout->msgdef);
|
||||
!upb_msg_field_done(&it);
|
||||
upb_msg_field_next(&it)) {
|
||||
const upb_fielddef* field = upb_msg_iter_field(&it);
|
||||
void* memory = ((uint8_t *)storage) +
|
||||
layout->offsets[upb_fielddef_index(field)];
|
||||
layout->fields[upb_fielddef_index(field)].offset;
|
||||
uint32_t* oneof_case = (uint32_t *)(((uint8_t *)storage) +
|
||||
layout->fields[upb_fielddef_index(field)].case_offset);
|
||||
|
||||
if (is_map_field(field)) {
|
||||
if (upb_fielddef_containingoneof(field)) {
|
||||
memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
|
||||
*oneof_case = 0;
|
||||
} else if (is_map_field(field)) {
|
||||
VALUE map = Qnil;
|
||||
|
||||
const upb_fielddef* key_field = map_field_key(field);
|
||||
|
@ -555,15 +647,21 @@ void layout_init(MessageLayout* layout,
|
|||
}
|
||||
|
||||
void layout_mark(MessageLayout* layout, void* storage) {
|
||||
upb_msg_iter it;
|
||||
for (upb_msg_begin(&it, layout->msgdef);
|
||||
!upb_msg_done(&it);
|
||||
upb_msg_next(&it)) {
|
||||
upb_msg_field_iter it;
|
||||
for (upb_msg_field_begin(&it, layout->msgdef);
|
||||
!upb_msg_field_done(&it);
|
||||
upb_msg_field_next(&it)) {
|
||||
const upb_fielddef* field = upb_msg_iter_field(&it);
|
||||
void* memory = ((uint8_t *)storage) +
|
||||
layout->offsets[upb_fielddef_index(field)];
|
||||
layout->fields[upb_fielddef_index(field)].offset;
|
||||
uint32_t* oneof_case = (uint32_t *)(((uint8_t *)storage) +
|
||||
layout->fields[upb_fielddef_index(field)].case_offset);
|
||||
|
||||
if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
if (upb_fielddef_containingoneof(field)) {
|
||||
if (*oneof_case == upb_fielddef_number(field)) {
|
||||
native_slot_mark(upb_fielddef_type(field), memory);
|
||||
}
|
||||
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
rb_gc_mark(DEREF(memory, VALUE));
|
||||
} else {
|
||||
native_slot_mark(upb_fielddef_type(field), memory);
|
||||
|
@ -572,17 +670,26 @@ void layout_mark(MessageLayout* layout, void* storage) {
|
|||
}
|
||||
|
||||
void layout_dup(MessageLayout* layout, void* to, void* from) {
|
||||
upb_msg_iter it;
|
||||
for (upb_msg_begin(&it, layout->msgdef);
|
||||
!upb_msg_done(&it);
|
||||
upb_msg_next(&it)) {
|
||||
upb_msg_field_iter it;
|
||||
for (upb_msg_field_begin(&it, layout->msgdef);
|
||||
!upb_msg_field_done(&it);
|
||||
upb_msg_field_next(&it)) {
|
||||
const upb_fielddef* field = upb_msg_iter_field(&it);
|
||||
void* to_memory = ((uint8_t *)to) +
|
||||
layout->offsets[upb_fielddef_index(field)];
|
||||
layout->fields[upb_fielddef_index(field)].offset;
|
||||
uint32_t* to_oneof_case = (uint32_t *)(((uint8_t *)to) +
|
||||
layout->fields[upb_fielddef_index(field)].case_offset);
|
||||
void* from_memory = ((uint8_t *)from) +
|
||||
layout->offsets[upb_fielddef_index(field)];
|
||||
layout->fields[upb_fielddef_index(field)].offset;
|
||||
uint32_t* from_oneof_case = (uint32_t *)(((uint8_t *)from) +
|
||||
layout->fields[upb_fielddef_index(field)].case_offset);
|
||||
|
||||
if (is_map_field(field)) {
|
||||
if (upb_fielddef_containingoneof(field)) {
|
||||
if (*from_oneof_case == upb_fielddef_number(field)) {
|
||||
*to_oneof_case = *from_oneof_case;
|
||||
native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
|
||||
}
|
||||
} else if (is_map_field(field)) {
|
||||
DEREF(to_memory, VALUE) = Map_dup(DEREF(from_memory, VALUE));
|
||||
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
DEREF(to_memory, VALUE) = RepeatedField_dup(DEREF(from_memory, VALUE));
|
||||
|
@ -593,17 +700,26 @@ void layout_dup(MessageLayout* layout, void* to, void* from) {
|
|||
}
|
||||
|
||||
void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
|
||||
upb_msg_iter it;
|
||||
for (upb_msg_begin(&it, layout->msgdef);
|
||||
!upb_msg_done(&it);
|
||||
upb_msg_next(&it)) {
|
||||
upb_msg_field_iter it;
|
||||
for (upb_msg_field_begin(&it, layout->msgdef);
|
||||
!upb_msg_field_done(&it);
|
||||
upb_msg_field_next(&it)) {
|
||||
const upb_fielddef* field = upb_msg_iter_field(&it);
|
||||
void* to_memory = ((uint8_t *)to) +
|
||||
layout->offsets[upb_fielddef_index(field)];
|
||||
layout->fields[upb_fielddef_index(field)].offset;
|
||||
uint32_t* to_oneof_case = (uint32_t *)(((uint8_t *)to) +
|
||||
layout->fields[upb_fielddef_index(field)].case_offset);
|
||||
void* from_memory = ((uint8_t *)from) +
|
||||
layout->offsets[upb_fielddef_index(field)];
|
||||
layout->fields[upb_fielddef_index(field)].offset;
|
||||
uint32_t* from_oneof_case = (uint32_t *)(((uint8_t *)from) +
|
||||
layout->fields[upb_fielddef_index(field)].case_offset);
|
||||
|
||||
if (is_map_field(field)) {
|
||||
if (upb_fielddef_containingoneof(field)) {
|
||||
if (*from_oneof_case == upb_fielddef_number(field)) {
|
||||
*to_oneof_case = *from_oneof_case;
|
||||
native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
|
||||
}
|
||||
} else if (is_map_field(field)) {
|
||||
DEREF(to_memory, VALUE) =
|
||||
Map_deep_copy(DEREF(from_memory, VALUE));
|
||||
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
|
@ -616,22 +732,38 @@ void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
|
|||
}
|
||||
|
||||
VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
|
||||
upb_msg_iter it;
|
||||
for (upb_msg_begin(&it, layout->msgdef);
|
||||
!upb_msg_done(&it);
|
||||
upb_msg_next(&it)) {
|
||||
upb_msg_field_iter it;
|
||||
for (upb_msg_field_begin(&it, layout->msgdef);
|
||||
!upb_msg_field_done(&it);
|
||||
upb_msg_field_next(&it)) {
|
||||
const upb_fielddef* field = upb_msg_iter_field(&it);
|
||||
void* msg1_memory = ((uint8_t *)msg1) +
|
||||
layout->offsets[upb_fielddef_index(field)];
|
||||
layout->fields[upb_fielddef_index(field)].offset;
|
||||
uint32_t* msg1_oneof_case = (uint32_t *)(((uint8_t *)msg1) +
|
||||
layout->fields[upb_fielddef_index(field)].case_offset);
|
||||
void* msg2_memory = ((uint8_t *)msg2) +
|
||||
layout->offsets[upb_fielddef_index(field)];
|
||||
layout->fields[upb_fielddef_index(field)].offset;
|
||||
uint32_t* msg2_oneof_case = (uint32_t *)(((uint8_t *)msg2) +
|
||||
layout->fields[upb_fielddef_index(field)].case_offset);
|
||||
|
||||
if (is_map_field(field)) {
|
||||
return Map_eq(DEREF(msg1_memory, VALUE),
|
||||
DEREF(msg2_memory, VALUE));
|
||||
if (upb_fielddef_containingoneof(field)) {
|
||||
if (*msg1_oneof_case != *msg2_oneof_case ||
|
||||
(*msg1_oneof_case == upb_fielddef_number(field) &&
|
||||
!native_slot_eq(upb_fielddef_type(field),
|
||||
msg1_memory,
|
||||
msg2_memory))) {
|
||||
return Qfalse;
|
||||
}
|
||||
} else if (is_map_field(field)) {
|
||||
if (!Map_eq(DEREF(msg1_memory, VALUE),
|
||||
DEREF(msg2_memory, VALUE))) {
|
||||
return Qfalse;
|
||||
}
|
||||
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
return RepeatedField_eq(DEREF(msg1_memory, VALUE),
|
||||
DEREF(msg2_memory, VALUE));
|
||||
if (!RepeatedField_eq(DEREF(msg1_memory, VALUE),
|
||||
DEREF(msg2_memory, VALUE))) {
|
||||
return Qfalse;
|
||||
}
|
||||
} else {
|
||||
if (!native_slot_eq(upb_fielddef_type(field),
|
||||
msg1_memory, msg2_memory)) {
|
||||
|
@ -643,12 +775,12 @@ VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
|
|||
}
|
||||
|
||||
VALUE layout_hash(MessageLayout* layout, void* storage) {
|
||||
upb_msg_iter it;
|
||||
upb_msg_field_iter it;
|
||||
st_index_t h = rb_hash_start(0);
|
||||
VALUE hash_sym = rb_intern("hash");
|
||||
for (upb_msg_begin(&it, layout->msgdef);
|
||||
!upb_msg_done(&it);
|
||||
upb_msg_next(&it)) {
|
||||
for (upb_msg_field_begin(&it, layout->msgdef);
|
||||
!upb_msg_field_done(&it);
|
||||
upb_msg_field_next(&it)) {
|
||||
const upb_fielddef* field = upb_msg_iter_field(&it);
|
||||
VALUE field_val = layout_get(layout, storage, field);
|
||||
h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0)));
|
||||
|
@ -661,11 +793,11 @@ VALUE layout_hash(MessageLayout* layout, void* storage) {
|
|||
VALUE layout_inspect(MessageLayout* layout, void* storage) {
|
||||
VALUE str = rb_str_new2("");
|
||||
|
||||
upb_msg_iter it;
|
||||
upb_msg_field_iter it;
|
||||
bool first = true;
|
||||
for (upb_msg_begin(&it, layout->msgdef);
|
||||
!upb_msg_done(&it);
|
||||
upb_msg_next(&it)) {
|
||||
for (upb_msg_field_begin(&it, layout->msgdef);
|
||||
!upb_msg_field_done(&it);
|
||||
upb_msg_field_next(&it)) {
|
||||
const upb_fielddef* field = upb_msg_iter_field(&it);
|
||||
VALUE field_val = layout_get(layout, storage, field);
|
||||
|
||||
|
|
|
@ -247,10 +247,12 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) {
|
|||
upb_fielddef **fields = malloc(n * sizeof(*fields));
|
||||
if (!fields) return false;
|
||||
|
||||
upb_msg_iter j;
|
||||
upb_msg_field_iter j;
|
||||
int i;
|
||||
m->submsg_field_count = 0;
|
||||
for(i = 0, upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j), i++) {
|
||||
for(i = 0, upb_msg_field_begin(&j, m);
|
||||
!upb_msg_field_done(&j);
|
||||
upb_msg_field_next(&j), i++) {
|
||||
upb_fielddef *f = upb_msg_iter_field(&j);
|
||||
assert(f->msg.def == m);
|
||||
if (!upb_validate_field(f, s)) {
|
||||
|
@ -286,7 +288,9 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) {
|
|||
upb_selector_t sel;
|
||||
upb_inttable_insert(&t, UPB_STARTMSG_SELECTOR, v);
|
||||
upb_inttable_insert(&t, UPB_ENDMSG_SELECTOR, v);
|
||||
for(upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j)) {
|
||||
for(upb_msg_field_begin(&j, m);
|
||||
!upb_msg_field_done(&j);
|
||||
upb_msg_field_next(&j)) {
|
||||
upb_fielddef *f = upb_msg_iter_field(&j);
|
||||
// These calls will assert-fail in upb_table if the value already exists.
|
||||
TRY(UPB_HANDLER_INT32);
|
||||
|
@ -544,6 +548,9 @@ static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit,
|
|||
if (upb_fielddef_containingtype(f)) {
|
||||
visit(r, UPB_UPCAST2(upb_fielddef_containingtype(f)), closure);
|
||||
}
|
||||
if (upb_fielddef_containingoneof(f)) {
|
||||
visit(r, UPB_UPCAST2(upb_fielddef_containingoneof(f)), closure);
|
||||
}
|
||||
if (upb_fielddef_subdef(f)) {
|
||||
visit(r, UPB_UPCAST(upb_fielddef_subdef(f)), closure);
|
||||
}
|
||||
|
@ -619,6 +626,7 @@ upb_fielddef *upb_fielddef_new(const void *owner) {
|
|||
}
|
||||
f->msg.def = NULL;
|
||||
f->sub.def = NULL;
|
||||
f->oneof = NULL;
|
||||
f->subdef_is_symbolic = false;
|
||||
f->msg_is_symbolic = false;
|
||||
f->label_ = UPB_LABEL_OPTIONAL;
|
||||
|
@ -748,6 +756,10 @@ const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) {
|
|||
return f->msg_is_symbolic ? NULL : f->msg.def;
|
||||
}
|
||||
|
||||
const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) {
|
||||
return f->oneof;
|
||||
}
|
||||
|
||||
upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f) {
|
||||
return (upb_msgdef*)upb_fielddef_containingtype(f);
|
||||
}
|
||||
|
@ -776,6 +788,10 @@ bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name,
|
|||
}
|
||||
|
||||
bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s) {
|
||||
if (upb_fielddef_containingtype(f) || upb_fielddef_containingoneof(f)) {
|
||||
upb_status_seterrmsg(s, "Already added to message or oneof");
|
||||
return false;
|
||||
}
|
||||
return upb_def_setfullname(UPB_UPCAST(f), name, s);
|
||||
}
|
||||
|
||||
|
@ -1247,15 +1263,25 @@ bool upb_fielddef_checkdescriptortype(int32_t type) {
|
|||
static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit,
|
||||
void *closure) {
|
||||
const upb_msgdef *m = (const upb_msgdef*)r;
|
||||
upb_msg_iter i;
|
||||
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
for(upb_msg_field_begin(&i, m);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
visit(r, UPB_UPCAST2(f), closure);
|
||||
}
|
||||
upb_msg_oneof_iter o;
|
||||
for(upb_msg_oneof_begin(&o, m);
|
||||
!upb_msg_oneof_done(&o);
|
||||
upb_msg_oneof_next(&o)) {
|
||||
upb_oneofdef *f = upb_msg_iter_oneof(&o);
|
||||
visit(r, UPB_UPCAST2(f), closure);
|
||||
}
|
||||
}
|
||||
|
||||
static void freemsg(upb_refcounted *r) {
|
||||
upb_msgdef *m = (upb_msgdef*)r;
|
||||
upb_strtable_uninit(&m->ntoo);
|
||||
upb_strtable_uninit(&m->ntof);
|
||||
upb_inttable_uninit(&m->itof);
|
||||
upb_def_uninit(UPB_UPCAST(m));
|
||||
|
@ -1267,14 +1293,17 @@ upb_msgdef *upb_msgdef_new(const void *owner) {
|
|||
upb_msgdef *m = malloc(sizeof(*m));
|
||||
if (!m) return NULL;
|
||||
if (!upb_def_init(UPB_UPCAST(m), UPB_DEF_MSG, &vtbl, owner)) goto err2;
|
||||
if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err2;
|
||||
if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err1;
|
||||
if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err3;
|
||||
if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err2;
|
||||
if (!upb_strtable_init(&m->ntoo, UPB_CTYPE_PTR)) goto err1;
|
||||
m->map_entry = false;
|
||||
return m;
|
||||
|
||||
err1:
|
||||
upb_inttable_uninit(&m->itof);
|
||||
upb_strtable_uninit(&m->ntof);
|
||||
err2:
|
||||
upb_inttable_uninit(&m->itof);
|
||||
err3:
|
||||
free(m);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1286,14 +1315,28 @@ upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) {
|
|||
upb_def_fullname(UPB_UPCAST(m)), NULL);
|
||||
newm->map_entry = m->map_entry;
|
||||
UPB_ASSERT_VAR(ok, ok);
|
||||
upb_msg_iter i;
|
||||
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
for(upb_msg_field_begin(&i, m);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f);
|
||||
// Fields in oneofs are dup'd below.
|
||||
if (upb_fielddef_containingoneof(f)) continue;
|
||||
if (!f || !upb_msgdef_addfield(newm, f, &f, NULL)) {
|
||||
upb_msgdef_unref(newm, owner);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
upb_msg_oneof_iter o;
|
||||
for(upb_msg_oneof_begin(&o, m);
|
||||
!upb_msg_oneof_done(&o);
|
||||
upb_msg_oneof_next(&o)) {
|
||||
upb_oneofdef *f = upb_oneofdef_dup(upb_msg_iter_oneof(&o), &f);
|
||||
if (!f || !upb_msgdef_addoneof(newm, f, &f, NULL)) {
|
||||
upb_msgdef_unref(newm, owner);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return newm;
|
||||
}
|
||||
|
||||
|
@ -1332,6 +1375,35 @@ bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname,
|
|||
return upb_def_setfullname(UPB_UPCAST(m), fullname, s);
|
||||
}
|
||||
|
||||
// Helper: check that the field |f| is safe to add to msgdef |m|. Set an error
|
||||
// on status |s| and return false if not.
|
||||
static bool check_field_add(const upb_msgdef *m, const upb_fielddef *f,
|
||||
upb_status *s) {
|
||||
if (upb_fielddef_containingtype(f) != NULL) {
|
||||
upb_status_seterrmsg(s, "fielddef already belongs to a message");
|
||||
return false;
|
||||
} else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
|
||||
upb_status_seterrmsg(s, "field name or number were not set");
|
||||
return false;
|
||||
} else if (upb_msgdef_ntofz(m, upb_fielddef_name(f)) ||
|
||||
upb_msgdef_itof(m, upb_fielddef_number(f))) {
|
||||
upb_status_seterrmsg(s, "duplicate field name or number for field");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void add_field(upb_msgdef *m, upb_fielddef *f, const void *ref_donor) {
|
||||
release_containingtype(f);
|
||||
f->msg.def = m;
|
||||
f->msg_is_symbolic = false;
|
||||
upb_inttable_insert(&m->itof, upb_fielddef_number(f), upb_value_ptr(f));
|
||||
upb_strtable_insert(&m->ntof, upb_fielddef_name(f), upb_value_ptr(f));
|
||||
upb_ref2(f, m);
|
||||
upb_ref2(m, f);
|
||||
if (ref_donor) upb_fielddef_unref(f, ref_donor);
|
||||
}
|
||||
|
||||
bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
|
||||
upb_status *s) {
|
||||
// TODO: extensions need to have a separate namespace, because proto2 allows a
|
||||
|
@ -1345,28 +1417,65 @@ bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
|
|||
// We also need to validate that the field number is in an extension range iff
|
||||
// it is an extension.
|
||||
|
||||
// This method is idempotent. Check if |f| is already part of this msgdef and
|
||||
// return immediately if so.
|
||||
if (upb_fielddef_containingtype(f) == m) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check constraints for all fields before performing any action.
|
||||
if (upb_fielddef_containingtype(f) != NULL) {
|
||||
upb_status_seterrmsg(s, "fielddef already belongs to a message");
|
||||
if (!check_field_add(m, f, s)) {
|
||||
return false;
|
||||
} else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
|
||||
upb_status_seterrmsg(s, "field name or number were not set");
|
||||
return false;
|
||||
} else if(upb_msgdef_itof(m, upb_fielddef_number(f)) ||
|
||||
upb_msgdef_ntofz(m, upb_fielddef_name(f))) {
|
||||
upb_status_seterrmsg(s, "duplicate field name or number");
|
||||
} else if (upb_fielddef_containingoneof(f) != NULL) {
|
||||
// Fields in a oneof can only be added by adding the oneof to the msgdef.
|
||||
upb_status_seterrmsg(s, "fielddef is part of a oneof");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Constraint checks ok, perform the action.
|
||||
release_containingtype(f);
|
||||
f->msg.def = m;
|
||||
f->msg_is_symbolic = false;
|
||||
upb_inttable_insert(&m->itof, upb_fielddef_number(f), upb_value_ptr(f));
|
||||
upb_strtable_insert(&m->ntof, upb_fielddef_name(f), upb_value_ptr(f));
|
||||
upb_ref2(f, m);
|
||||
upb_ref2(m, f);
|
||||
if (ref_donor) upb_fielddef_unref(f, ref_donor);
|
||||
add_field(m, f, ref_donor);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor,
|
||||
upb_status *s) {
|
||||
// Check various conditions that would prevent this oneof from being added.
|
||||
if (upb_oneofdef_containingtype(o)) {
|
||||
upb_status_seterrmsg(s, "oneofdef already belongs to a message");
|
||||
return false;
|
||||
} else if (upb_oneofdef_name(o) == NULL) {
|
||||
upb_status_seterrmsg(s, "oneofdef name was not set");
|
||||
return false;
|
||||
} else if (upb_msgdef_ntooz(m, upb_oneofdef_name(o))) {
|
||||
upb_status_seterrmsg(s, "duplicate oneof name");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that all of the oneof's fields do not conflict with names or numbers
|
||||
// of fields already in the message.
|
||||
upb_oneof_iter it;
|
||||
for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) {
|
||||
const upb_fielddef *f = upb_oneof_iter_field(&it);
|
||||
if (!check_field_add(m, f, s)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything checks out -- commit now.
|
||||
|
||||
// Add oneof itself first.
|
||||
o->parent = m;
|
||||
upb_strtable_insert(&m->ntoo, upb_oneofdef_name(o), upb_value_ptr(o));
|
||||
upb_ref2(o, m);
|
||||
upb_ref2(m, o);
|
||||
|
||||
// Add each field of the oneof directly to the msgdef.
|
||||
for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) {
|
||||
upb_fielddef *f = upb_oneof_iter_field(&it);
|
||||
add_field(m, f, NULL);
|
||||
}
|
||||
|
||||
if (ref_donor) upb_oneofdef_unref(o, ref_donor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1384,10 +1493,21 @@ const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
|
|||
upb_value_getptr(val) : NULL;
|
||||
}
|
||||
|
||||
const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
|
||||
size_t len) {
|
||||
upb_value val;
|
||||
return upb_strtable_lookup2(&m->ntoo, name, len, &val) ?
|
||||
upb_value_getptr(val) : NULL;
|
||||
}
|
||||
|
||||
int upb_msgdef_numfields(const upb_msgdef *m) {
|
||||
return upb_strtable_count(&m->ntof);
|
||||
}
|
||||
|
||||
int upb_msgdef_numoneofs(const upb_msgdef *m) {
|
||||
return upb_strtable_count(&m->ntoo);
|
||||
}
|
||||
|
||||
void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry) {
|
||||
assert(!upb_msgdef_isfrozen(m));
|
||||
m->map_entry = map_entry;
|
||||
|
@ -1397,19 +1517,246 @@ bool upb_msgdef_mapentry(const upb_msgdef *m) {
|
|||
return m->map_entry;
|
||||
}
|
||||
|
||||
void upb_msg_begin(upb_msg_iter *iter, const upb_msgdef *m) {
|
||||
void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) {
|
||||
upb_inttable_begin(iter, &m->itof);
|
||||
}
|
||||
|
||||
void upb_msg_next(upb_msg_iter *iter) { upb_inttable_next(iter); }
|
||||
void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); }
|
||||
|
||||
bool upb_msg_done(const upb_msg_iter *iter) { return upb_inttable_done(iter); }
|
||||
bool upb_msg_field_done(const upb_msg_field_iter *iter) {
|
||||
return upb_inttable_done(iter);
|
||||
}
|
||||
|
||||
upb_fielddef *upb_msg_iter_field(const upb_msg_iter *iter) {
|
||||
upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) {
|
||||
return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter));
|
||||
}
|
||||
|
||||
void upb_msg_iter_setdone(upb_msg_iter *iter) {
|
||||
void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) {
|
||||
upb_inttable_iter_setdone(iter);
|
||||
}
|
||||
|
||||
void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) {
|
||||
upb_strtable_begin(iter, &m->ntoo);
|
||||
}
|
||||
|
||||
void upb_msg_oneof_next(upb_msg_oneof_iter *iter) { upb_strtable_next(iter); }
|
||||
|
||||
bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) {
|
||||
return upb_strtable_done(iter);
|
||||
}
|
||||
|
||||
upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) {
|
||||
return (upb_oneofdef*)upb_value_getptr(upb_strtable_iter_value(iter));
|
||||
}
|
||||
|
||||
void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) {
|
||||
upb_strtable_iter_setdone(iter);
|
||||
}
|
||||
|
||||
/* upb_oneofdef ***************************************************************/
|
||||
|
||||
static void visitoneof(const upb_refcounted *r, upb_refcounted_visit *visit,
|
||||
void *closure) {
|
||||
const upb_oneofdef *o = (const upb_oneofdef*)r;
|
||||
upb_oneof_iter i;
|
||||
for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) {
|
||||
const upb_fielddef *f = upb_oneof_iter_field(&i);
|
||||
visit(r, UPB_UPCAST2(f), closure);
|
||||
}
|
||||
if (o->parent) {
|
||||
visit(r, UPB_UPCAST2(o->parent), closure);
|
||||
}
|
||||
}
|
||||
|
||||
static void freeoneof(upb_refcounted *r) {
|
||||
upb_oneofdef *o = (upb_oneofdef*)r;
|
||||
upb_strtable_uninit(&o->ntof);
|
||||
upb_inttable_uninit(&o->itof);
|
||||
upb_def_uninit(UPB_UPCAST(o));
|
||||
free(o);
|
||||
}
|
||||
|
||||
upb_oneofdef *upb_oneofdef_new(const void *owner) {
|
||||
static const struct upb_refcounted_vtbl vtbl = {visitoneof, freeoneof};
|
||||
upb_oneofdef *o = malloc(sizeof(*o));
|
||||
o->parent = NULL;
|
||||
if (!o) return NULL;
|
||||
if (!upb_def_init(UPB_UPCAST(o), UPB_DEF_ONEOF, &vtbl, owner)) goto err2;
|
||||
if (!upb_inttable_init(&o->itof, UPB_CTYPE_PTR)) goto err2;
|
||||
if (!upb_strtable_init(&o->ntof, UPB_CTYPE_PTR)) goto err1;
|
||||
return o;
|
||||
|
||||
err1:
|
||||
upb_inttable_uninit(&o->itof);
|
||||
err2:
|
||||
free(o);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner) {
|
||||
upb_oneofdef *newo = upb_oneofdef_new(owner);
|
||||
if (!newo) return NULL;
|
||||
bool ok = upb_def_setfullname(UPB_UPCAST(newo),
|
||||
upb_def_fullname(UPB_UPCAST(o)), NULL);
|
||||
UPB_ASSERT_VAR(ok, ok);
|
||||
upb_oneof_iter i;
|
||||
for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) {
|
||||
upb_fielddef *f = upb_fielddef_dup(upb_oneof_iter_field(&i), &f);
|
||||
if (!f || !upb_oneofdef_addfield(newo, f, &f, NULL)) {
|
||||
upb_oneofdef_unref(newo, owner);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return newo;
|
||||
}
|
||||
|
||||
bool upb_oneofdef_isfrozen(const upb_oneofdef *o) {
|
||||
return upb_def_isfrozen(UPB_UPCAST(o));
|
||||
}
|
||||
|
||||
void upb_oneofdef_ref(const upb_oneofdef *o, const void *owner) {
|
||||
upb_def_ref(UPB_UPCAST(o), owner);
|
||||
}
|
||||
|
||||
void upb_oneofdef_unref(const upb_oneofdef *o, const void *owner) {
|
||||
upb_def_unref(UPB_UPCAST(o), owner);
|
||||
}
|
||||
|
||||
void upb_oneofdef_donateref(const upb_oneofdef *o, const void *from,
|
||||
const void *to) {
|
||||
upb_def_donateref(UPB_UPCAST(o), from, to);
|
||||
}
|
||||
|
||||
void upb_oneofdef_checkref(const upb_oneofdef *o, const void *owner) {
|
||||
upb_def_checkref(UPB_UPCAST(o), owner);
|
||||
}
|
||||
|
||||
const char *upb_oneofdef_name(const upb_oneofdef *o) {
|
||||
return upb_def_fullname(UPB_UPCAST(o));
|
||||
}
|
||||
|
||||
bool upb_oneofdef_setname(upb_oneofdef *o, const char *fullname,
|
||||
upb_status *s) {
|
||||
if (upb_oneofdef_containingtype(o)) {
|
||||
upb_status_seterrmsg(s, "oneof already added to a message");
|
||||
return false;
|
||||
}
|
||||
return upb_def_setfullname(UPB_UPCAST(o), fullname, s);
|
||||
}
|
||||
|
||||
const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) {
|
||||
return o->parent;
|
||||
}
|
||||
|
||||
int upb_oneofdef_numfields(const upb_oneofdef *o) {
|
||||
return upb_strtable_count(&o->ntof);
|
||||
}
|
||||
|
||||
bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
|
||||
const void *ref_donor,
|
||||
upb_status *s) {
|
||||
assert(!upb_oneofdef_isfrozen(o));
|
||||
assert(!o->parent || !upb_msgdef_isfrozen(o->parent));
|
||||
|
||||
// This method is idempotent. Check if |f| is already part of this oneofdef
|
||||
// and return immediately if so.
|
||||
if (upb_fielddef_containingoneof(f) == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The field must have an OPTIONAL label.
|
||||
if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) {
|
||||
upb_status_seterrmsg(s, "fields in oneof must have OPTIONAL label");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that no field with this name or number exists already in the oneof.
|
||||
// Also check that the field is not already part of a oneof.
|
||||
if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
|
||||
upb_status_seterrmsg(s, "field name or number were not set");
|
||||
return false;
|
||||
} else if (upb_oneofdef_itof(o, upb_fielddef_number(f)) ||
|
||||
upb_oneofdef_ntofz(o, upb_fielddef_name(f))) {
|
||||
upb_status_seterrmsg(s, "duplicate field name or number");
|
||||
return false;
|
||||
} else if (upb_fielddef_containingoneof(f) != NULL) {
|
||||
upb_status_seterrmsg(s, "fielddef already belongs to a oneof");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We allow adding a field to the oneof either if the field is not part of a
|
||||
// msgdef, or if it is and we are also part of the same msgdef.
|
||||
if (o->parent == NULL) {
|
||||
// If we're not in a msgdef, the field cannot be either. Otherwise we would
|
||||
// need to magically add this oneof to a msgdef to remain consistent, which
|
||||
// is surprising behavior.
|
||||
if (upb_fielddef_containingtype(f) != NULL) {
|
||||
upb_status_seterrmsg(s, "fielddef already belongs to a message, but "
|
||||
"oneof does not");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// If we're in a msgdef, the user can add fields that either aren't in any
|
||||
// msgdef (in which case they're added to our msgdef) or already a part of
|
||||
// our msgdef.
|
||||
if (upb_fielddef_containingtype(f) != NULL &&
|
||||
upb_fielddef_containingtype(f) != o->parent) {
|
||||
upb_status_seterrmsg(s, "fielddef belongs to a different message "
|
||||
"than oneof");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit phase. First add the field to our parent msgdef, if any, because
|
||||
// that may fail; then add the field to our own tables.
|
||||
|
||||
if (o->parent != NULL && upb_fielddef_containingtype(f) == NULL) {
|
||||
if (!upb_msgdef_addfield((upb_msgdef*)o->parent, f, NULL, s)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
release_containingtype(f);
|
||||
f->oneof = o;
|
||||
upb_inttable_insert(&o->itof, upb_fielddef_number(f), upb_value_ptr(f));
|
||||
upb_strtable_insert(&o->ntof, upb_fielddef_name(f), upb_value_ptr(f));
|
||||
upb_ref2(f, o);
|
||||
upb_ref2(o, f);
|
||||
if (ref_donor) upb_fielddef_unref(f, ref_donor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
|
||||
const char *name, size_t length) {
|
||||
upb_value val;
|
||||
return upb_strtable_lookup2(&o->ntof, name, length, &val) ?
|
||||
upb_value_getptr(val) : NULL;
|
||||
}
|
||||
|
||||
const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) {
|
||||
upb_value val;
|
||||
return upb_inttable_lookup32(&o->itof, num, &val) ?
|
||||
upb_value_getptr(val) : NULL;
|
||||
}
|
||||
|
||||
void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) {
|
||||
upb_inttable_begin(iter, &o->itof);
|
||||
}
|
||||
|
||||
void upb_oneof_next(upb_oneof_iter *iter) {
|
||||
upb_inttable_next(iter);
|
||||
}
|
||||
|
||||
bool upb_oneof_done(upb_oneof_iter *iter) {
|
||||
return upb_inttable_done(iter);
|
||||
}
|
||||
|
||||
upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) {
|
||||
return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter));
|
||||
}
|
||||
|
||||
void upb_oneof_iter_setdone(upb_oneof_iter *iter) {
|
||||
upb_inttable_iter_setdone(iter);
|
||||
}
|
||||
/*
|
||||
|
@ -1452,8 +1799,10 @@ static void freehandlers(upb_refcounted *r) {
|
|||
static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit,
|
||||
void *closure) {
|
||||
const upb_handlers *h = (const upb_handlers*)r;
|
||||
upb_msg_iter i;
|
||||
for(upb_msg_begin(&i, h->msg); !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
for(upb_msg_field_begin(&i, h->msg);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
if (!upb_fielddef_issubmsg(f)) continue;
|
||||
const upb_handlers *sub = upb_handlers_getsubhandlers(h, f);
|
||||
|
@ -1482,8 +1831,10 @@ static upb_handlers *newformsg(const upb_msgdef *m, const void *owner,
|
|||
|
||||
// For each submessage field, get or create a handlers object and set it as
|
||||
// the subhandlers.
|
||||
upb_msg_iter i;
|
||||
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
for(upb_msg_field_begin(&i, m);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
if (!upb_fielddef_issubmsg(f)) continue;
|
||||
|
||||
|
@ -1840,8 +2191,10 @@ bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
|
|||
|
||||
// Check that there are no closure mismatches due to missing Start* handlers
|
||||
// or subhandlers with different type-level types.
|
||||
upb_msg_iter j;
|
||||
for(upb_msg_begin(&j, h->msg); !upb_msg_done(&j); upb_msg_next(&j)) {
|
||||
upb_msg_field_iter j;
|
||||
for(upb_msg_field_begin(&j, h->msg);
|
||||
!upb_msg_field_done(&j);
|
||||
upb_msg_field_next(&j)) {
|
||||
|
||||
const upb_fielddef *f = upb_msg_iter_field(&j);
|
||||
if (upb_fielddef_isseq(f)) {
|
||||
|
@ -3114,8 +3467,10 @@ static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab,
|
|||
// For messages, continue the recursion by visiting all subdefs.
|
||||
const upb_msgdef *m = upb_dyncast_msgdef(def);
|
||||
if (m) {
|
||||
upb_msg_iter i;
|
||||
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
for(upb_msg_field_begin(&i, m);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
if (!upb_fielddef_hassubdef(f)) continue;
|
||||
// |= to avoid short-circuit; we need its side-effects.
|
||||
|
@ -3268,8 +3623,10 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
|
|||
// Type names are resolved relative to the message in which they appear.
|
||||
const char *base = upb_msgdef_fullname(m);
|
||||
|
||||
upb_msg_iter j;
|
||||
for(upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j)) {
|
||||
upb_msg_field_iter j;
|
||||
for(upb_msg_field_begin(&j, m);
|
||||
!upb_msg_field_done(&j);
|
||||
upb_msg_field_next(&j)) {
|
||||
upb_fielddef *f = upb_msg_iter_field(&j);
|
||||
const char *name = upb_fielddef_subdefname(f);
|
||||
if (name && !upb_fielddef_subdef(f)) {
|
||||
|
@ -3416,16 +3773,12 @@ char *upb_strdup(const char *s) {
|
|||
}
|
||||
|
||||
char *upb_strdup2(const char *s, size_t len) {
|
||||
// Prevent overflow errors.
|
||||
if (len == SIZE_MAX) return NULL;
|
||||
// Always null-terminate, even if binary data; but don't rely on the input to
|
||||
// have a null-terminating byte since it may be a raw binary buffer.
|
||||
size_t n = len + 1;
|
||||
char *p = malloc(n);
|
||||
if (p) {
|
||||
memcpy(p, s, len);
|
||||
p[len] = 0;
|
||||
}
|
||||
if (p) memcpy(p, s, len);
|
||||
p[len] = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -6462,8 +6815,10 @@ static void compile_method(compiler *c, upb_pbdecodermethod *method) {
|
|||
putsel(c, OP_STARTMSG, UPB_STARTMSG_SELECTOR, h);
|
||||
label(c, LABEL_FIELD);
|
||||
uint32_t* start_pc = c->pc;
|
||||
upb_msg_iter i;
|
||||
for(upb_msg_begin(&i, md); !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
for(upb_msg_field_begin(&i, md);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
const upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
upb_fieldtype_t type = upb_fielddef_type(f);
|
||||
|
||||
|
@ -6513,9 +6868,11 @@ static void find_methods(compiler *c, const upb_handlers *h) {
|
|||
newmethod(h, c->group);
|
||||
|
||||
// Find submethods.
|
||||
upb_msg_iter i;
|
||||
upb_msg_field_iter i;
|
||||
const upb_msgdef *md = upb_handlers_msgdef(h);
|
||||
for(upb_msg_begin(&i, md); !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
for(upb_msg_field_begin(&i, md);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
const upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
const upb_handlers *sub_h;
|
||||
if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
|
||||
|
@ -6557,7 +6914,7 @@ static void set_bytecode_handlers(mgroup *g) {
|
|||
}
|
||||
|
||||
|
||||
/* JIT setup. ******************************************************************/
|
||||
/* JIT setup. *****************************************************************/
|
||||
|
||||
#ifdef UPB_USE_JIT_X64
|
||||
|
||||
|
@ -7980,8 +8337,10 @@ static void newhandlers_callback(const void *closure, upb_handlers *h) {
|
|||
upb_handlers_setendmsg(h, endmsg, NULL);
|
||||
|
||||
const upb_msgdef *m = upb_handlers_msgdef(h);
|
||||
upb_msg_iter i;
|
||||
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
for(upb_msg_field_begin(&i, m);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
const upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) &&
|
||||
upb_fielddef_packed(f);
|
||||
|
@ -8443,8 +8802,10 @@ static void onmreg(const void *c, upb_handlers *h) {
|
|||
upb_handlers_setstartmsg(h, textprinter_startmsg, NULL);
|
||||
upb_handlers_setendmsg(h, textprinter_endmsg, NULL);
|
||||
|
||||
upb_msg_iter i;
|
||||
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
for(upb_msg_field_begin(&i, m);
|
||||
!upb_msg_field_done(&i);
|
||||
upb_msg_field_next(&i)) {
|
||||
upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
|
||||
upb_handlerattr_sethandlerdata(&attr, f);
|
||||
|
@ -8857,6 +9218,7 @@ badpadding:
|
|||
// the true value in a contiguous buffer.
|
||||
|
||||
static void assert_accumulate_empty(upb_json_parser *p) {
|
||||
UPB_UNUSED(p);
|
||||
assert(p->accumulated == NULL);
|
||||
assert(p->accumulated_len == 0);
|
||||
}
|
||||
|
@ -9442,11 +9804,11 @@ static void end_object(upb_json_parser *p) {
|
|||
// final state once, when the closing '"' is seen.
|
||||
|
||||
|
||||
#line 904 "upb/json/parser.rl"
|
||||
#line 905 "upb/json/parser.rl"
|
||||
|
||||
|
||||
|
||||
#line 816 "upb/json/parser.c"
|
||||
#line 817 "upb/json/parser.c"
|
||||
static const char _json_actions[] = {
|
||||
0, 1, 0, 1, 2, 1, 3, 1,
|
||||
5, 1, 6, 1, 7, 1, 8, 1,
|
||||
|
@ -9597,7 +9959,7 @@ static const int json_en_value_machine = 27;
|
|||
static const int json_en_main = 1;
|
||||
|
||||
|
||||
#line 907 "upb/json/parser.rl"
|
||||
#line 908 "upb/json/parser.rl"
|
||||
|
||||
size_t parse(void *closure, const void *hd, const char *buf, size_t size,
|
||||
const upb_bufhandle *handle) {
|
||||
|
@ -9617,7 +9979,7 @@ size_t parse(void *closure, const void *hd, const char *buf, size_t size,
|
|||
capture_resume(parser, buf);
|
||||
|
||||
|
||||
#line 987 "upb/json/parser.c"
|
||||
#line 988 "upb/json/parser.c"
|
||||
{
|
||||
int _klen;
|
||||
unsigned int _trans;
|
||||
|
@ -9692,118 +10054,118 @@ _match:
|
|||
switch ( *_acts++ )
|
||||
{
|
||||
case 0:
|
||||
#line 819 "upb/json/parser.rl"
|
||||
#line 820 "upb/json/parser.rl"
|
||||
{ p--; {cs = stack[--top]; goto _again;} }
|
||||
break;
|
||||
case 1:
|
||||
#line 820 "upb/json/parser.rl"
|
||||
#line 821 "upb/json/parser.rl"
|
||||
{ p--; {stack[top++] = cs; cs = 10; goto _again;} }
|
||||
break;
|
||||
case 2:
|
||||
#line 824 "upb/json/parser.rl"
|
||||
#line 825 "upb/json/parser.rl"
|
||||
{ start_text(parser, p); }
|
||||
break;
|
||||
case 3:
|
||||
#line 825 "upb/json/parser.rl"
|
||||
#line 826 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(end_text(parser, p)); }
|
||||
break;
|
||||
case 4:
|
||||
#line 831 "upb/json/parser.rl"
|
||||
#line 832 "upb/json/parser.rl"
|
||||
{ start_hex(parser); }
|
||||
break;
|
||||
case 5:
|
||||
#line 832 "upb/json/parser.rl"
|
||||
#line 833 "upb/json/parser.rl"
|
||||
{ hexdigit(parser, p); }
|
||||
break;
|
||||
case 6:
|
||||
#line 833 "upb/json/parser.rl"
|
||||
#line 834 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(end_hex(parser)); }
|
||||
break;
|
||||
case 7:
|
||||
#line 839 "upb/json/parser.rl"
|
||||
#line 840 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(escape(parser, p)); }
|
||||
break;
|
||||
case 8:
|
||||
#line 845 "upb/json/parser.rl"
|
||||
#line 846 "upb/json/parser.rl"
|
||||
{ p--; {cs = stack[--top]; goto _again;} }
|
||||
break;
|
||||
case 9:
|
||||
#line 848 "upb/json/parser.rl"
|
||||
#line 849 "upb/json/parser.rl"
|
||||
{ {stack[top++] = cs; cs = 19; goto _again;} }
|
||||
break;
|
||||
case 10:
|
||||
#line 850 "upb/json/parser.rl"
|
||||
#line 851 "upb/json/parser.rl"
|
||||
{ p--; {stack[top++] = cs; cs = 27; goto _again;} }
|
||||
break;
|
||||
case 11:
|
||||
#line 855 "upb/json/parser.rl"
|
||||
#line 856 "upb/json/parser.rl"
|
||||
{ start_member(parser); }
|
||||
break;
|
||||
case 12:
|
||||
#line 856 "upb/json/parser.rl"
|
||||
#line 857 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(end_member(parser)); }
|
||||
break;
|
||||
case 13:
|
||||
#line 859 "upb/json/parser.rl"
|
||||
#line 860 "upb/json/parser.rl"
|
||||
{ clear_member(parser); }
|
||||
break;
|
||||
case 14:
|
||||
#line 865 "upb/json/parser.rl"
|
||||
#line 866 "upb/json/parser.rl"
|
||||
{ start_object(parser); }
|
||||
break;
|
||||
case 15:
|
||||
#line 868 "upb/json/parser.rl"
|
||||
#line 869 "upb/json/parser.rl"
|
||||
{ end_object(parser); }
|
||||
break;
|
||||
case 16:
|
||||
#line 874 "upb/json/parser.rl"
|
||||
#line 875 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(start_array(parser)); }
|
||||
break;
|
||||
case 17:
|
||||
#line 878 "upb/json/parser.rl"
|
||||
#line 879 "upb/json/parser.rl"
|
||||
{ end_array(parser); }
|
||||
break;
|
||||
case 18:
|
||||
#line 883 "upb/json/parser.rl"
|
||||
#line 884 "upb/json/parser.rl"
|
||||
{ start_number(parser, p); }
|
||||
break;
|
||||
case 19:
|
||||
#line 884 "upb/json/parser.rl"
|
||||
#line 885 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(end_number(parser, p)); }
|
||||
break;
|
||||
case 20:
|
||||
#line 886 "upb/json/parser.rl"
|
||||
#line 887 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(start_stringval(parser)); }
|
||||
break;
|
||||
case 21:
|
||||
#line 887 "upb/json/parser.rl"
|
||||
#line 888 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(end_stringval(parser)); }
|
||||
break;
|
||||
case 22:
|
||||
#line 889 "upb/json/parser.rl"
|
||||
#line 890 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(parser_putbool(parser, true)); }
|
||||
break;
|
||||
case 23:
|
||||
#line 891 "upb/json/parser.rl"
|
||||
#line 892 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(parser_putbool(parser, false)); }
|
||||
break;
|
||||
case 24:
|
||||
#line 893 "upb/json/parser.rl"
|
||||
#line 894 "upb/json/parser.rl"
|
||||
{ /* null value */ }
|
||||
break;
|
||||
case 25:
|
||||
#line 895 "upb/json/parser.rl"
|
||||
#line 896 "upb/json/parser.rl"
|
||||
{ CHECK_RETURN_TOP(start_subobject(parser)); }
|
||||
break;
|
||||
case 26:
|
||||
#line 896 "upb/json/parser.rl"
|
||||
#line 897 "upb/json/parser.rl"
|
||||
{ end_subobject(parser); }
|
||||
break;
|
||||
case 27:
|
||||
#line 901 "upb/json/parser.rl"
|
||||
#line 902 "upb/json/parser.rl"
|
||||
{ p--; {cs = stack[--top]; goto _again;} }
|
||||
break;
|
||||
#line 1173 "upb/json/parser.c"
|
||||
#line 1174 "upb/json/parser.c"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9816,7 +10178,7 @@ _again:
|
|||
_out: {}
|
||||
}
|
||||
|
||||
#line 926 "upb/json/parser.rl"
|
||||
#line 927 "upb/json/parser.rl"
|
||||
|
||||
if (p != pe) {
|
||||
upb_status_seterrf(parser->status, "Parse error at %s\n", p);
|
||||
|
@ -9865,13 +10227,13 @@ void upb_json_parser_reset(upb_json_parser *p) {
|
|||
int top;
|
||||
// Emit Ragel initialization of the parser.
|
||||
|
||||
#line 1235 "upb/json/parser.c"
|
||||
#line 1236 "upb/json/parser.c"
|
||||
{
|
||||
cs = json_start;
|
||||
top = 0;
|
||||
}
|
||||
|
||||
#line 974 "upb/json/parser.rl"
|
||||
#line 975 "upb/json/parser.rl"
|
||||
p->current_state = cs;
|
||||
p->parser_top = top;
|
||||
accumulate_clear(p);
|
||||
|
@ -10327,9 +10689,9 @@ void printer_sethandlers(const void *closure, upb_handlers *h) {
|
|||
} \
|
||||
break;
|
||||
|
||||
upb_msg_iter i;
|
||||
upb_msg_begin(&i, upb_handlers_msgdef(h));
|
||||
for(; !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
upb_msg_field_iter i;
|
||||
upb_msg_field_begin(&i, upb_handlers_msgdef(h));
|
||||
for(; !upb_msg_field_done(&i); upb_msg_field_next(&i)) {
|
||||
const upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
|
||||
upb_handlerattr name_attr = UPB_HANDLERATTR_INITIALIZER;
|
||||
|
|
|
@ -710,6 +710,9 @@ typedef struct {
|
|||
#define UPB_STRTABLE_INIT(count, mask, ctype, size_lg2, entries) \
|
||||
{{count, mask, ctype, size_lg2, entries}}
|
||||
|
||||
#define UPB_EMPTY_STRTABLE_INIT(ctype) \
|
||||
UPB_STRTABLE_INIT(0, 0, ctype, 0, NULL)
|
||||
|
||||
typedef struct {
|
||||
upb_table t; // For entries that don't fit in the array part.
|
||||
const _upb_value *array; // Array part of the table. See const note above.
|
||||
|
@ -1129,6 +1132,7 @@ class Def;
|
|||
class EnumDef;
|
||||
class FieldDef;
|
||||
class MessageDef;
|
||||
class OneofDef;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1136,6 +1140,7 @@ UPB_DECLARE_TYPE(upb::Def, upb_def);
|
|||
UPB_DECLARE_TYPE(upb::EnumDef, upb_enumdef);
|
||||
UPB_DECLARE_TYPE(upb::FieldDef, upb_fielddef);
|
||||
UPB_DECLARE_TYPE(upb::MessageDef, upb_msgdef);
|
||||
UPB_DECLARE_TYPE(upb::OneofDef, upb_oneofdef);
|
||||
|
||||
// Maximum field number allowed for FieldDefs. This is an inherent limit of the
|
||||
// protobuf wire format.
|
||||
|
@ -1159,6 +1164,7 @@ typedef enum {
|
|||
UPB_DEF_MSG,
|
||||
UPB_DEF_FIELD,
|
||||
UPB_DEF_ENUM,
|
||||
UPB_DEF_ONEOF,
|
||||
UPB_DEF_SERVICE, // Not yet implemented.
|
||||
UPB_DEF_ANY = -1, // Wildcard for upb_symtab_get*()
|
||||
} upb_deftype_t;
|
||||
|
@ -1443,6 +1449,10 @@ UPB_DEFINE_DEF(upb::FieldDef, fielddef, FIELD,
|
|||
const MessageDef* containing_type() const;
|
||||
const char* containing_type_name();
|
||||
|
||||
// The OneofDef to which this field belongs, or NULL if this field is not part
|
||||
// of a oneof.
|
||||
const OneofDef* containing_oneof() const;
|
||||
|
||||
// The field's type according to the enum in descriptor.proto. This is not
|
||||
// the same as UPB_TYPE_*, because it distinguishes between (for example)
|
||||
// INT32 and SINT32, whereas our "type" enum does not. This return of
|
||||
|
@ -1616,6 +1626,7 @@ UPB_DEFINE_STRUCT(upb_fielddef, upb_def,
|
|||
} sub; // The msgdef or enumdef for this field, if upb_hassubdef(f).
|
||||
bool subdef_is_symbolic;
|
||||
bool msg_is_symbolic;
|
||||
const upb_oneofdef *oneof;
|
||||
bool default_is_string;
|
||||
bool type_is_set_; // False until type is explicitly set.
|
||||
bool is_extension_;
|
||||
|
@ -1631,11 +1642,11 @@ UPB_DEFINE_STRUCT(upb_fielddef, upb_def,
|
|||
));
|
||||
|
||||
#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, lazy, \
|
||||
packed, name, num, msgdef, subdef, selector_base, \
|
||||
packed, name, num, msgdef, subdef, selector_base, \
|
||||
index, defaultval, refs, ref2s) \
|
||||
{ \
|
||||
UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, {msgdef}, \
|
||||
{subdef}, false, false, \
|
||||
{subdef}, NULL, false, false, \
|
||||
type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, is_extension, \
|
||||
lazy, packed, intfmt, tagdelim, type, label, num, selector_base, index \
|
||||
}
|
||||
|
@ -1669,6 +1680,7 @@ bool upb_fielddef_isextension(const upb_fielddef *f);
|
|||
bool upb_fielddef_lazy(const upb_fielddef *f);
|
||||
bool upb_fielddef_packed(const upb_fielddef *f);
|
||||
const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f);
|
||||
const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f);
|
||||
upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f);
|
||||
const char *upb_fielddef_containingtypename(upb_fielddef *f);
|
||||
upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f);
|
||||
|
@ -1736,7 +1748,8 @@ UPB_END_EXTERN_C // }
|
|||
|
||||
/* upb::MessageDef ************************************************************/
|
||||
|
||||
typedef upb_inttable_iter upb_msg_iter;
|
||||
typedef upb_inttable_iter upb_msg_field_iter;
|
||||
typedef upb_strtable_iter upb_msg_oneof_iter;
|
||||
|
||||
// Structure that describes a single .proto message type.
|
||||
//
|
||||
|
@ -1766,14 +1779,37 @@ UPB_DEFINE_DEF(upb::MessageDef, msgdef, MSG, UPB_QUOTE(
|
|||
// The number of fields that belong to the MessageDef.
|
||||
int field_count() const;
|
||||
|
||||
// The number of oneofs that belong to the MessageDef.
|
||||
int oneof_count() const;
|
||||
|
||||
// Adds a field (upb_fielddef object) to a msgdef. Requires that the msgdef
|
||||
// and the fielddefs are mutable. The fielddef's name and number must be
|
||||
// set, and the message may not already contain any field with this name or
|
||||
// number, and this fielddef may not be part of another message. In error
|
||||
// cases false is returned and the msgdef is unchanged.
|
||||
//
|
||||
// If the given field is part of a oneof, this call succeeds if and only if
|
||||
// that oneof is already part of this msgdef. (Note that adding a oneof to a
|
||||
// msgdef automatically adds all of its fields to the msgdef at the time that
|
||||
// the oneof is added, so it is usually more idiomatic to add the oneof's
|
||||
// fields first then add the oneof to the msgdef. This case is supported for
|
||||
// convenience.)
|
||||
//
|
||||
// If |f| is already part of this MessageDef, this method performs no action
|
||||
// and returns true (success). Thus, this method is idempotent.
|
||||
bool AddField(FieldDef* f, Status* s);
|
||||
bool AddField(const reffed_ptr<FieldDef>& f, Status* s);
|
||||
|
||||
// Adds a oneof (upb_oneofdef object) to a msgdef. Requires that the msgdef,
|
||||
// oneof, and any fielddefs are mutable, that the fielddefs contained in the
|
||||
// oneof do not have any name or number conflicts with existing fields in the
|
||||
// msgdef, and that the oneof's name is unique among all oneofs in the msgdef.
|
||||
// If the oneof is added successfully, all of its fields will be added
|
||||
// directly to the msgdef as well. In error cases, false is returned and the
|
||||
// msgdef is unchanged.
|
||||
bool AddOneof(OneofDef* o, Status* s);
|
||||
bool AddOneof(const reffed_ptr<OneofDef>& o, Status* s);
|
||||
|
||||
// These return NULL if the field is not found.
|
||||
FieldDef* FindFieldByNumber(uint32_t number);
|
||||
FieldDef* FindFieldByName(const char *name, size_t len);
|
||||
|
@ -1797,6 +1833,25 @@ UPB_DEFINE_DEF(upb::MessageDef, msgdef, MSG, UPB_QUOTE(
|
|||
return FindFieldByName(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
OneofDef* FindOneofByName(const char* name, size_t len);
|
||||
const OneofDef* FindOneofByName(const char* name, size_t len) const;
|
||||
|
||||
OneofDef* FindOneofByName(const char* name) {
|
||||
return FindOneofByName(name, strlen(name));
|
||||
}
|
||||
const OneofDef* FindOneofByName(const char* name) const {
|
||||
return FindOneofByName(name, strlen(name));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
OneofDef* FindOneofByName(const T& str) {
|
||||
return FindOneofByName(str.c_str(), str.size());
|
||||
}
|
||||
template<class T>
|
||||
const OneofDef* FindOneofByName(const T& str) const {
|
||||
return FindOneofByName(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
// Returns a new msgdef that is a copy of the given msgdef (and a copy of all
|
||||
// the fields) but with any references to submessages broken and replaced
|
||||
// with just the name of the submessage. Returns NULL if memory allocation
|
||||
|
@ -1812,39 +1867,117 @@ UPB_DEFINE_DEF(upb::MessageDef, msgdef, MSG, UPB_QUOTE(
|
|||
bool mapentry() const;
|
||||
|
||||
// Iteration over fields. The order is undefined.
|
||||
class iterator : public std::iterator<std::forward_iterator_tag, FieldDef*> {
|
||||
class field_iterator
|
||||
: public std::iterator<std::forward_iterator_tag, FieldDef*> {
|
||||
public:
|
||||
explicit iterator(MessageDef* md);
|
||||
static iterator end(MessageDef* md);
|
||||
explicit field_iterator(MessageDef* md);
|
||||
static field_iterator end(MessageDef* md);
|
||||
|
||||
void operator++();
|
||||
FieldDef* operator*() const;
|
||||
bool operator!=(const iterator& other) const;
|
||||
bool operator==(const iterator& other) const;
|
||||
bool operator!=(const field_iterator& other) const;
|
||||
bool operator==(const field_iterator& other) const;
|
||||
|
||||
private:
|
||||
upb_msg_iter iter_;
|
||||
upb_msg_field_iter iter_;
|
||||
};
|
||||
|
||||
class const_iterator
|
||||
class const_field_iterator
|
||||
: public std::iterator<std::forward_iterator_tag, const FieldDef*> {
|
||||
public:
|
||||
explicit const_iterator(const MessageDef* md);
|
||||
static const_iterator end(const MessageDef* md);
|
||||
explicit const_field_iterator(const MessageDef* md);
|
||||
static const_field_iterator end(const MessageDef* md);
|
||||
|
||||
void operator++();
|
||||
const FieldDef* operator*() const;
|
||||
bool operator!=(const const_iterator& other) const;
|
||||
bool operator==(const const_iterator& other) const;
|
||||
bool operator!=(const const_field_iterator& other) const;
|
||||
bool operator==(const const_field_iterator& other) const;
|
||||
|
||||
private:
|
||||
upb_msg_iter iter_;
|
||||
upb_msg_field_iter iter_;
|
||||
};
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
// Iteration over oneofs. The order is undefined.
|
||||
class oneof_iterator
|
||||
: public std::iterator<std::forward_iterator_tag, FieldDef*> {
|
||||
public:
|
||||
explicit oneof_iterator(MessageDef* md);
|
||||
static oneof_iterator end(MessageDef* md);
|
||||
|
||||
void operator++();
|
||||
OneofDef* operator*() const;
|
||||
bool operator!=(const oneof_iterator& other) const;
|
||||
bool operator==(const oneof_iterator& other) const;
|
||||
|
||||
private:
|
||||
upb_msg_oneof_iter iter_;
|
||||
};
|
||||
|
||||
class const_oneof_iterator
|
||||
: public std::iterator<std::forward_iterator_tag, const FieldDef*> {
|
||||
public:
|
||||
explicit const_oneof_iterator(const MessageDef* md);
|
||||
static const_oneof_iterator end(const MessageDef* md);
|
||||
|
||||
void operator++();
|
||||
const OneofDef* operator*() const;
|
||||
bool operator!=(const const_oneof_iterator& other) const;
|
||||
bool operator==(const const_oneof_iterator& other) const;
|
||||
|
||||
private:
|
||||
upb_msg_oneof_iter iter_;
|
||||
};
|
||||
|
||||
class FieldAccessor {
|
||||
public:
|
||||
explicit FieldAccessor(MessageDef* msg) : msg_(msg) {}
|
||||
field_iterator begin() { return msg_->field_begin(); }
|
||||
field_iterator end() { return msg_->field_end(); }
|
||||
private:
|
||||
MessageDef* msg_;
|
||||
};
|
||||
|
||||
class ConstFieldAccessor {
|
||||
public:
|
||||
explicit ConstFieldAccessor(const MessageDef* msg) : msg_(msg) {}
|
||||
const_field_iterator begin() { return msg_->field_begin(); }
|
||||
const_field_iterator end() { return msg_->field_end(); }
|
||||
private:
|
||||
const MessageDef* msg_;
|
||||
};
|
||||
|
||||
class OneofAccessor {
|
||||
public:
|
||||
explicit OneofAccessor(MessageDef* msg) : msg_(msg) {}
|
||||
oneof_iterator begin() { return msg_->oneof_begin(); }
|
||||
oneof_iterator end() { return msg_->oneof_end(); }
|
||||
private:
|
||||
MessageDef* msg_;
|
||||
};
|
||||
|
||||
class ConstOneofAccessor {
|
||||
public:
|
||||
explicit ConstOneofAccessor(const MessageDef* msg) : msg_(msg) {}
|
||||
const_oneof_iterator begin() { return msg_->oneof_begin(); }
|
||||
const_oneof_iterator end() { return msg_->oneof_end(); }
|
||||
private:
|
||||
const MessageDef* msg_;
|
||||
};
|
||||
|
||||
field_iterator field_begin();
|
||||
field_iterator field_end();
|
||||
const_field_iterator field_begin() const;
|
||||
const_field_iterator field_end() const;
|
||||
|
||||
oneof_iterator oneof_begin();
|
||||
oneof_iterator oneof_end();
|
||||
const_oneof_iterator oneof_begin() const;
|
||||
const_oneof_iterator oneof_end() const;
|
||||
|
||||
FieldAccessor fields() { return FieldAccessor(this); }
|
||||
ConstFieldAccessor fields() const { return ConstFieldAccessor(this); }
|
||||
OneofAccessor oneofs() { return OneofAccessor(this); }
|
||||
ConstOneofAccessor oneofs() const { return ConstOneofAccessor(this); }
|
||||
|
||||
private:
|
||||
UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef);
|
||||
|
@ -1857,6 +1990,9 @@ UPB_DEFINE_STRUCT(upb_msgdef, upb_def,
|
|||
upb_inttable itof; // int to field
|
||||
upb_strtable ntof; // name to field
|
||||
|
||||
// Tables for looking up oneofs by name.
|
||||
upb_strtable ntoo; // name to oneof
|
||||
|
||||
// Is this a map-entry message?
|
||||
// TODO: set this flag properly for static descriptors; regenerate
|
||||
// descriptor.upb.c.
|
||||
|
@ -1865,11 +2001,14 @@ UPB_DEFINE_STRUCT(upb_msgdef, upb_def,
|
|||
// TODO(haberman): proper extension ranges (there can be multiple).
|
||||
));
|
||||
|
||||
// TODO: also support static initialization of the oneofs table. This will be
|
||||
// needed if we compile in descriptors that contain oneofs.
|
||||
#define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \
|
||||
refs, ref2s) \
|
||||
{ \
|
||||
UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, \
|
||||
submsg_field_count, itof, ntof, false \
|
||||
submsg_field_count, itof, ntof, \
|
||||
UPB_EMPTY_STRTABLE_INIT(UPB_CTYPE_PTR), false \
|
||||
}
|
||||
|
||||
UPB_BEGIN_EXTERN_C // {
|
||||
|
@ -1893,6 +2032,8 @@ bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s);
|
|||
upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner);
|
||||
bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
|
||||
upb_status *s);
|
||||
bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor,
|
||||
upb_status *s);
|
||||
|
||||
// Field lookup in a couple of different variations:
|
||||
// - itof = int to field
|
||||
|
@ -1917,11 +2058,34 @@ UPB_INLINE upb_fielddef *upb_msgdef_ntof_mutable(upb_msgdef *m,
|
|||
return (upb_fielddef *)upb_msgdef_ntof(m, name, len);
|
||||
}
|
||||
|
||||
// Oneof lookup:
|
||||
// - ntoo = name to oneof
|
||||
// - ntooz = name to oneof, null-terminated string.
|
||||
const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
|
||||
size_t len);
|
||||
int upb_msgdef_numoneofs(const upb_msgdef *m);
|
||||
|
||||
UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m,
|
||||
const char *name) {
|
||||
return upb_msgdef_ntoo(m, name, strlen(name));
|
||||
}
|
||||
|
||||
UPB_INLINE upb_oneofdef *upb_msgdef_ntoo_mutable(upb_msgdef *m,
|
||||
const char *name, size_t len) {
|
||||
return (upb_oneofdef *)upb_msgdef_ntoo(m, name, len);
|
||||
}
|
||||
|
||||
void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry);
|
||||
bool upb_msgdef_mapentry(const upb_msgdef *m);
|
||||
|
||||
// upb_msg_iter i;
|
||||
// for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
|
||||
const upb_oneofdef *upb_msgdef_findoneof(const upb_msgdef *m,
|
||||
const char *name);
|
||||
int upb_msgdef_numoneofs(const upb_msgdef *m);
|
||||
|
||||
// upb_msg_field_iter i;
|
||||
// for(upb_msg_field_begin(&i, m);
|
||||
// !upb_msg_field_done(&i);
|
||||
// upb_msg_field_next(&i)) {
|
||||
// upb_fielddef *f = upb_msg_iter_field(&i);
|
||||
// // ...
|
||||
// }
|
||||
|
@ -1929,11 +2093,18 @@ bool upb_msgdef_mapentry(const upb_msgdef *m);
|
|||
// For C we don't have separate iterators for const and non-const.
|
||||
// It is the caller's responsibility to cast the upb_fielddef* to
|
||||
// const if the upb_msgdef* is const.
|
||||
void upb_msg_begin(upb_msg_iter *iter, const upb_msgdef *m);
|
||||
void upb_msg_next(upb_msg_iter *iter);
|
||||
bool upb_msg_done(const upb_msg_iter *iter);
|
||||
upb_fielddef *upb_msg_iter_field(const upb_msg_iter *iter);
|
||||
void upb_msg_iter_setdone(upb_msg_iter *iter);
|
||||
void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m);
|
||||
void upb_msg_field_next(upb_msg_field_iter *iter);
|
||||
bool upb_msg_field_done(const upb_msg_field_iter *iter);
|
||||
upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter);
|
||||
void upb_msg_field_iter_setdone(upb_msg_field_iter *iter);
|
||||
|
||||
// Similar to above, we also support iterating through the oneofs in a msgdef.
|
||||
void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m);
|
||||
void upb_msg_oneof_next(upb_msg_oneof_iter *iter);
|
||||
bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter);
|
||||
upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter);
|
||||
void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter);
|
||||
|
||||
UPB_END_EXTERN_C // }
|
||||
|
||||
|
@ -2075,6 +2246,172 @@ int32_t upb_enum_iter_number(upb_enum_iter *iter);
|
|||
|
||||
UPB_END_EXTERN_C // }
|
||||
|
||||
/* upb::OneofDef **************************************************************/
|
||||
|
||||
typedef upb_inttable_iter upb_oneof_iter;
|
||||
|
||||
// Class that represents a oneof. Its base class is upb::Def (convert with
|
||||
// upb::upcast()).
|
||||
UPB_DEFINE_DEF(upb::OneofDef, oneofdef, ONEOF, UPB_QUOTE(
|
||||
public:
|
||||
// Returns NULL if memory allocation failed.
|
||||
static reffed_ptr<OneofDef> New();
|
||||
|
||||
// Functionality from upb::RefCounted.
|
||||
bool IsFrozen() const;
|
||||
void Ref(const void* owner) const;
|
||||
void Unref(const void* owner) const;
|
||||
void DonateRef(const void* from, const void* to) const;
|
||||
void CheckRef(const void* owner) const;
|
||||
|
||||
// Functionality from upb::Def.
|
||||
const char* full_name() const;
|
||||
|
||||
// Returns the MessageDef that owns this OneofDef.
|
||||
const MessageDef* containing_type() const;
|
||||
|
||||
// Returns the name of this oneof. This is the name used to look up the oneof
|
||||
// by name once added to a message def.
|
||||
const char* name() const;
|
||||
bool set_name(const char* name, Status* s);
|
||||
|
||||
// Returns the number of fields currently defined in the oneof.
|
||||
int field_count() const;
|
||||
|
||||
// Adds a field to the oneof. The field must not have been added to any other
|
||||
// oneof or msgdef. If the oneof is not yet part of a msgdef, then when the
|
||||
// oneof is eventually added to a msgdef, all fields added to the oneof will
|
||||
// also be added to the msgdef at that time. If the oneof is already part of a
|
||||
// msgdef, the field must either be a part of that msgdef already, or must not
|
||||
// be a part of any msgdef; in the latter case, the field is added to the
|
||||
// msgdef as a part of this operation.
|
||||
//
|
||||
// The field may only have an OPTIONAL label, never REQUIRED or REPEATED.
|
||||
//
|
||||
// If |f| is already part of this MessageDef, this method performs no action
|
||||
// and returns true (success). Thus, this method is idempotent.
|
||||
bool AddField(FieldDef* field, Status* s);
|
||||
bool AddField(const reffed_ptr<FieldDef>& field, Status* s);
|
||||
|
||||
// Looks up by name.
|
||||
const FieldDef* FindFieldByName(const char* name, size_t len) const;
|
||||
FieldDef* FindFieldByName(const char* name, size_t len);
|
||||
const FieldDef* FindFieldByName(const char* name) const {
|
||||
return FindFieldByName(name, strlen(name));
|
||||
}
|
||||
FieldDef* FindFieldByName(const char* name) {
|
||||
return FindFieldByName(name, strlen(name));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
FieldDef* FindFieldByName(const T& str) {
|
||||
return FindFieldByName(str.c_str(), str.size());
|
||||
}
|
||||
template <class T>
|
||||
const FieldDef* FindFieldByName(const T& str) const {
|
||||
return FindFieldByName(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
// Looks up by tag number.
|
||||
const FieldDef* FindFieldByNumber(uint32_t num) const;
|
||||
|
||||
// Returns a new OneofDef with all the same fields. The OneofDef will be owned
|
||||
// by the given owner.
|
||||
OneofDef* Dup(const void* owner) const;
|
||||
|
||||
// Iteration over fields. The order is undefined.
|
||||
class iterator : public std::iterator<std::forward_iterator_tag, FieldDef*> {
|
||||
public:
|
||||
explicit iterator(OneofDef* md);
|
||||
static iterator end(OneofDef* md);
|
||||
|
||||
void operator++();
|
||||
FieldDef* operator*() const;
|
||||
bool operator!=(const iterator& other) const;
|
||||
bool operator==(const iterator& other) const;
|
||||
|
||||
private:
|
||||
upb_oneof_iter iter_;
|
||||
};
|
||||
|
||||
class const_iterator
|
||||
: public std::iterator<std::forward_iterator_tag, const FieldDef*> {
|
||||
public:
|
||||
explicit const_iterator(const OneofDef* md);
|
||||
static const_iterator end(const OneofDef* md);
|
||||
|
||||
void operator++();
|
||||
const FieldDef* operator*() const;
|
||||
bool operator!=(const const_iterator& other) const;
|
||||
bool operator==(const const_iterator& other) const;
|
||||
|
||||
private:
|
||||
upb_oneof_iter iter_;
|
||||
};
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
|
||||
private:
|
||||
UPB_DISALLOW_POD_OPS(OneofDef, upb::OneofDef);
|
||||
),
|
||||
UPB_DEFINE_STRUCT(upb_oneofdef, upb_def,
|
||||
upb_strtable ntof;
|
||||
upb_inttable itof;
|
||||
const upb_msgdef *parent;
|
||||
));
|
||||
|
||||
#define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \
|
||||
{ UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntof, itof }
|
||||
|
||||
UPB_BEGIN_EXTERN_C // {
|
||||
|
||||
// Native C API.
|
||||
upb_oneofdef *upb_oneofdef_new(const void *owner);
|
||||
upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner);
|
||||
|
||||
// From upb_refcounted.
|
||||
void upb_oneofdef_unref(const upb_oneofdef *o, const void *owner);
|
||||
bool upb_oneofdef_isfrozen(const upb_oneofdef *e);
|
||||
void upb_oneofdef_ref(const upb_oneofdef *o, const void *owner);
|
||||
void upb_oneofdef_donateref(const upb_oneofdef *m, const void *from,
|
||||
const void *to);
|
||||
void upb_oneofdef_checkref(const upb_oneofdef *o, const void *owner);
|
||||
|
||||
const char *upb_oneofdef_name(const upb_oneofdef *o);
|
||||
bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s);
|
||||
|
||||
const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o);
|
||||
int upb_oneofdef_numfields(const upb_oneofdef *o);
|
||||
bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
|
||||
const void *ref_donor,
|
||||
upb_status *s);
|
||||
|
||||
// Oneof lookups:
|
||||
// - ntof: look up a field by name.
|
||||
// - ntofz: look up a field by name (as a null-terminated string).
|
||||
// - itof: look up a field by number.
|
||||
const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
|
||||
const char *name, size_t length);
|
||||
UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o,
|
||||
const char *name) {
|
||||
return upb_oneofdef_ntof(o, name, strlen(name));
|
||||
}
|
||||
const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num);
|
||||
|
||||
// upb_oneof_iter i;
|
||||
// for(upb_oneof_begin(&i, e); !upb_oneof_done(&i); upb_oneof_next(&i)) {
|
||||
// // ...
|
||||
// }
|
||||
void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o);
|
||||
void upb_oneof_next(upb_oneof_iter *iter);
|
||||
bool upb_oneof_done(upb_oneof_iter *iter);
|
||||
upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter);
|
||||
void upb_oneof_iter_setdone(upb_oneof_iter *iter);
|
||||
|
||||
UPB_END_EXTERN_C // }
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
@ -2201,6 +2538,9 @@ inline void FieldDef::set_packed(bool packed) {
|
|||
inline const MessageDef* FieldDef::containing_type() const {
|
||||
return upb_fielddef_containingtype(this);
|
||||
}
|
||||
inline const OneofDef* FieldDef::containing_oneof() const {
|
||||
return upb_fielddef_containingoneof(this);
|
||||
}
|
||||
inline const char* FieldDef::containing_type_name() {
|
||||
return upb_fielddef_containingtypename(this);
|
||||
}
|
||||
|
@ -2351,12 +2691,21 @@ inline bool MessageDef::Freeze(Status* status) {
|
|||
inline int MessageDef::field_count() const {
|
||||
return upb_msgdef_numfields(this);
|
||||
}
|
||||
inline int MessageDef::oneof_count() const {
|
||||
return upb_msgdef_numoneofs(this);
|
||||
}
|
||||
inline bool MessageDef::AddField(upb_fielddef* f, Status* s) {
|
||||
return upb_msgdef_addfield(this, f, NULL, s);
|
||||
}
|
||||
inline bool MessageDef::AddField(const reffed_ptr<FieldDef>& f, Status* s) {
|
||||
return upb_msgdef_addfield(this, f.get(), NULL, s);
|
||||
}
|
||||
inline bool MessageDef::AddOneof(upb_oneofdef* o, Status* s) {
|
||||
return upb_msgdef_addoneof(this, o, NULL, s);
|
||||
}
|
||||
inline bool MessageDef::AddOneof(const reffed_ptr<OneofDef>& o, Status* s) {
|
||||
return upb_msgdef_addoneof(this, o.get(), NULL, s);
|
||||
}
|
||||
inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) {
|
||||
return upb_msgdef_itof_mutable(this, number);
|
||||
}
|
||||
|
@ -2370,6 +2719,13 @@ inline const FieldDef *MessageDef::FindFieldByName(const char *name,
|
|||
size_t len) const {
|
||||
return upb_msgdef_ntof(this, name, len);
|
||||
}
|
||||
inline OneofDef* MessageDef::FindOneofByName(const char* name, size_t len) {
|
||||
return upb_msgdef_ntoo_mutable(this, name, len);
|
||||
}
|
||||
inline const OneofDef* MessageDef::FindOneofByName(const char* name,
|
||||
size_t len) const {
|
||||
return upb_msgdef_ntoo(this, name, len);
|
||||
}
|
||||
inline MessageDef* MessageDef::Dup(const void *owner) const {
|
||||
return upb_msgdef_dup(this, owner);
|
||||
}
|
||||
|
@ -2379,55 +2735,127 @@ inline void MessageDef::setmapentry(bool map_entry) {
|
|||
inline bool MessageDef::mapentry() const {
|
||||
return upb_msgdef_mapentry(this);
|
||||
}
|
||||
inline MessageDef::iterator MessageDef::begin() { return iterator(this); }
|
||||
inline MessageDef::iterator MessageDef::end() { return iterator::end(this); }
|
||||
inline MessageDef::const_iterator MessageDef::begin() const {
|
||||
return const_iterator(this);
|
||||
inline MessageDef::field_iterator MessageDef::field_begin() {
|
||||
return field_iterator(this);
|
||||
}
|
||||
inline MessageDef::const_iterator MessageDef::end() const {
|
||||
return const_iterator::end(this);
|
||||
inline MessageDef::field_iterator MessageDef::field_end() {
|
||||
return field_iterator::end(this);
|
||||
}
|
||||
inline MessageDef::const_field_iterator MessageDef::field_begin() const {
|
||||
return const_field_iterator(this);
|
||||
}
|
||||
inline MessageDef::const_field_iterator MessageDef::field_end() const {
|
||||
return const_field_iterator::end(this);
|
||||
}
|
||||
|
||||
inline MessageDef::iterator::iterator(MessageDef* md) {
|
||||
upb_msg_begin(&iter_, md);
|
||||
inline MessageDef::oneof_iterator MessageDef::oneof_begin() {
|
||||
return oneof_iterator(this);
|
||||
}
|
||||
inline MessageDef::iterator MessageDef::iterator::end(MessageDef* md) {
|
||||
MessageDef::iterator iter(md);
|
||||
upb_msg_iter_setdone(&iter.iter_);
|
||||
inline MessageDef::oneof_iterator MessageDef::oneof_end() {
|
||||
return oneof_iterator::end(this);
|
||||
}
|
||||
inline MessageDef::const_oneof_iterator MessageDef::oneof_begin() const {
|
||||
return const_oneof_iterator(this);
|
||||
}
|
||||
inline MessageDef::const_oneof_iterator MessageDef::oneof_end() const {
|
||||
return const_oneof_iterator::end(this);
|
||||
}
|
||||
|
||||
inline MessageDef::field_iterator::field_iterator(MessageDef* md) {
|
||||
upb_msg_field_begin(&iter_, md);
|
||||
}
|
||||
inline MessageDef::field_iterator MessageDef::field_iterator::end(
|
||||
MessageDef* md) {
|
||||
MessageDef::field_iterator iter(md);
|
||||
upb_msg_field_iter_setdone(&iter.iter_);
|
||||
return iter;
|
||||
}
|
||||
inline FieldDef* MessageDef::iterator::operator*() const {
|
||||
inline FieldDef* MessageDef::field_iterator::operator*() const {
|
||||
return upb_msg_iter_field(&iter_);
|
||||
}
|
||||
inline void MessageDef::iterator::operator++() { return upb_msg_next(&iter_); }
|
||||
inline bool MessageDef::iterator::operator==(const iterator &other) const {
|
||||
inline void MessageDef::field_iterator::operator++() {
|
||||
return upb_msg_field_next(&iter_);
|
||||
}
|
||||
inline bool MessageDef::field_iterator::operator==(
|
||||
const field_iterator &other) const {
|
||||
return upb_inttable_iter_isequal(&iter_, &other.iter_);
|
||||
}
|
||||
inline bool MessageDef::iterator::operator!=(const iterator &other) const {
|
||||
inline bool MessageDef::field_iterator::operator!=(
|
||||
const field_iterator &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
inline MessageDef::const_iterator::const_iterator(const MessageDef* md) {
|
||||
upb_msg_begin(&iter_, md);
|
||||
inline MessageDef::const_field_iterator::const_field_iterator(
|
||||
const MessageDef* md) {
|
||||
upb_msg_field_begin(&iter_, md);
|
||||
}
|
||||
inline MessageDef::const_iterator MessageDef::const_iterator::end(
|
||||
inline MessageDef::const_field_iterator MessageDef::const_field_iterator::end(
|
||||
const MessageDef *md) {
|
||||
MessageDef::const_iterator iter(md);
|
||||
upb_msg_iter_setdone(&iter.iter_);
|
||||
MessageDef::const_field_iterator iter(md);
|
||||
upb_msg_field_iter_setdone(&iter.iter_);
|
||||
return iter;
|
||||
}
|
||||
inline const FieldDef* MessageDef::const_iterator::operator*() const {
|
||||
inline const FieldDef* MessageDef::const_field_iterator::operator*() const {
|
||||
return upb_msg_iter_field(&iter_);
|
||||
}
|
||||
inline void MessageDef::const_iterator::operator++() {
|
||||
return upb_msg_next(&iter_);
|
||||
inline void MessageDef::const_field_iterator::operator++() {
|
||||
return upb_msg_field_next(&iter_);
|
||||
}
|
||||
inline bool MessageDef::const_iterator::operator==(
|
||||
const const_iterator &other) const {
|
||||
inline bool MessageDef::const_field_iterator::operator==(
|
||||
const const_field_iterator &other) const {
|
||||
return upb_inttable_iter_isequal(&iter_, &other.iter_);
|
||||
}
|
||||
inline bool MessageDef::const_iterator::operator!=(
|
||||
const const_iterator &other) const {
|
||||
inline bool MessageDef::const_field_iterator::operator!=(
|
||||
const const_field_iterator &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
inline MessageDef::oneof_iterator::oneof_iterator(MessageDef* md) {
|
||||
upb_msg_oneof_begin(&iter_, md);
|
||||
}
|
||||
inline MessageDef::oneof_iterator MessageDef::oneof_iterator::end(
|
||||
MessageDef* md) {
|
||||
MessageDef::oneof_iterator iter(md);
|
||||
upb_msg_oneof_iter_setdone(&iter.iter_);
|
||||
return iter;
|
||||
}
|
||||
inline OneofDef* MessageDef::oneof_iterator::operator*() const {
|
||||
return upb_msg_iter_oneof(&iter_);
|
||||
}
|
||||
inline void MessageDef::oneof_iterator::operator++() {
|
||||
return upb_msg_oneof_next(&iter_);
|
||||
}
|
||||
inline bool MessageDef::oneof_iterator::operator==(
|
||||
const oneof_iterator &other) const {
|
||||
return upb_strtable_iter_isequal(&iter_, &other.iter_);
|
||||
}
|
||||
inline bool MessageDef::oneof_iterator::operator!=(
|
||||
const oneof_iterator &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
inline MessageDef::const_oneof_iterator::const_oneof_iterator(
|
||||
const MessageDef* md) {
|
||||
upb_msg_oneof_begin(&iter_, md);
|
||||
}
|
||||
inline MessageDef::const_oneof_iterator MessageDef::const_oneof_iterator::end(
|
||||
const MessageDef *md) {
|
||||
MessageDef::const_oneof_iterator iter(md);
|
||||
upb_msg_oneof_iter_setdone(&iter.iter_);
|
||||
return iter;
|
||||
}
|
||||
inline const OneofDef* MessageDef::const_oneof_iterator::operator*() const {
|
||||
return upb_msg_iter_oneof(&iter_);
|
||||
}
|
||||
inline void MessageDef::const_oneof_iterator::operator++() {
|
||||
return upb_msg_oneof_next(&iter_);
|
||||
}
|
||||
inline bool MessageDef::const_oneof_iterator::operator==(
|
||||
const const_oneof_iterator &other) const {
|
||||
return upb_strtable_iter_isequal(&iter_, &other.iter_);
|
||||
}
|
||||
inline bool MessageDef::const_oneof_iterator::operator!=(
|
||||
const const_oneof_iterator &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
@ -2495,6 +2923,105 @@ inline const char* EnumDef::Iterator::name() {
|
|||
}
|
||||
inline bool EnumDef::Iterator::Done() { return upb_enum_done(&iter_); }
|
||||
inline void EnumDef::Iterator::Next() { return upb_enum_next(&iter_); }
|
||||
|
||||
inline reffed_ptr<OneofDef> OneofDef::New() {
|
||||
upb_oneofdef *o = upb_oneofdef_new(&o);
|
||||
return reffed_ptr<OneofDef>(o, &o);
|
||||
}
|
||||
inline bool OneofDef::IsFrozen() const { return upb_oneofdef_isfrozen(this); }
|
||||
inline void OneofDef::Ref(const void* owner) const {
|
||||
return upb_oneofdef_ref(this, owner);
|
||||
}
|
||||
inline void OneofDef::Unref(const void* owner) const {
|
||||
return upb_oneofdef_unref(this, owner);
|
||||
}
|
||||
inline void OneofDef::DonateRef(const void* from, const void* to) const {
|
||||
return upb_oneofdef_donateref(this, from, to);
|
||||
}
|
||||
inline void OneofDef::CheckRef(const void* owner) const {
|
||||
return upb_oneofdef_checkref(this, owner);
|
||||
}
|
||||
inline const char* OneofDef::full_name() const {
|
||||
return upb_oneofdef_name(this);
|
||||
}
|
||||
|
||||
inline const MessageDef* OneofDef::containing_type() const {
|
||||
return upb_oneofdef_containingtype(this);
|
||||
}
|
||||
inline const char* OneofDef::name() const {
|
||||
return upb_oneofdef_name(this);
|
||||
}
|
||||
inline bool OneofDef::set_name(const char* name, Status* s) {
|
||||
return upb_oneofdef_setname(this, name, s);
|
||||
}
|
||||
inline int OneofDef::field_count() const {
|
||||
return upb_oneofdef_numfields(this);
|
||||
}
|
||||
inline bool OneofDef::AddField(FieldDef* field, Status* s) {
|
||||
return upb_oneofdef_addfield(this, field, NULL, s);
|
||||
}
|
||||
inline bool OneofDef::AddField(const reffed_ptr<FieldDef>& field, Status* s) {
|
||||
return upb_oneofdef_addfield(this, field.get(), NULL, s);
|
||||
}
|
||||
inline const FieldDef* OneofDef::FindFieldByName(const char* name,
|
||||
size_t len) const {
|
||||
return upb_oneofdef_ntof(this, name, len);
|
||||
}
|
||||
inline const FieldDef* OneofDef::FindFieldByNumber(uint32_t num) const {
|
||||
return upb_oneofdef_itof(this, num);
|
||||
}
|
||||
inline OneofDef::iterator OneofDef::begin() { return iterator(this); }
|
||||
inline OneofDef::iterator OneofDef::end() { return iterator::end(this); }
|
||||
inline OneofDef::const_iterator OneofDef::begin() const {
|
||||
return const_iterator(this);
|
||||
}
|
||||
inline OneofDef::const_iterator OneofDef::end() const {
|
||||
return const_iterator::end(this);
|
||||
}
|
||||
|
||||
inline OneofDef::iterator::iterator(OneofDef* o) {
|
||||
upb_oneof_begin(&iter_, o);
|
||||
}
|
||||
inline OneofDef::iterator OneofDef::iterator::end(OneofDef* o) {
|
||||
OneofDef::iterator iter(o);
|
||||
upb_oneof_iter_setdone(&iter.iter_);
|
||||
return iter;
|
||||
}
|
||||
inline FieldDef* OneofDef::iterator::operator*() const {
|
||||
return upb_oneof_iter_field(&iter_);
|
||||
}
|
||||
inline void OneofDef::iterator::operator++() { return upb_oneof_next(&iter_); }
|
||||
inline bool OneofDef::iterator::operator==(const iterator &other) const {
|
||||
return upb_inttable_iter_isequal(&iter_, &other.iter_);
|
||||
}
|
||||
inline bool OneofDef::iterator::operator!=(const iterator &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
inline OneofDef::const_iterator::const_iterator(const OneofDef* md) {
|
||||
upb_oneof_begin(&iter_, md);
|
||||
}
|
||||
inline OneofDef::const_iterator OneofDef::const_iterator::end(
|
||||
const OneofDef *md) {
|
||||
OneofDef::const_iterator iter(md);
|
||||
upb_oneof_iter_setdone(&iter.iter_);
|
||||
return iter;
|
||||
}
|
||||
inline const FieldDef* OneofDef::const_iterator::operator*() const {
|
||||
return upb_msg_iter_field(&iter_);
|
||||
}
|
||||
inline void OneofDef::const_iterator::operator++() {
|
||||
return upb_oneof_next(&iter_);
|
||||
}
|
||||
inline bool OneofDef::const_iterator::operator==(
|
||||
const const_iterator &other) const {
|
||||
return upb_inttable_iter_isequal(&iter_, &other.iter_);
|
||||
}
|
||||
inline bool OneofDef::const_iterator::operator!=(
|
||||
const const_iterator &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
} // namespace upb
|
||||
#endif
|
||||
|
||||
|
|
|
@ -73,6 +73,15 @@ module BasicTest
|
|||
optional :key, :string, 1
|
||||
optional :value, :message, 2, "TestMessage2"
|
||||
end
|
||||
|
||||
add_message "OneofMessage" do
|
||||
oneof :my_oneof do
|
||||
optional :a, :string, 1
|
||||
optional :b, :int32, 2
|
||||
optional :c, :message, 3, "TestMessage2"
|
||||
optional :d, :enum, 4, "TestEnum"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
TestMessage = pool.lookup("TestMessage").msgclass
|
||||
|
@ -87,6 +96,7 @@ module BasicTest
|
|||
pool.lookup("MapMessageWireEquiv_entry1").msgclass
|
||||
MapMessageWireEquiv_entry2 =
|
||||
pool.lookup("MapMessageWireEquiv_entry2").msgclass
|
||||
OneofMessage = pool.lookup("OneofMessage").msgclass
|
||||
|
||||
# ------------ test cases ---------------
|
||||
|
||||
|
@ -582,6 +592,80 @@ module BasicTest
|
|||
"b" => TestMessage2.new(:foo => 2)}
|
||||
end
|
||||
|
||||
def test_oneof_descriptors
|
||||
d = OneofMessage.descriptor
|
||||
o = d.lookup_oneof("my_oneof")
|
||||
assert o != nil
|
||||
assert o.class == Google::Protobuf::OneofDescriptor
|
||||
assert o.name == "my_oneof"
|
||||
assert d.oneofs == [o]
|
||||
assert o.count == 4
|
||||
field_names = o.map{|f| f.name}.sort
|
||||
assert field_names == ["a", "b", "c", "d"]
|
||||
end
|
||||
|
||||
def test_oneof
|
||||
d = OneofMessage.new
|
||||
assert d.a == nil
|
||||
assert d.b == nil
|
||||
assert d.c == nil
|
||||
assert d.d == nil
|
||||
|
||||
d.a = "hi"
|
||||
assert d.a == "hi"
|
||||
assert d.b == nil
|
||||
assert d.c == nil
|
||||
assert d.d == nil
|
||||
|
||||
d.b = 42
|
||||
assert d.a == nil
|
||||
assert d.b == 42
|
||||
assert d.c == nil
|
||||
assert d.d == nil
|
||||
|
||||
d.c = TestMessage2.new(:foo => 100)
|
||||
assert d.a == nil
|
||||
assert d.b == nil
|
||||
assert d.c.foo == 100
|
||||
assert d.d == nil
|
||||
|
||||
d.d = :C
|
||||
assert d.a == nil
|
||||
assert d.b == nil
|
||||
assert d.c == nil
|
||||
assert d.d == :C
|
||||
|
||||
d2 = OneofMessage.decode(OneofMessage.encode(d))
|
||||
assert d2 == d
|
||||
|
||||
encoded_field_a = OneofMessage.encode(OneofMessage.new(:a => "string"))
|
||||
encoded_field_b = OneofMessage.encode(OneofMessage.new(:b => 1000))
|
||||
encoded_field_c = OneofMessage.encode(
|
||||
OneofMessage.new(:c => TestMessage2.new(:foo => 1)))
|
||||
encoded_field_d = OneofMessage.encode(OneofMessage.new(:d => :B))
|
||||
|
||||
d3 = OneofMessage.decode(
|
||||
encoded_field_c + encoded_field_a + encoded_field_d)
|
||||
assert d3.a == nil
|
||||
assert d3.b == nil
|
||||
assert d3.c == nil
|
||||
assert d3.d == :B
|
||||
|
||||
d4 = OneofMessage.decode(
|
||||
encoded_field_c + encoded_field_a + encoded_field_d +
|
||||
encoded_field_c)
|
||||
assert d4.a == nil
|
||||
assert d4.b == nil
|
||||
assert d4.c.foo == 1
|
||||
assert d4.d == nil
|
||||
|
||||
d5 = OneofMessage.new(:a => "hello")
|
||||
assert d5.a != nil
|
||||
d5.a = nil
|
||||
assert d5.a == nil
|
||||
assert OneofMessage.encode(d5) == ''
|
||||
end
|
||||
|
||||
def test_enum_field
|
||||
m = TestMessage.new
|
||||
assert m.optional_enum == :Default
|
||||
|
@ -621,6 +705,14 @@ module BasicTest
|
|||
assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id
|
||||
end
|
||||
|
||||
def test_eq
|
||||
m = TestMessage.new(:optional_int32 => 42,
|
||||
:repeated_int32 => [1, 2, 3])
|
||||
m2 = TestMessage.new(:optional_int32 => 43,
|
||||
:repeated_int32 => [1, 2, 3])
|
||||
assert m != m2
|
||||
end
|
||||
|
||||
def test_enum_lookup
|
||||
assert TestEnum::A == 1
|
||||
assert TestEnum::B == 2
|
||||
|
|
Loading…
Add table
Reference in a new issue