This PR is a massive rewrite the wasmer-ruby language embedding. Here are some highlights.
rutie-derive and rutie-derive-macros
We are using rutie as the layer to integrate Rust inside Ruby. It's nice, but the “DSL” is verbose and limited. We have decided to write 2 new crates:
rutie-derive-macros, which provides the #[rubyclass], the #[rubymethods] and the #[rubyfunction] procedural macros,
rutie-derive, which provides some extra logic needed by rutie-derive-macros to upcast some types from Ruby to Rust seemlessly.
This is not really super documented for the moment, as it's all experimental. The crates don't aim to be reused by other projects for the moment. There is still sharp edge corners, but it fulfills our initial objective: Making the Rust code more readable and easier to maintain.
Here is a before/after example, illustrating how the rutie-derive* crates improve the code. The before:
struct Module {
inner: wasmer::Module,
}
rutie::wrappable_struct!(Module, ModuleWrapper, MODULE_WRAPPER);
rutie::class!(RubyModule);
impl rutie::VerifiedObject for RubyModule {
fn is_correct_type<T>(object: &T) -> bool
where T: rutie::Object
{
object.class() == rutie::Module::from_existing("Wasmer").get_nested_class("Module")
}
fn error_message() -> &'static str {
"Error converting to `RubyModule`"
}
}
rutie::methods!(
Module,
_itself,
fn ruby_module_new(store: …, bytes: rutie::RString) -> rutie::AnyObject {
unwrap_or_else(|| {
let store = store?.get_data(&*STORE_WRAPPER);
let bytes = bytes?
let module = wasmer::Module::new(store.inner(), bytes.to_str_unchecked());
let wasmer_module = rutie::Module::from_existing("Wasmer");
let ruby_module: AnyObject = wasmer_module
.get_nested_class("Module")
.wrap_data(module, &*MODULE_WRAPPER);
Ok(ruby_module)
})
}
);
This PR is a massive rewrite the
wasmer-ruby
language embedding. Here are some highlights.rutie-derive
andrutie-derive-macros
We are using
rutie
as the layer to integrate Rust inside Ruby. It's nice, but the “DSL” is verbose and limited. We have decided to write 2 new crates:rutie-derive-macros
, which provides the#[rubyclass]
, the#[rubymethods]
and the#[rubyfunction]
procedural macros,rutie-derive
, which provides some extra logic needed byrutie-derive-macros
to upcast some types from Ruby to Rust seemlessly.This is not really super documented for the moment, as it's all experimental. The crates don't aim to be reused by other projects for the moment. There is still sharp edge corners, but it fulfills our initial objective: Making the Rust code more readable and easier to maintain.
Here is a before/after example, illustrating how the
rutie-derive*
crates improve the code. The before:And the after:
#[rubymethods]
can have a receiver of type&self
or&mut self
,RubyResult
type,::ruby_new
method is declared to create a Ruby object of a Rust type,It's not perfect as I said, but it's a good start!
The
wasmer
crateBefore, we were only able to create an instance from the raw Wasm bytes, and fetch an exported function or an exported global, with a poor API.
Now, we have a complete new API based on the Wasmer “standard API” (the one we use in Rust, but also in Go, in Python etc.), which includes:
Store
, which holds the engine, the compiler etc.Module
, which represents a Wasm module, withvalidate
,new
,name=
,name
,exports
,imports
,custom_sections
,serialize
anddeserialize
,Instance
, which represents a Wasm instance, withnew
andexports
,Exports
, which represents a collection of exported entities, withrespond_to_missing?
,method_missing
, andlength
,ImportObject
, which represents a collection of imports that will be passed toInstance
, withnew
,contains_namespace
, andregister
,Function
, which represents an imported or exported function, withnew
,call
andtype
,Memory
, which represents an imported or exported memory, withnew
,type
,size
,data_size
,grow
, + memory views that extendsEnumerable
,Global
, which represents an imported or exported global, withnew
,mutable?
,value
,value=
, andtype
,Table
, which represents an imported or exported table, withnew
(small API for the moment),Type
,FunctionType
,MemoryType
,GlobalType
andTableType
,ExportType
andImportType
,Value
which represents a Wasm value,Wasi
module, which provides theVersion
,StateBuilder
andEnvironment
classes.This new API is much richer and complete than the previous one!
Left to do