Skip to content

Commit

Permalink
Update rb_check_typeddata to check inherited types
Browse files Browse the repository at this point in the history
  • Loading branch information
bjfish committed Jul 15, 2020
1 parent 1e29461 commit f460ce7
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 2 deletions.
15 changes: 15 additions & 0 deletions spec/ruby/optional/capi/ext/typed_data_spec.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,18 @@ VALUE sws_typed_change_struct(VALUE self, VALUE obj, VALUE new_val) {
return Qnil;
}

VALUE sws_typed_rb_check_typeddata_same_type(VALUE self, VALUE obj) {
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
}

VALUE sws_typed_rb_check_typeddata_same_type_parent(VALUE self, VALUE obj) {
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_parent_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
}

VALUE sws_typed_rb_check_typeddata_different_type(VALUE self, VALUE obj) {
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_other_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
}

void Init_typed_data_spec(void) {
VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject);
rb_define_alloc_func(cls, sdaf_alloc_typed_func);
Expand All @@ -160,6 +172,9 @@ void Init_typed_data_spec(void) {
rb_define_method(cls, "typed_get_struct_rdata", sws_typed_get_struct_rdata, 1);
rb_define_method(cls, "typed_get_struct_data_ptr", sws_typed_get_struct_data_ptr, 1);
rb_define_method(cls, "typed_change_struct", sws_typed_change_struct, 2);
rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1);
rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1);
rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1);
}

#ifdef __cplusplus
Expand Down
17 changes: 17 additions & 0 deletions spec/ruby/optional/capi/typed_data_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,21 @@
@s.typed_get_struct_data_ptr(a).should == 1024
end
end

describe "rb_check_typeddata" do
it "returns data pointer when the struct has the given type" do
a = @s.typed_wrap_struct(1024)
@s.rb_check_typeddata_same_type(a).should == true
end

it "returns data pointer when the parent struct has the given type" do
a = @s.typed_wrap_struct(1024)
@s.rb_check_typeddata_same_type_parent(a).should == true
end

it "raises an error for different types" do
a = @s.typed_wrap_struct(1024)
-> { @s.rb_check_typeddata_different_type(a) }.should raise_error(TypeError)
end
end
end
7 changes: 5 additions & 2 deletions src/main/c/cext/data.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ VALUE rb_data_typed_object_make(VALUE ruby_class, const rb_data_type_t *type, vo

void *rb_check_typeddata(VALUE value, const rb_data_type_t *data_type) {
struct RTypedData* typed_data = RTYPEDDATA(value);
if (typed_data->type != data_type) {
rb_raise(rb_eTypeError, "wrong argument type");
// NOTE: this function is used on every access to typed data so it should remain fast.
// RB_TYPE_P(value, T_DATA) is already checked by `RTYPEDDATA(value)`, see Truffle::CExt.RDATA().
// RTYPEDDATA_P(value) is already checked implicitly by `typed_data->type` which would return `nil` if not `RTYPEDDATA_P`.
if (!rb_typeddata_inherited_p(typed_data->type, data_type)) {
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected %s)", rb_obj_class(value), data_type->wrap_struct_name);
}
return typed_data->data;
}
Expand Down

0 comments on commit f460ce7

Please sign in to comment.