[−][src]Crate mruby
mruby
mruby crate provides a safe interface over the raw mruby bindings in
mruby-sys. mruby crate aims to expose as much of the mruby API
as possible.
Execute Ruby Code
mruby crate exposes several mechanisms for executing Ruby code on the interpreter.
Evaling Source Code
mruby crate exposes eval on the mrb_state with the MrbEval
trait. Side effects from eval are persisted across invocations.
use mruby::eval::MrbEval; let interp = mruby::interpreter().unwrap(); let result = interp.eval("10 * 10").unwrap(); let result = result.try_into::<i64>(); assert_eq!(result, Ok(100));
Calling Ruby Functions from Rust
The ValueLike trait exposes a funcall interface which
can call Ruby functions on a Value using a String
function name and a Vec<Value> or arguments. funcall takes a type parameter
bound by TryFromMrb and converts the result of the function call to a Rust
type (which may be Value or another "native" type).
mruby limits functions to a maximum of 16 arguments.
Virtual Filesystem and Kernel#require
The mruby State embeds an
in-memory virtual Unix filesystem. The VFS stores Ruby sources
that are either pure Ruby, implemented with a Rust MrbFile, or
both.
mruby crate implements
Kernel#require and Kernel#require_relative which
loads sources from the VFS. For Ruby sources, the source is loaded from the VFS
as a Vec<u8> and evaled with MrbEval::eval_with_context. For
Rust sources, MrbFile::require methods are stored as custom
metadata on File nodes in the VFS.
use mruby::eval::MrbEval; use mruby::load::MrbLoadSources; let mut interp = mruby::interpreter().unwrap(); let code = " def source_location __FILE__ end "; interp.def_rb_source_file("source.rb", code).unwrap(); interp.eval("require 'source'").unwrap(); let result = interp.eval("source_location").unwrap(); let result = result.try_into::<String>().unwrap(); assert_eq!(&result, "/src/lib/source.rb");
Embed Rust Objects in mrb_value
The mrb_value struct is a data type that represents a Ruby object. The
concrete type of an mrb_value is specified by its type tag, an mrb_vtype
enum value.
One mrb_vtype is MRB_TT_DATA, which allows an mrb_value to store an owned
c_void pointer. mruby crate leverages this to store an owned copy of an
Rc<RefCell<T>> for any T that implements RustBackedValue.
RustBackedValue provides two methods for working with
MRB_TT_DATA:
- RustBackedValue::try_into_rubyconsumes- selfand returns a live- mrb_valuethat wraps- T.
- RustBackedValue::try_from_rubyextracts an- Rc<RefCell<T>>from an- mrb_valueand manages the strong count of the- Rcsmart pointer to ensure that the- mrb_valuecontinues to point to valid memory.
These mrb_values with type tag MRB_TT_DATA can be used to implement Ruby
Classes and Modules with Rust structs. An example of this is the
Regexp class which wraps an Oniguruma regex
provided by the [onig] crate.
#[macro_use] extern crate mruby; use mruby::convert::{FromMrb, RustBackedValue, TryFromMrb}; use mruby::def::{rust_data_free, ClassLike, Define}; use mruby::eval::MrbEval; use mruby::file::MrbFile; use mruby::load::MrbLoadSources; use mruby::sys; use mruby::value::Value; use mruby::{Mrb, MrbError}; use std::io::Write; use std::mem; struct Container { inner: i64 } impl Container { unsafe extern "C" fn initialize(mrb: *mut sys::mrb_state, mut slf: sys::mrb_value) -> sys::mrb_value { let interp = unwrap_interpreter!(mrb); let api = interp.borrow(); let int = mem::uninitialized::<sys::mrb_int>(); let mut argspec = vec![]; argspec.write_all(format!("{}\0", sys::specifiers::INTEGER).as_bytes()).unwrap(); sys::mrb_get_args(mrb, argspec.as_ptr() as *const i8, &int); let cont = Self { inner: int }; cont .try_into_ruby(&interp, Some(slf)) .unwrap_or_else(|_| Value::from_mrb(&interp, None::<Value>)) .inner() } unsafe extern "C" fn value(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value { let interp = unwrap_interpreter!(mrb); if let Ok(cont) = Self::try_from_ruby(&interp, &Value::new(&interp, slf)) { let borrow = cont.borrow(); Value::from_mrb(&interp, borrow.inner).inner() } else { Value::from_mrb(&interp, None::<Value>).inner() } } } impl RustBackedValue for Container {} impl MrbFile for Container { fn require(interp: Mrb) -> Result<(), MrbError> { let spec = interp.borrow_mut().def_class::<Self>("Container", None, Some(rust_data_free::<Self>)); spec.borrow_mut().add_method("initialize", Self::initialize, sys::mrb_args_req(1)); spec.borrow_mut().add_method("value", Self::value, sys::mrb_args_none()); spec.borrow_mut().mrb_value_is_rust_backed(true); spec.borrow().define(&interp)?; Ok(()) } } fn main() { let interp = mruby::interpreter().unwrap(); interp.def_file_for_type::<_, Container>("container.rb").unwrap(); interp.eval("require 'container'").unwrap(); let result = interp.eval("Container.new(15).value * 24").unwrap(); assert_eq!(result.try_into::<i64>(), Ok(360)); }
Converters Between Ruby and Rust Types
The convert module provides implementations for conversions
between mrb_value Ruby types and native Rust types like i64 and
HashMap<String, Option<Vec<u8>>> using an Mrb interpreter.
There are two converter traits:
- FromMrbprovides infallible conversions that return- Self. Converting from a Rust native type to a Ruby- mrb_valueis usually an infallible conversion.
- TryFromMrbprovides fallible conversions that return- Result<Self, Error>. Converting from a Ruby- mrb_valueto a Rust native type is always an fallible conversion because an- mrb_valuemay be any type tag.
Supported conversions:
- Ruby primitive types to Rust types. Primitive Ruby types are TrueClass,FalseClass,String(both UTF-8 and binary),Fixnum(i64),Float(f64).
- Rust types to Ruby types. Supported Rust types are bool,Vec<u8>,&[u8], integer types that losslessly convert toi64(i64,i32,i16,i8,u32,u16,u8),f64,String,&str.
- Ruby nilable types to RustOption<T>.
- Rust Option<T>types to Rubynilor anmrb_valueconverted fromT.
- Ruby Arrayto RustVec<T>whereTcorresponds to a Ruby primitive type.
- Rust Vec<T>to RubyArraywhereTcorresponds to a Ruby primitive type.
- Ruby Hashto RustVec<(Key, Value)>orHashMap<Key, Value>whereKeyandValuecorrespond to Ruby primitive types.
- Rust Vec<(Key, Value)>orHashMap<Key, Value>to RubyHashwhereKeyandValuecorrespond to Ruby primitive types.
- Identity conversion from ValuetoValue, which is useful when working with collection types.
The infallible converters are safe Rust functions. The fallibile converters are
unsafe Rust functions.
Re-exports
| pub use mruby_sys as sys; | 
Modules
| class | |
| convert | |
| def | |
| eval | |
| exception | |
| extn | |
| ffi | Functions for interacting directly with  | 
| file | |
| fs | 
 | 
| gc | |
| load | |
| method | |
| module | |
| state | |
| top_self | |
| value | |
| warn | 
Macros
| unwrap_interpreter | Extract an  | 
Enums
| MrbError | Errors returned by mruby crate. | 
Functions
| interpreter | Create and initialize an  | 
Type Definitions
| Mrb | Interpreter instance. |