mrusty::mrfn! [] [src]

macro_rules! mrfn {
    ( |$mruby:ident, $slf:ident : $st:tt| $block:expr ) => { ... };
    ( |$mruby:ident, $slf:ident : $st:tt; &$blk:ident| $block:expr ) => { ... };
    ( |$mruby:ident, $slf:ident : $st:tt; $args:ident| $block:expr ) => { ... };
    ( |$mruby:ident, $slf:ident : $st:tt; $args:ident, &$blk:ident| $block:expr ) => { ... };
    ( |$mruby:ident, $slf:ident : $st:tt, $( $name:ident : $t:tt ),*| $block:expr ) => { ... };
    ( |$mruby:ident, $slf:ident : $st:tt, $( $name:ident : $t:tt ),* ; &$blk:ident| $block:expr ) => { ... };
    ( |$mruby:ident, $slf:ident : $st:tt, $( $name:ident : $t:tt ),* ; $args:ident| $block:expr ) => { ... };
    ( |$mruby:ident, $slf:ident : $st:tt, $( $name:ident : $t:tt ),* ; $args:ident, &$blk:ident| $block:expr ) => { ... };
}

A macro useful for defining Rust closures for mruby.

Types can be:

Any panic! call within the closure will get rescued in a RustPanic mruby Exception.

Examples

mrfn! uses the usual Rust closure syntax. mruby does not need type information. slf can be either Value or T.

use mrusty::{Mruby, MrubyImpl};

let mruby = Mruby::new();

struct Cont;

mruby.def_class_for::<Cont>("Container");
// slf cannot be cast to Cont because it does not define initialize().
mruby.def_method_for::<Cont, _>("hi", mrfn!(|mruby, _slf: Value, a: i32, b: i32| {
    mruby.fixnum(a + b)
}));

let result = mruby.run("Container.new.hi 1, 2").unwrap();

assert_eq!(result.to_i32().unwrap(), 3);


mrfn! is also used for class method definitions.

use mrusty::{Mruby, MrubyImpl};

let mruby = Mruby::new();

struct Cont;

mruby.def_class_for::<Cont>("Container");
mruby.def_class_method_for::<Cont, _>("hi", mrfn!(|mruby, _slf: Value, a: (&str), b: (&str)| {
    mruby.string(&(a.to_owned() + b))
}));
// slf is a Value here. (mruby Class type)
mruby.def_class_method_for::<Cont, _>("class_name", mrfn!(|_mruby, slf: Value| {
    slf.call("to_s", vec![]).unwrap()
}));

let result = mruby.run("Container.hi 'a', 'b'").unwrap();
let name = mruby.run("Container.class_name").unwrap();

assert_eq!(result.to_str().unwrap(), "ab");
assert_eq!(name.to_str().unwrap(), "Container");


mrfn! does automatic casting on all mruby classes defined with def_class.

use mrusty::{Mruby, MrubyImpl};

let mruby = Mruby::new();

struct Cont {
    value: i32
};

mruby.def_class_for::<Cont>("Container");
mruby.def_method_for::<Cont, _>("gt", mrfn!(|mruby, slf: (&Cont), o: (&Cont)| {
    mruby.bool(slf.value > o.value)
}));

let a = mruby.obj::<Cont>(Cont { value: 3 });
let b = mruby.obj::<Cont>(Cont { value: 2 });

let result = a.call("gt", vec![b]).unwrap();

assert_eq!(result.to_bool().unwrap(), true);


Last, optional untyped argument will match all remaining arguments, as long as it's separated by a ;.

use mrusty::{Mruby, MrubyImpl};

let mruby = Mruby::new();

struct Cont {
    value: i32
};

mruby.def_class_for::<Cont>("Container");
mruby.def_method_for::<Cont, _>("initialize", mrfn!(|mruby, slf: Value; args| {
    let cont = Cont { value: args[0].to_i32().unwrap() + args[1].to_i32().unwrap() };

    slf.init(cont)
}));

let result = mruby.run("Container.new 1, 2, 3").unwrap();
let result = result.to_obj::<Cont>().unwrap();
let result = result.borrow();

assert_eq!(result.value, 3);


Also separated by a ; is an mruby block whose type is a Value.

use mrusty::{Mruby, MrubyImpl};

let mruby = Mruby::new();

struct Cont;

mruby.def_class_for::<Cont>("Container");
mruby.def_method_for::<Cont, _>("apply", mrfn!(|mruby, _slf: Value, a: Value; &block| {
    block.call("call", vec![a]).unwrap()
}));

let result = mruby.run("Container.new.apply(1) { |a| a + 2 }").unwrap();

assert_eq!(result.to_i32().unwrap(), 3);