|
@@ -70,6 +70,36 @@ VALUE Message_alloc(VALUE klass) {
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
|
|
|
|
+ // If no fields in the oneof, always nil.
|
|
|
|
+ if (upb_oneofdef_numfields(o) == 0) {
|
|
|
|
+ return Qnil;
|
|
|
|
+ }
|
|
|
|
+ // Grab the first field in the oneof so we can get its layout info to find the
|
|
|
|
+ // oneof_case field.
|
|
|
|
+ upb_oneof_iter it;
|
|
|
|
+ upb_oneof_begin(&it, o);
|
|
|
|
+ assert(!upb_oneof_done(&it));
|
|
|
|
+ const upb_fielddef* first_field = upb_oneof_iter_field(&it);
|
|
|
|
+ assert(upb_fielddef_containingoneof(first_field) != NULL);
|
|
|
|
+
|
|
|
|
+ size_t case_ofs =
|
|
|
|
+ self->descriptor->layout->
|
|
|
|
+ fields[upb_fielddef_index(first_field)].case_offset;
|
|
|
|
+ uint32_t oneof_case = *((uint32_t*)(Message_data(self) + case_ofs));
|
|
|
|
+
|
|
|
|
+ // oneof_case == 0 indicates no field set.
|
|
|
|
+ if (oneof_case == 0) {
|
|
|
|
+ return Qnil;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // oneof_case is a field index, so find that field.
|
|
|
|
+ const upb_fielddef* f = upb_oneofdef_itof(o, oneof_case);
|
|
|
|
+ assert(f != NULL);
|
|
|
|
+
|
|
|
|
+ return ID2SYM(rb_intern(upb_fielddef_name(f)));
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* call-seq:
|
|
* call-seq:
|
|
* Message.method_missing(*args)
|
|
* Message.method_missing(*args)
|
|
@@ -82,6 +112,10 @@ VALUE Message_alloc(VALUE klass) {
|
|
*
|
|
*
|
|
* msg.foo = 42
|
|
* msg.foo = 42
|
|
* puts msg.foo
|
|
* puts msg.foo
|
|
|
|
+ *
|
|
|
|
+ * This method also provides read-only accessors for oneofs. If a oneof exists
|
|
|
|
+ * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
|
|
|
|
+ * the name of the field in that oneof that is currently set, or nil if none.
|
|
*/
|
|
*/
|
|
VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
|
VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
|
MessageHeader* self;
|
|
MessageHeader* self;
|
|
@@ -104,6 +138,17 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
|
name_len--;
|
|
name_len--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Check for a oneof name first.
|
|
|
|
+ const upb_oneofdef* o = upb_msgdef_ntoo(self->descriptor->msgdef,
|
|
|
|
+ name, name_len);
|
|
|
|
+ if (o != NULL) {
|
|
|
|
+ if (setter) {
|
|
|
|
+ rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
|
|
|
|
+ }
|
|
|
|
+ return which_oneof_field(self, o);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Otherwise, check for a field with that name.
|
|
const upb_fielddef* f = upb_msgdef_ntof(self->descriptor->msgdef,
|
|
const upb_fielddef* f = upb_msgdef_ntof(self->descriptor->msgdef,
|
|
name, name_len);
|
|
name, name_len);
|
|
|
|
|