plugger_ruby/
lib.rs

1extern crate plugger_core;
2extern crate rurust;
3extern crate libc;
4
5pub use rurust::Value as Value;
6
7/// Shim functions which act as middlemen between C and Ruby.
8pub mod shims;
9
10// Must be public so that the plugger crate can use.
11#[doc(hidden)]
12pub use self::marshall::Marshall;
13
14mod marshall;
15
16/// The Ruby support code.
17const RUBY_SUPPORT: &'static str = include_str!("../support/ruby.rb");
18/// The base class all Ruby plugger objects derive from.
19const PLUGGER_BASE_CLASS: &'static str = "PluggerObject";
20
21use plugger_core::Pluggable;
22
23pub extern fn do_something() {
24    println!("do_something");
25}
26
27#[derive(Debug)]
28pub enum ErrorKind
29{
30    Ruby(rurust::ErrorKind),
31}
32
33pub struct Ruby
34{
35    pub vm: rurust::VM,
36}
37
38impl Ruby
39{
40    pub fn new() -> Result<Self, ErrorKind> {
41        match rurust::VM::new() {
42            Ok(vm) => {
43                let mut ruby = Ruby { vm: vm };
44                ruby.eval(RUBY_SUPPORT).expect("the support module crashed");
45
46                Ok(ruby)
47            }
48            Err(e) => return Err(ErrorKind::Ruby(e)),
49        }
50    }
51
52    pub fn plug<P>(&mut self, name: &str, object: &mut P) where P: Pluggable {
53        let base_class = self.vm.eval(PLUGGER_BASE_CLASS).expect("could not find the plugger base class");
54
55        let class_builder = object.methods().iter().fold(self.vm.class(object.name()).extend(base_class), |class, method| {
56            let ptr = method.marshall("ruby") as usize;
57            let ptr_value = self.vm.eval(&format!("{}", ptr)).unwrap();
58
59            let name = format!("{}_internal", method.name);
60
61            if method.is_static {
62                class.singleton_method(name, shims::ruby_singleton_method as *mut _, -1)
63            } else {
64                class.method(name, shims::ruby_method as *mut _, -1)
65            }.constant(method.name.to_uppercase(), ptr_value)
66        });
67
68        // class_builder = class_builder.constant("PLUGGED_METHODS", jkjk
69
70        class_builder.build();
71        let ptr = object as *mut _ as usize;
72
73        let constant_name = name.to_uppercase();
74
75        let ruby_val = self.vm.eval(&format!("{}.new({})", object.name(), ptr)).unwrap();
76        self.vm.set_global_const(&constant_name, ruby_val);
77
78        println!("Plugging in {} {}", object.name(), constant_name);
79    }
80
81    pub fn eval(&mut self, code: &str) -> Result<String, ErrorKind> {
82        match self.vm.eval(code) {
83            Ok(val) => Ok(val.inspect_string()),
84            Err(e) => Err(ErrorKind::Ruby(e)),
85        }
86    }
87}
88