ref: 395897779086894349c735f94625727adb4e9cfd rust-ruby-wrap-data/README.md -rw-r--r-- 2.0 KiB View raw
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# ruby-wrap-data

`ruby_wrap_data` is a module that provides a fairly low-level means of doing
what Ruby's `Data_Wrap_Struct` macro does. That is to say, you can store a
pointer to a Rust `Box<T>` inside a Ruby object and get it back out again.

Any heap-allocated struct, enum, or whatever should work.

### Example

```rust
extern crate ruby_sys;
extern crate ruby_wrap_data;

use ruby_sys::{
    class::{rb_class_new_instance, rb_define_class},
    rb_cObject,
    types::Value,
    value::RubySpecialConsts::{Nil},
    vm::ruby_init
};

use std::ffi::CString;
use std::mem;

const RB_NIL: Value = Value { value: Nil as usize };

struct MyValue {
    pub val: u16
}

fn alloc(klass: Value) -> Value {
    // build your data and put it on the heap
    let data = Box::new(MyValue { val: 1 });
    // call `wrap()`, passing your class and data
    ruby_wrap_data::wrap(klass, Some(data))
}

fn main() {
    // you may need to start the ruby vm
    unsafe { ruby_init() };

    // create a ruby class and attach your alloc function
    let name = CString::new("Thing").unwrap().into_raw();
    let klass = unsafe { rb_define_class(name, rb_cObject) };
    ruby_wrap_data::define_alloc_func(klass, alloc);

    // create a new instance of the class
    let thing = unsafe { rb_class_new_instance(0, &RB_NIL, klass) };

    // get the data out of the ruby object
    let data: Option<Box<MyValue>> = ruby_wrap_data::remove(thing);
    assert!(data.is_some());

    // if you try to remove it again, you get None
    let data: Option<Box<MyValue>> = ruby_wrap_data::remove(thing);
    assert!(data.is_none());

    // set new data on the object
    let new_data = Box::new(MyValue { val : 2 });
    ruby_wrap_data::set(thing, new_data);
}
```

### Testing

Assuming you're using rbenv (if not, sorry, you're on your own):

```bash
CONFIGURE_OPTS=--enable-shared rbenv install
RUBY=$(rbenv which ruby) cargo test
```

You may need to help Rust find the libruby.so file, like this:

```bash
export LD_LIBRARY_PATH=$HOME/.rbenv/versions/2.5.1/lib
RUBY=$(rbenv which ruby) cargo test
```

License: MIT