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:
bool
i32
f64
(&str)
(&str
; macro limtation)(Vec<Value>)
(Vec<Value>
; macro limtation)(&T)
(defined withdef_class
; macro limtation)Value
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);