|
@@ -118,7 +118,8 @@ enum {
|
|
|
METHOD_GETTER = 1,
|
|
|
METHOD_SETTER = 2,
|
|
|
METHOD_CLEAR = 3,
|
|
|
- METHOD_PRESENCE = 4
|
|
|
+ METHOD_PRESENCE = 4,
|
|
|
+ METHOD_ENUM_GETTER = 5
|
|
|
};
|
|
|
|
|
|
static int extract_method_call(VALUE method_name, MessageHeader* self,
|
|
@@ -153,9 +154,34 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
|
|
|
accessor_type = METHOD_GETTER;
|
|
|
}
|
|
|
|
|
|
+ bool has_field = upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
|
|
|
+ &test_f, &test_o);
|
|
|
+
|
|
|
+ // Look for enum accessor of the form <enum_name>_const
|
|
|
+ if (!has_field && accessor_type == METHOD_GETTER &&
|
|
|
+ name_len > 6 && strncmp(name + name_len - 6, "_const", 6) == 0) {
|
|
|
+
|
|
|
+ // Find enum field name
|
|
|
+ char enum_name[name_len - 5];
|
|
|
+ strncpy(enum_name, name, name_len - 6);
|
|
|
+ enum_name[name_len - 4] = '\0';
|
|
|
+
|
|
|
+ // Check if enum field exists
|
|
|
+ const upb_oneofdef* test_o_enum;
|
|
|
+ const upb_fielddef* test_f_enum;
|
|
|
+ if (upb_msgdef_lookupname(self->descriptor->msgdef, enum_name, name_len - 6,
|
|
|
+ &test_f_enum, &test_o_enum) &&
|
|
|
+ upb_fielddef_type(test_f_enum) == UPB_TYPE_ENUM) {
|
|
|
+ // It does exist!
|
|
|
+ has_field = true;
|
|
|
+ accessor_type = METHOD_ENUM_GETTER;
|
|
|
+ test_o = test_o_enum;
|
|
|
+ test_f = test_f_enum;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// Verify the name corresponds to a oneof or field in this message.
|
|
|
- if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
|
|
|
- &test_f, &test_o)) {
|
|
|
+ if (!has_field) {
|
|
|
return METHOD_UNKNOWN;
|
|
|
}
|
|
|
|
|
@@ -231,13 +257,13 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
|
|
return oneof_field == NULL ? Qfalse : Qtrue;
|
|
|
} else if (accessor_type == METHOD_CLEAR) {
|
|
|
if (oneof_field != NULL) {
|
|
|
- layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
|
|
|
+ layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
|
|
|
}
|
|
|
return Qnil;
|
|
|
} else {
|
|
|
// METHOD_ACCESSOR
|
|
|
return oneof_field == NULL ? Qnil :
|
|
|
- ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
|
|
|
+ ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
|
|
|
}
|
|
|
// Otherwise we're operating on a single proto field
|
|
|
} else if (accessor_type == METHOD_SETTER) {
|
|
@@ -248,6 +274,25 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
|
|
return Qnil;
|
|
|
} else if (accessor_type == METHOD_PRESENCE) {
|
|
|
return layout_has(self->descriptor->layout, Message_data(self), f);
|
|
|
+ } else if (accessor_type == METHOD_ENUM_GETTER) {
|
|
|
+ VALUE enum_type = field_type_class(f);
|
|
|
+ VALUE method = rb_intern("const_get");
|
|
|
+ VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
|
|
|
+
|
|
|
+ // Map repeated fields to a new type with ints
|
|
|
+ if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
|
|
|
+ int array_size = FIX2INT(rb_funcall(raw_value, rb_intern("length"), 0));
|
|
|
+ VALUE array_args[1] = { ID2SYM(rb_intern("int64")) };
|
|
|
+ VALUE array = rb_class_new_instance(1, array_args, CLASS_OF(raw_value));
|
|
|
+ for (int i = 0; i < array_size; i++) {
|
|
|
+ VALUE entry = rb_funcall(enum_type, method, 1, rb_funcall(raw_value,
|
|
|
+ rb_intern("at"), 1, INT2NUM(i)));
|
|
|
+ rb_funcall(array, rb_intern("push"), 1, entry);
|
|
|
+ }
|
|
|
+ return array;
|
|
|
+ }
|
|
|
+ // Convert the value for singular fields
|
|
|
+ return rb_funcall(enum_type, method, 1, raw_value);
|
|
|
} else {
|
|
|
return layout_get(self->descriptor->layout, Message_data(self), f);
|
|
|
}
|