DEV Community

Rory O'Connell
Rory O'Connell

Posted on

Receiving Data types as arugments with mruby

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)
Enter fullscreen mode Exit fullscreen mode

Getting started with creating a VulkanState class is also typical

RClass *VulkanState_C = mrb_define_class(state, "VulkanState", state->object_class);
MRB_SET_INSTANCE_TT(VulkanState_C, MRB_TT_DATA);
mrb_define_method(state, VulkanState_C, "initialize",
                VulkanState_initialize, MRB_ARGS_REQ(1));
Enter fullscreen mode Exit fullscreen mode

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` |
Enter fullscreen mode Exit fullscreen mode

First try is a normal mrb_value

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

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));
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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 };

mrb_value
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);
MRB_SET_INSTANCE_TT(Foo, MRB_TT_DATA);
RClass *Bar = mrb_define_class(state, "Bar", state->object_class);
mrb_define_method(state, Bar, "get_foo", Bar_get_foo, MRB_ARGS_REQ(1));
Enter fullscreen mode Exit fullscreen mode

Top comments (0)