Skip to content

Commit

Permalink
Added RefCell to Rust types.
Browse files Browse the repository at this point in the history
  • Loading branch information
dragostis committed Apr 29, 2016
1 parent 6a5dc66 commit 1e01279
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 35 deletions.
20 changes: 19 additions & 1 deletion src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,10 @@
/// }));
///
/// let result = mruby.run("Container.new 1, 2, 3").unwrap();
/// let result = result.to_obj::<Cont>().unwrap();
/// let result = result.borrow();
///
/// assert_eq!(result.to_obj::<Cont>().unwrap().value, 3);
/// assert_eq!(result.value, 3);
/// # }
/// ```
#[macro_export]
Expand Down Expand Up @@ -240,10 +242,21 @@ macro_rules! mrfn {
( @slf $slf:ident, Value ) => ();
( @slf $slf:ident, (&$t:ty) ) => (let $slf = $slf.to_obj::<$t>().unwrap(););

// borrow
( @borrow $name:ident, (&str) ) => ();
( @borrow $name:ident, (&$t:ty) ) => (let $name = $name.borrow());
( @borrow $name:ident, $_t:tt ) => ();
( @borrow $name:ident : $t:tt ) => (mrfn!(@borrow $name, $t));
( @borrow $name:ident : $t:tt, $($names:ident : $ts:tt),+ ) => {
mrfn!(@borrow $name, $t);
mrfn!(@borrow $( $names : $ts ),*);
};

// mrfn
( |$mruby:ident, $slf:ident : $st:tt| $block:expr ) => {
|$mruby, $slf| {
mrfn!(@slf $slf, $st);
mrfn!(@borrow $slf, $st);

$block
}
Expand All @@ -255,6 +268,7 @@ macro_rules! mrfn {
use std::slice;

mrfn!(@slf $slf, $st);
mrfn!(@borrow $slf, $st);

unsafe {
let mrb = $mruby.borrow().mrb;
Expand Down Expand Up @@ -286,6 +300,7 @@ macro_rules! mrfn {

unsafe {
mrfn!(@slf $slf, $st);
mrfn!(@borrow $slf, $st);

mrfn!(@init $( $name : $t ),*);

Expand All @@ -294,6 +309,7 @@ macro_rules! mrfn {

mrfn!(@args mrb, sig, $( $name : $t ),*);
mrfn!(@conv $mruby, $( $name : $t ),*);
mrfn!(@borrow $( $name : $t ),*);

$block
}
Expand All @@ -312,13 +328,15 @@ macro_rules! mrfn {

unsafe {
mrfn!(@slf $slf, $st);
mrfn!(@borrow $slf, $st);

mrfn!(@init $( $name : $t ),*);

let sig = CString::new(concat!(mrfn!(@sig $( $t ),*), "*")).unwrap().as_ptr();

let $args = mrfn!(@args_rest $mruby, sig, $( $name : $t ),*);
mrfn!(@conv $mruby, $( $name : $t ),*);
mrfn!(@borrow $( $name : $t ),*);

$block
}
Expand Down
25 changes: 16 additions & 9 deletions src/mruby.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,8 +949,11 @@ pub trait MrubyImpl {
/// let none = mruby.option::<Cont>(None);
/// let some = mruby.option(Some(Cont { value: 3 }));
///
/// let some = some.to_obj::<Cont>().unwrap();
/// let some = some.borrow();
///
/// assert_eq!(none.call("nil?", vec![]).unwrap().to_bool().unwrap(), true);
/// assert_eq!(some.to_obj::<Cont>().unwrap().value, 3);
/// assert_eq!(some.value, 3);
/// ```
#[inline]
fn option<T: Any>(&self, obj: Option<T>) -> Value;
Expand Down Expand Up @@ -1023,7 +1026,7 @@ fn get_class_for<T: Any, F>(mruby: &MrubyType, name: &str, get: F) -> Class

extern "C" fn free<T>(_mrb: *const MrState, ptr: *const u8) {
unsafe {
mem::transmute::<*const u8, Rc<T>>(ptr);
mem::transmute::<*const u8, Rc<RefCell<T>>>(ptr);
}
}

Expand Down Expand Up @@ -1638,14 +1641,16 @@ impl Value {
/// }));
///
/// let result = mruby.run("Container.new 3").unwrap();
/// let result = result.to_obj::<Cont>().unwrap();
/// let result = result.borrow();
///
/// assert_eq!(result.to_obj::<Cont>().unwrap().value, 3);
/// assert_eq!(result.value, 3);
/// # }
/// ```
pub fn init<T: Any>(self, obj: T) -> Value {
unsafe {
let rc = Rc::new(obj);
let ptr = mem::transmute::<Rc<T>, *const u8>(rc);
let rc = Rc::new(RefCell::new(obj));
let ptr = mem::transmute::<Rc<RefCell<T>>, *const u8>(rc);

let borrow = self.mruby.borrow();

Expand Down Expand Up @@ -1970,11 +1975,12 @@ impl Value {
///
/// let value = mruby.obj(Cont { value: 3 });
/// let cont = value.to_obj::<Cont>().unwrap();
/// let cont = cont.borrow();
///
/// assert_eq!(cont.value, 3);
/// ```
#[inline]
pub fn to_obj<T: Any>(&self) -> Result<Rc<T>, MrubyError> {
pub fn to_obj<T: Any>(&self) -> Result<Rc<RefCell<T>>, MrubyError> {
unsafe {
let borrow = self.mruby.borrow();

Expand Down Expand Up @@ -2013,13 +2019,14 @@ impl Value {
/// mruby.def_class_for::<Cont>("Container");
///
/// let value = mruby.obj(Cont { value: 3 });
/// let cont = value.to_option::<Cont>().unwrap();
/// let cont = value.to_option::<Cont>().unwrap().unwrap();
/// let cont = cont.borrow();
///
/// assert_eq!(cont.unwrap().value, 3);
/// assert_eq!(cont.value, 3);
/// assert!(mruby.nil().to_option::<Cont>().unwrap().is_none());
/// ```
#[inline]
pub fn to_option<T: Any>(&self) -> Result<Option<Rc<T>>, MrubyError> {
pub fn to_option<T: Any>(&self) -> Result<Option<Rc<RefCell<T>>>, MrubyError> {
if self.value.typ == MrType::MRB_TT_DATA {
self.to_obj::<T>().map(|obj| Some(obj))
} else {
Expand Down
11 changes: 6 additions & 5 deletions src/mruby_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::any::Any;
use std::cell::RefCell;
use std::ffi::CStr;
use std::mem;
use std::os::raw::c_char;
Expand Down Expand Up @@ -74,8 +75,8 @@ impl MrValue {
#[inline]
pub unsafe fn obj<T: Any>(mrb: *const MrState, class: *const MrClass,
obj: T, typ: &MrDataType) -> MrValue {
let rc = Rc::new(obj);
let ptr = mem::transmute::<Rc<T>, *const u8>(rc);
let rc = Rc::new(RefCell::new(obj));
let ptr = mem::transmute::<Rc<RefCell<T>>, *const u8>(rc);
let data = mrb_data_object_alloc(mrb, class, ptr, typ as *const MrDataType);

mrb_ext_data_value(data)
Expand Down Expand Up @@ -140,19 +141,19 @@ impl MrValue {

#[inline]
pub unsafe fn to_obj<T: Any>(&self, mrb: *const MrState,
typ: &MrDataType) -> Result<Rc<T>, MrubyError> {
typ: &MrDataType) -> Result<Rc<RefCell<T>>, MrubyError> {
match self.typ {
MrType::MRB_TT_DATA => {
let ptr = mrb_data_get_ptr(mrb, *self, typ as *const MrDataType) as *const u8;
let rc = mem::transmute::<*const u8, Rc<T>>(ptr);
let rc = mem::transmute::<*const u8, Rc<RefCell<T>>>(ptr);

let result = Ok(rc.clone());

mem::forget(rc);

result
},
_ => Err(MrubyError::Cast("Data(Rust Rc)".to_owned()))
_ => Err(MrubyError::Cast("Data(Rust Rc<RefCell<T>>)".to_owned()))
}
}

Expand Down
26 changes: 16 additions & 10 deletions src/tests/mruby_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ fn string() {

#[test]
fn obj() {
use std::cell::RefCell;
use std::mem;
use std::rc::Rc;

Expand All @@ -656,16 +657,18 @@ fn obj() {

let obj = Cont { value: 3 };
let obj = MrValue::obj(mrb, cont_class, obj, &data_type);
let obj: Rc<Cont> = obj.to_obj(mrb, &data_type).unwrap();
let obj: Rc<RefCell<Cont>> = obj.to_obj(mrb, &data_type).unwrap();
let value = obj.borrow().value;

assert_eq!(obj.value, 3);
assert_eq!(value, 3);

mrb_close(mrb);
}
}

#[test]
fn obj_init() {
use std::cell::RefCell;
use std::mem;
use std::rc::Rc;

Expand All @@ -684,15 +687,15 @@ fn obj_init() {

extern "C" fn free(_mrb: *const MrState, ptr: *const u8) {
unsafe {
mem::transmute::<*const u8, Rc<Cont>>(ptr);
mem::transmute::<*const u8, Rc<RefCell<Cont>>>(ptr);
}
}

extern "C" fn init(mrb: *const MrState, slf: MrValue) -> MrValue {
unsafe {
let cont = Cont { value: 3 };
let rc = Rc::new(cont);
let ptr = mem::transmute::<Rc<Cont>, *const u8>(rc);
let rc = Rc::new(RefCell::new(cont));
let ptr = mem::transmute::<Rc<RefCell<Cont>>, *const u8>(rc);

let data_type = mem::transmute::<*const u8,
*const MrDataType>(mrb_ext_get_ud(mrb));
Expand All @@ -707,9 +710,10 @@ fn obj_init() {
unsafe {
let data_type = mem::transmute::<*const u8, &MrDataType>(mrb_ext_get_ud(mrb));

let cont = slf.to_obj::<Cont>(mrb, data_type);
let cont = slf.to_obj::<Cont>(mrb, data_type).unwrap();
let value = cont.borrow().value;

MrValue::fixnum(cont.unwrap().value)
MrValue::fixnum(value)
}
}

Expand All @@ -734,6 +738,7 @@ fn obj_init() {

#[test]
fn obj_scoping() {
use std::cell::RefCell;
use std::mem;
use std::rc::Rc;

Expand Down Expand Up @@ -761,7 +766,7 @@ fn obj_scoping() {

extern "C" fn free(_mrb: *const MrState, ptr: *const u8) {
unsafe {
mem::transmute::<*const u8, Rc<Cont>>(ptr);
mem::transmute::<*const u8, Rc<RefCell<Cont>>>(ptr);
}
}

Expand All @@ -772,9 +777,10 @@ fn obj_scoping() {

{
let obj = MrValue::obj(mrb, cont_class, orig, &data_type);
let obj: Rc<Cont> = obj.to_obj(mrb, &data_type).unwrap();
let obj: Rc<RefCell<Cont>> = obj.to_obj(mrb, &data_type).unwrap();
let value = obj.borrow().value;

assert_eq!(obj.value, 3);
assert_eq!(value, 3);

assert_eq!(DROPPED, false);
}
Expand Down
32 changes: 22 additions & 10 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ fn api_init() {
let scalar = mruby.run("Scalar.new 2.3").unwrap();
let vector = mruby.run("Vector.new 1.0, 2.0, 3.0").unwrap();

assert_eq!(*scalar.to_obj::<Scalar>().unwrap(), Scalar::new(2.3));
assert_eq!(*vector.to_obj::<Vector>().unwrap(), Vector::new(1.0, 2.0, 3.0));
let scalar = scalar.to_obj::<Scalar>().unwrap();
let vector = vector.to_obj::<Vector>().unwrap();

assert_eq!(*scalar.borrow(), Scalar::new(2.3));
assert_eq!(*vector.borrow(), Vector::new(1.0, 2.0, 3.0));
}

#[test]
Expand All @@ -40,11 +43,14 @@ fn api_getters() {
let scalar = mruby.run("Scalar.new 2.3").unwrap();
let vector = mruby.run("Vector.new 1.0, 2.0, 3.0").unwrap();

assert_eq!(scalar.to_obj::<Scalar>().unwrap().value, 2.3);
let scalar = scalar.to_obj::<Scalar>().unwrap();
let vector = vector.to_obj::<Vector>().unwrap();

assert_eq!(scalar.borrow().value, 2.3);

assert_eq!(vector.to_obj::<Vector>().unwrap().x, 1.0);
assert_eq!(vector.to_obj::<Vector>().unwrap().y, 2.0);
assert_eq!(vector.to_obj::<Vector>().unwrap().z, 3.0);
assert_eq!(vector.borrow().x, 1.0);
assert_eq!(vector.borrow().y, 2.0);
assert_eq!(vector.borrow().z, 3.0);
}

#[test]
Expand All @@ -55,8 +61,9 @@ fn api_mul() {
Vector::require(mruby.clone());

let vector = mruby.run("Scalar.new(2.0) * Vector.new(1.0, 2.0, 3.0)").unwrap();
let vector = vector.to_obj::<Vector>().unwrap();

assert_eq!(*vector.to_obj::<Vector>().unwrap(), Vector::new(2.0, 4.0, 6.0));
assert_eq!(*vector.borrow(), Vector::new(2.0, 4.0, 6.0));
}

#[test]
Expand All @@ -79,8 +86,9 @@ fn api_vec() {
Vector::require(mruby.clone());

let result = mruby.run("Vector.from_a [1.0, 2.0, 3.0]").unwrap();
let result = result.to_obj::<Vector>().unwrap();

assert_eq!(*result.to_obj::<Vector>().unwrap(), Vector::new(1.0, 2.0, 3.0));
assert_eq!(*result.borrow(), Vector::new(1.0, 2.0, 3.0));
}

#[test]
Expand All @@ -95,7 +103,9 @@ fn api_require() {
Vector.new(1.0, 2.0, 3.0)
").unwrap();

assert_eq!(*result.to_obj::<Vector>().unwrap(), Vector::new(1.0, 2.0, 3.0));
let result = result.to_obj::<Vector>().unwrap();

assert_eq!(*result.borrow(), Vector::new(1.0, 2.0, 3.0));
}

#[test]
Expand Down Expand Up @@ -144,6 +154,7 @@ fn api_dup() {
{
let obj = mruby.obj(orig);
let dup = obj.call("dup", vec![]).unwrap().to_obj::<Cont>().unwrap();
let dup = dup.borrow();

assert_eq!(dup.value, 3);

Expand All @@ -167,8 +178,9 @@ fn api_execute_binary() {
Scalar::require(mruby.clone());

let result = mruby.execute(Path::new("tests/compiled.mrb")).unwrap();
let result = result.to_obj::<Scalar>().unwrap();

assert_eq!(*result.to_obj::<Scalar>().unwrap(), Scalar::new(2.0));
assert_eq!(*result.borrow(), Scalar::new(2.0));
}

#[test]
Expand Down

0 comments on commit 1e01279

Please sign in to comment.