aboutsummaryrefslogtreecommitdiffhomepage
path: root/ruby/ext
diff options
context:
space:
mode:
authorGravatar Chris Fallin <cfallin@google.com>2015-01-13 18:14:39 -0800
committerGravatar Chris Fallin <cfallin@google.com>2015-01-14 14:35:57 -0800
commitfcd8889d5b68be6ca7d1df705ad2159777e2f379 (patch)
treebda288000f1088700a175bf9b04591d01b0f67f9 /ruby/ext
parent5446deaea7ffc29f6e09368cb6238da083969123 (diff)
Support oneofs in MRI Ruby C extension.
Diffstat (limited to 'ruby/ext')
-rw-r--r--ruby/ext/google/protobuf_c/defs.c303
-rw-r--r--ruby/ext/google/protobuf_c/encode_decode.c190
-rw-r--r--ruby/ext/google/protobuf_c/protobuf.c2
-rw-r--r--ruby/ext/google/protobuf_c/protobuf.h49
-rw-r--r--ruby/ext/google/protobuf_c/storage.c250
-rw-r--r--ruby/ext/google/protobuf_c/upb.c552
-rw-r--r--ruby/ext/google/protobuf_c/upb.h635
7 files changed, 1748 insertions, 233 deletions
diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c
index a18aaac4..371939ae 100644
--- a/ruby/ext/google/protobuf_c/defs.c
+++ b/ruby/ext/google/protobuf_c/defs.c
@@ -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.
@@ -379,6 +386,67 @@ VALUE Descriptor_add_field(VALUE _self, VALUE obj) {
/*
* 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
*
* Returns the Ruby class created for this message type. Valid only once the
@@ -744,6 +812,120 @@ VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
}
// -----------------------------------------------------------------------------
+// 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.");
diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c
index e5e1514b..26a038b6 100644
--- a/ruby/ext/google/protobuf_c/encode_decode.c
+++ b/ruby/ext/google/protobuf_c/encode_decode.c
@@ -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);
diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c
index 30552705..d2d35033 100644
--- a/ruby/ext/google/protobuf_c/protobuf.c
+++ b/ruby/ext/google/protobuf_c/protobuf.c
@@ -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);
diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h
index 88ae62e4..84f318b3 100644
--- a/ruby/ext/google/protobuf_c/protobuf.h
+++ b/ruby/ext/google/protobuf_c/protobuf.h
@@ -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;
};
diff --git a/ruby/ext/google/protobuf_c/storage.c b/ruby/ext/google/protobuf_c/storage.c
index 14f49d44..d526679a 100644
--- a/ruby/ext/google/protobuf_c/storage.c
+++ b/ruby/ext/google/protobuf_c/storage.c
@@ -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->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);
- layout->offsets[upb_fielddef_index(field)] = off;
+ // 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)];
-
- 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)) {
+ 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)];
-
- if (is_map_field(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 (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)];
-
- if (is_map_field(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 (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)];
-
- if (is_map_field(field)) {
- return Map_eq(DEREF(msg1_memory, VALUE),
- DEREF(msg2_memory, VALUE));
+ 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 (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);
diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c
index 571c809f..c223c568 100644
--- a/ruby/ext/google/protobuf_c/upb.c
+++ b/ruby/ext/google/protobuf_c/upb.c
@@ -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");
- 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");
+ if (!check_field_add(m, f, s)) {
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;
diff --git a/ruby/ext/google/protobuf_c/upb.h b/ruby/ext/google/protobuf_c/upb.h
index fbcb8e99..572f6ad1 100644
--- a/ruby/ext/google/protobuf_c/upb.h
+++ b/ruby/ext/google/protobuf_c/upb.h
@@ -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::oneof_iterator MessageDef::oneof_begin() {
+ return oneof_iterator(this);
+}
+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::iterator::iterator(MessageDef* md) {
- upb_msg_begin(&iter_, md);
+inline MessageDef::field_iterator::field_iterator(MessageDef* md) {
+ upb_msg_field_begin(&iter_, md);
}
-inline MessageDef::iterator MessageDef::iterator::end(MessageDef* md) {
- MessageDef::iterator iter(md);
- upb_msg_iter_setdone(&iter.iter_);
+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