Skip to content

Commit

Permalink
Fix void pointers. Previously Rice could not send a wrap C++ object b…
Browse files Browse the repository at this point in the history
…ack to C++ via a void method parameter.
  • Loading branch information
cfis committed Nov 16, 2024
1 parent b58d751 commit 439eb8d
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 0 deletions.
42 changes: 42 additions & 0 deletions rice/Data_Object.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -452,5 +452,47 @@ namespace Rice::detail
return Data_Object<T>(value);
}
};

template<>
class From_Ruby<void*>
{
public:
Convertible is_convertible(VALUE value)
{
switch (rb_type(value))
{
case RUBY_T_DATA:
// Hope for the best!
return Convertible::Exact;
break;
case RUBY_T_NIL:
return Convertible::Exact;
break;
default:
return Convertible::None;
}
}

void* convert(VALUE value)
{
switch (rb_type(value))
{
case RUBY_T_DATA:
{
// Since C++ is not telling us type information, we need to extract it
// from the Ruby object.
const rb_data_type_t* rb_type = RTYPEDDATA_TYPE(value);
return detail::unwrap<void>(value, (rb_data_type_t*)rb_type);
break;
}
case RUBY_T_NIL:
return nullptr;
break;
default:
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
detail::protect(rb_obj_classname, value), "pointer");
}
}
};
}
#endif // Rice__Data_Object__ipp_
63 changes: 63 additions & 0 deletions test/test_Data_Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,69 @@ TESTCASE(null_ptrs)
ASSERT_EQUAL(Qnil, result.value());
}

namespace
{
class Helper
{
public:

Helper(int value) : value_(value)
{
}

int value()
{
return this->value_;
}

private:
int value_;
};

class MyClass2
{
public:
Helper* passThrough(Helper* helper)
{
return helper;
}

Helper* passThrough(void* helper)
{
return static_cast<Helper*>(helper);
}
};
} // namespace

TESTCASE(pointers)
{
Class helperClass = define_class<Helper>("Helper")
.define_constructor(Constructor<Helper, int>())
.define_method("value", &Helper::value);

Class myClass = define_class<MyClass2>("MyClass")
.define_constructor(Constructor<MyClass>())
.define_method<Helper*(MyClass2::*)(Helper*)>("pass_through", &MyClass2::passThrough)
.define_method<Helper*(MyClass2::*)(void*)>("pass_through_void", &MyClass2::passThrough);

Object helper = helperClass.call("new", 5);
Object object = myClass.call("new");

Object result = object.call("pass_through", nullptr);
ASSERT_EQUAL(Qnil, result.value());

result = object.call("pass_through", helper);
Object value = result.call("value");
ASSERT_EQUAL(5, detail::From_Ruby<int>().convert(value));

result = object.call("pass_through_void", nullptr);
ASSERT_EQUAL(Qnil, result.value());

result = object.call("pass_through_void", helper);
value = result.call("value");
ASSERT_EQUAL(5, detail::From_Ruby<int>().convert(value));
}

namespace
{
class SomeClass
Expand Down

0 comments on commit 439eb8d

Please sign in to comment.