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
82
83
84
85
86
87
88
extern crate plugger_core;
extern crate rurust;
extern crate libc;
pub use rurust::Value as Value;
pub mod shims;
#[doc(hidden)]
pub use self::marshall::Marshall;
mod marshall;
const RUBY_SUPPORT: &'static str = include_str!("../support/ruby.rb");
const PLUGGER_BASE_CLASS: &'static str = "PluggerObject";
use plugger_core::Pluggable;
pub extern fn do_something() {
println!("do_something");
}
#[derive(Debug)]
pub enum ErrorKind
{
Ruby(rurust::ErrorKind),
}
pub struct Ruby
{
pub vm: rurust::VM,
}
impl Ruby
{
pub fn new() -> Result<Self, ErrorKind> {
match rurust::VM::new() {
Ok(vm) => {
let mut ruby = Ruby { vm: vm };
ruby.eval(RUBY_SUPPORT).expect("the support module crashed");
Ok(ruby)
}
Err(e) => return Err(ErrorKind::Ruby(e)),
}
}
pub fn plug<P>(&mut self, name: &str, object: &mut P) where P: Pluggable {
let base_class = self.vm.eval(PLUGGER_BASE_CLASS).expect("could not find the plugger base class");
let class_builder = object.methods().iter().fold(self.vm.class(object.name()).extend(base_class), |class, method| {
let ptr = method.marshall("ruby") as usize;
let ptr_value = self.vm.eval(&format!("{}", ptr)).unwrap();
let name = format!("{}_internal", method.name);
if method.is_static {
class.singleton_method(name, shims::ruby_singleton_method as *mut _, -1)
} else {
class.method(name, shims::ruby_method as *mut _, -1)
}.constant(method.name.to_uppercase(), ptr_value)
});
class_builder.build();
let ptr = object as *mut _ as usize;
let constant_name = name.to_uppercase();
let ruby_val = self.vm.eval(&format!("{}.new({})", object.name(), ptr)).unwrap();
self.vm.set_global_const(&constant_name, ruby_val);
println!("Plugging in {} {}", object.name(), constant_name);
}
pub fn eval(&mut self, code: &str) -> Result<String, ErrorKind> {
match self.vm.eval(code) {
Ok(val) => Ok(val.inspect_string()),
Err(e) => Err(ErrorKind::Ruby(e)),
}
}
}