Receiving Data types as arugments with mruby

roryo profile image Rory O'Connell ・2 min read

It's funny when searching for examples on how to do something you end up getting results for posts you wrote a few days ago and not much else. I suppose that's a sign that I'm doing something bleeding edge and esoteric. Also props on dev.to for good SEO.

A quick hit for today, since apparently I not only accidentally started writing a book and accidentally started this mruby project, I also accidentally became the primary documenter for using mruby in practice. We learned how to create a Ruby class in C with mruby which stores arbitrary C data using the Data class type. What I want to do now is pass a Data instance as a parameter into another method. For example I'm pulling Win32 window management and Vulkan state into Ruby classes. Creating a VulkanState depends on a native window, in this case a Win32 window. The Ruby side is easy enough

@native_window = W32Window.new 'Foo', width: 1024, height: 768
@vulkan_state = VulkanState.new(@native_window)

Getting started with creating a VulkanState class is also typical

RClass *VulkanState_C = mrb_define_class(state, "VulkanState", state->object_class);
mrb_define_method(state, VulkanState_C, "initialize",
                VulkanState_initialize, MRB_ARGS_REQ(1));

It's extracting the Data type with mrb_get_args which had me stumped for a while as I could not figure out how to get the right data type out. The documentation for mrb_get_args states how to get a Data type argument

| `d`  | data           | void *, {mrb_data_type} const | 2nd argument will be used to check data type so it won't be modified; when `!` follows, the value may be `nil` |

First try is a normal mrb_value

VulkanState_initialize(mrb_state* state, mrb_value self) {
  mrb_value gui_window;
  mrb_get_args(state, "d", &gui_window, &W32Window_data_type);

Which creates some wild looking data pointers in gui_window

Next attempt is try pulling the data out with DATA_PTR from the mrb_value

W32Window* window = reinterpret_cast<W32Window *>(DATA_PTR(gui_window));

Still wild data

Digging into the code, mrb_get_args automatically pulls out and type casts the void * for us using mrb_data_get_ptr. Therefore pulling a Data type out doesn't require any extra work from our side.

W32Window_data* gui_window;
mrb_get_args(state, "d", &gui_window, &W32Window_data_type);

Now it's correct

That's all! A complete abstract example on receiving a Data type as a method argument

struct Foo_data {
  uint32_t baz;

static const Foo_data_type = { "Foo", mrb_free };

Bar_get_foo(mrb_state* state, mrb_value* self) {
  Foo_data *foo_data;
  mrb_get_args(state, "d", &foo_data, &Foo_data_type);
  return mrb_nil_value();

RClass *Foo = mrb_define_class(state, "Foo", state->object_class);
RClass *Bar = mrb_define_class(state, "Bar", state->object_class);
mrb_define_method(state, Bar, "get_foo", Bar_get_foo, MRB_ARGS_REQ(1));


Editor guide