rb_iv_get and rb_iv_set VS. Data_Wrap_Struct for creating custom classes
rb_iv_get
and rb_iv_set
VS. Data_Wrap_Struct
for custom calsses
So, reading the Ruby Exten开发者_JS百科sion API I found Data_Wrap_Struct
which converts a pointer into a Ruby object (right?). However, when I tried using is I kept getting random errors and whatnot, so I kind of though of switching to something like:
void Init_custom() {
//cCustom declared as VALUE higher in the code
cCustom = rb_define_class("Custom", T_OBJECT);
rb_define_method(mTester, "initialize", init_Custom, 1);
rb_define_method(mTester, "someValue", someValue_get_Custom, 0);
rb_define_method(mTester, "someValue=", someValue_set_Custom, 1);
//And so on.
}
Secondly the someValue_get_Custom
and someValue_set_Custom
would be:
VALUE someValue_get_Custom(VALUE self) {
return rb_iv_get(self, "@someValue")
}
VALUE someValue_set_Custom(VALUE self, VALUE val) {
return rb_iv_set(self, "@someValue", val) //or do I have to do return val;?
}
Another option would be to create a C version of attr_accessor
which would make the code slightly shorter and DRYer, but it would still be a part of plan B (using rb_iv_
set
/get
).
Now, I would really love to figure out how to use Data_Wrap_Struct
, since I have a suspicion it might be faster than using rb_iv_set
and rb_iv_get
, but if it's not what I think it is, then I'll have to resort to plan B.
So, I guess the real question is:
What exactly does Data_Wrap_Struct
do and how to properly use it or just
use it without erroring.
Oh, and I almost forgot, a few more questions related to Data_Wrap_Struct
:
What exactly does the mark parameter (a function) do? It says to set the mark parameter to 0 if the object isn't referenced anywhere, but what if it is referenced somewhere (a RArray maybe)?
Secondly, would the free parameter (also a function) be a simple function that frees the allocated memory for that object?
And is anything passed to those two functions by the Garbage Collector, maybe a VALUE self
?
Thanks!
Those are a lot of questions, I'll try to answer those that I can answer in a few sentences.
Think of Data_Wrap_Struct
as a thin Ruby wrapper that is visible in Ruby as a "normal" object, but actually carries a reference to a C struct (could be anything in theory but just makes sense really for complex types) under its hood. The idea is that this way you can attach a struct to a Ruby object and at any time have access to the struct data whenever Ruby requests it by sending messages to that wrapper object. In C you then retrieve the data from the struct, transform it into something rubyish and pass it back. Or you do the opposite when you are requested to set data in the wrapper object - you transform Ruby data into data that is appropriate for the struct.
When the garbage collector decides to collect the wrapper object it also wants to free the underlying C struct - this is the job of the free
argument, it's a function pointer to a function that takes the struct type as an argument and ought to free that struct's memory.
The mark
parameter is a lot more complicated, I'd advise you to post this as a separate question. The good thing: most of the time you won't need it.
rb_iv_get
, rb_iv_set
, as well as rb_ivar_get
and rb_ivar_set
are for a totally different purpose. They set instance variables of your Ruby object and my guess is this was what you actually were looking for. The point here is that you get/set VALUE
s here, i.e. you are working with Ruby objects here instead of plain C types.
You don't have to write your C version of attr_accessor
, it's already there: rb_attr
.
To sum this up: Data_Wrap_Struct
wraps a container object over your C struct but other than that provides no functionality yet. You should use rb_attr
in your Init
method if you intend to have attr_accessor
functionality. Use rb_iv*
if you actually want to set or get instance variables explicitly.`
I agree that there is a lack of a definite resource on how to write C extensions for Ruby. There are a lot of blog posts, though. From my own experience, I would probably start with the Pickaxe PDF that Serabe mentioned in the comments and there is an actually pretty neat introduction in the Ruby sources (README.EXT). After that the best thing you can do is to look into the extensions in the ext
directory in the Ruby sources. Pick one you're familiar with or whose functionality you like and play with it. Always have the Ruby source code at hand. If you don't know what a particular function does, look its declaration up in the sources to get at least a feeling for what it does. You don't need to understand it all at first glance, but it generally gives you enough to move on with your task.
精彩评论