wasmer 0.1.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cargo/config +1 -1
- data/.github/workflows/documentation.yml +50 -0
- data/.github/workflows/test.yml +73 -0
- data/.gitignore +3 -1
- data/CHANGELOG.md +225 -0
- data/Cargo.lock +747 -708
- data/Cargo.toml +7 -21
- data/Gemfile +2 -3
- data/LICENSE +21 -0
- data/README.md +1 -0
- data/Rakefile +4 -3
- data/bors.toml +6 -0
- data/crates/rutie-derive-macros/Cargo.toml +19 -0
- data/crates/rutie-derive-macros/README.md +4 -0
- data/crates/rutie-derive-macros/src/class.rs +156 -0
- data/crates/rutie-derive-macros/src/function.rs +178 -0
- data/crates/rutie-derive-macros/src/lib.rs +27 -0
- data/crates/rutie-derive-macros/src/methods.rs +282 -0
- data/crates/rutie-derive/Cargo.toml +14 -0
- data/crates/rutie-derive/README.md +97 -0
- data/crates/rutie-derive/src/lib.rs +4 -0
- data/crates/rutie-derive/src/upcast.rs +47 -0
- data/crates/rutie-test/Cargo.toml +10 -0
- data/crates/rutie-test/src/lib.rs +38 -0
- data/crates/wasmer/Cargo.toml +27 -0
- data/crates/wasmer/README.md +229 -0
- data/crates/wasmer/src/doc.rs +1512 -0
- data/crates/wasmer/src/error.rs +55 -0
- data/crates/wasmer/src/exports.rs +107 -0
- data/crates/wasmer/src/externals/function.rs +159 -0
- data/crates/wasmer/src/externals/global.rs +62 -0
- data/crates/wasmer/src/externals/memory.rs +117 -0
- data/crates/wasmer/src/externals/mod.rs +9 -0
- data/crates/wasmer/src/externals/table.rs +41 -0
- data/crates/wasmer/src/import_object.rs +78 -0
- data/crates/wasmer/src/instance.rs +45 -0
- data/crates/wasmer/src/lib.rs +307 -0
- data/crates/wasmer/src/memory/mod.rs +1 -0
- data/crates/wasmer/src/memory/views.rs +112 -0
- data/crates/wasmer/src/module.rs +106 -0
- data/crates/wasmer/src/prelude.rs +3 -0
- data/crates/wasmer/src/store.rs +22 -0
- data/crates/wasmer/src/types.rs +396 -0
- data/crates/wasmer/src/values.rs +84 -0
- data/crates/wasmer/src/wasi.rs +226 -0
- data/crates/wasmer/src/wat.rs +20 -0
- data/justfile +20 -2
- data/lib/wasmer.rb +29 -3
- data/wasmer.gemspec +8 -12
- metadata +53 -49
- data/.circleci/config.yml +0 -70
- data/README.md +0 -279
- data/lib/wasmer/version.rb +0 -3
- data/src/instance.rs +0 -282
- data/src/lib.rs +0 -98
- data/src/memory/mod.rs +0 -120
- data/src/memory/view.rs +0 -127
- data/src/module.rs +0 -28
@@ -0,0 +1,27 @@
|
|
1
|
+
mod class;
|
2
|
+
mod function;
|
3
|
+
mod methods;
|
4
|
+
|
5
|
+
#[proc_macro_attribute]
|
6
|
+
pub fn rubyclass(
|
7
|
+
attr: proc_macro::TokenStream,
|
8
|
+
input: proc_macro::TokenStream,
|
9
|
+
) -> proc_macro::TokenStream {
|
10
|
+
class::entry(attr, input)
|
11
|
+
}
|
12
|
+
|
13
|
+
#[proc_macro_attribute]
|
14
|
+
pub fn rubymethods(
|
15
|
+
attr: proc_macro::TokenStream,
|
16
|
+
input: proc_macro::TokenStream,
|
17
|
+
) -> proc_macro::TokenStream {
|
18
|
+
methods::entry(attr, input)
|
19
|
+
}
|
20
|
+
|
21
|
+
#[proc_macro_attribute]
|
22
|
+
pub fn rubyfunction(
|
23
|
+
attr: proc_macro::TokenStream,
|
24
|
+
input: proc_macro::TokenStream,
|
25
|
+
) -> proc_macro::TokenStream {
|
26
|
+
function::entry(attr, input)
|
27
|
+
}
|
@@ -0,0 +1,282 @@
|
|
1
|
+
use proc_macro2::{Group, Ident, Span, TokenStream, TokenTree};
|
2
|
+
use quote::{quote, ToTokens};
|
3
|
+
use syn::{punctuated::Punctuated, token::Colon2, *};
|
4
|
+
|
5
|
+
pub fn entry(
|
6
|
+
_attr: proc_macro::TokenStream,
|
7
|
+
input: proc_macro::TokenStream,
|
8
|
+
) -> proc_macro::TokenStream {
|
9
|
+
let impl_block = parse_macro_input!(input as ItemImpl);
|
10
|
+
|
11
|
+
let ty_name = match *impl_block.self_ty {
|
12
|
+
Type::Path(TypePath { qself: None, path }) if path.get_ident().is_some() => {
|
13
|
+
path.get_ident().unwrap().clone()
|
14
|
+
}
|
15
|
+
|
16
|
+
Type::Group(TypeGroup { elem, .. }) => match *elem {
|
17
|
+
Type::Path(TypePath { qself: None, path }) if path.get_ident().is_some() => {
|
18
|
+
path.get_ident().unwrap().clone()
|
19
|
+
}
|
20
|
+
_ => panic!("`impl` block must target a simple grouped identifier"),
|
21
|
+
},
|
22
|
+
|
23
|
+
_ => panic!("`impl` block must target a simple identifier, e.g. `impl T`"),
|
24
|
+
};
|
25
|
+
|
26
|
+
let ruby_rust_module_name = Ident::new(
|
27
|
+
&format!("ruby_{}", ty_name.to_string().to_lowercase()),
|
28
|
+
Span::call_site(),
|
29
|
+
);
|
30
|
+
let ruby_ty_name = Ident::new(&format!("Ruby{}", ty_name), ty_name.span());
|
31
|
+
|
32
|
+
let mut ruby_items = Vec::with_capacity(impl_block.items.len());
|
33
|
+
|
34
|
+
for item in impl_block.items {
|
35
|
+
match item {
|
36
|
+
ImplItem::Method(method) => {
|
37
|
+
if !method.attrs.is_empty() {
|
38
|
+
panic!("Methods in `impl` block do not support attributes for the moment");
|
39
|
+
}
|
40
|
+
|
41
|
+
let method_name = method.sig.ident.to_string();
|
42
|
+
|
43
|
+
if method.sig.constness.is_some() {
|
44
|
+
panic!("Method `{}` cannot be `const`", method_name);
|
45
|
+
}
|
46
|
+
|
47
|
+
if method.sig.asyncness.is_some() {
|
48
|
+
panic!("Method `{}` cannot be `async`", method_name);
|
49
|
+
}
|
50
|
+
|
51
|
+
if method.sig.unsafety.is_some() {
|
52
|
+
panic!("Method `{}` cannot be `unsafe`", method_name);
|
53
|
+
}
|
54
|
+
|
55
|
+
if method.sig.abi.is_some() {
|
56
|
+
panic!("Method `{}` cannot have a different ABI", method_name);
|
57
|
+
}
|
58
|
+
|
59
|
+
if !method.sig.generics.params.is_empty() {
|
60
|
+
panic!("Method `{}` cannot be generic", method_name);
|
61
|
+
}
|
62
|
+
|
63
|
+
if method.sig.variadic.is_some() {
|
64
|
+
panic!("Method `{}` cannot be variadic", method_name);
|
65
|
+
}
|
66
|
+
|
67
|
+
let ruby_method_name = &method.sig.ident;
|
68
|
+
let ruby_method_block = &method.block;
|
69
|
+
let ruby_method_visibility = &method.vis;
|
70
|
+
|
71
|
+
let mut need_self = false;
|
72
|
+
let mut need_mut_self = false;
|
73
|
+
|
74
|
+
let ruby_arguments_parsing = {
|
75
|
+
let (ruby_input_names, ruby_input_types): (
|
76
|
+
Vec<Ident>,
|
77
|
+
Vec<Punctuated<PathSegment, Colon2>>,
|
78
|
+
) = method
|
79
|
+
.sig
|
80
|
+
.inputs
|
81
|
+
.iter()
|
82
|
+
.filter_map(|input| match input {
|
83
|
+
FnArg::Receiver(Receiver { mutability, .. }) => {
|
84
|
+
need_self = true;
|
85
|
+
need_mut_self = mutability.is_some();
|
86
|
+
|
87
|
+
None
|
88
|
+
}
|
89
|
+
FnArg::Typed(PatType { pat, ty, .. }) => match (&**pat, &**ty) {
|
90
|
+
(
|
91
|
+
Pat::Ident(ident),
|
92
|
+
Type::Reference(TypeReference { elem, .. }),
|
93
|
+
) => match &**elem {
|
94
|
+
Type::Path(TypePath {
|
95
|
+
qself: None,
|
96
|
+
path: Path { segments: ty, .. },
|
97
|
+
}) => Some((ident.ident.clone(), ty.clone())),
|
98
|
+
_ => panic!(
|
99
|
+
"Typed input has an unsupported form (method `{}`)",
|
100
|
+
method_name
|
101
|
+
),
|
102
|
+
},
|
103
|
+
_ => panic!(
|
104
|
+
"Typed input has an unsupported form (method `{}`), it must be a reference type",
|
105
|
+
method_name
|
106
|
+
),
|
107
|
+
},
|
108
|
+
})
|
109
|
+
.unzip();
|
110
|
+
|
111
|
+
if ruby_input_names.is_empty() {
|
112
|
+
quote! {}
|
113
|
+
} else {
|
114
|
+
quote! {
|
115
|
+
let ( #( #ruby_input_names ),* ) =
|
116
|
+
{
|
117
|
+
let arguments = rutie::util::parse_arguments(argc, argv);
|
118
|
+
let mut argument_nth = 0;
|
119
|
+
|
120
|
+
(
|
121
|
+
#(
|
122
|
+
{
|
123
|
+
let argument = arguments
|
124
|
+
.get(argument_nth)
|
125
|
+
.ok_or_else(|| {
|
126
|
+
<rutie::AnyException as rutie::Exception>::new(
|
127
|
+
"ArgumentError",
|
128
|
+
Some(&format!(concat!("Argument #{} (`", stringify!( #ruby_input_types ), "`) of method `", stringify!( #ty_name ), ".", stringify!( #ruby_method_name ), "` is missing"), argument_nth)),
|
129
|
+
)
|
130
|
+
})
|
131
|
+
.and_then(|argument| {
|
132
|
+
<rutie::AnyObject as rutie::Object>
|
133
|
+
::try_convert_to::<< #ruby_input_types as rutie_derive::ClassInfo>::RubyClass>(argument)
|
134
|
+
})
|
135
|
+
.unwrap_or_else(|error| {
|
136
|
+
rutie::VM::raise_ex(error);
|
137
|
+
unreachable!()
|
138
|
+
});
|
139
|
+
|
140
|
+
argument_nth += 1;
|
141
|
+
|
142
|
+
argument
|
143
|
+
}
|
144
|
+
),*
|
145
|
+
)
|
146
|
+
};
|
147
|
+
|
148
|
+
let ( #( #ruby_input_names ),* ) =
|
149
|
+
(
|
150
|
+
#(
|
151
|
+
rutie_derive::UpcastRubyClass::<
|
152
|
+
<
|
153
|
+
< #ruby_input_types as rutie_derive::ClassInfo>::RubyClass as rutie_derive::ClassInfo
|
154
|
+
>::Class
|
155
|
+
>::upcast(&#ruby_input_names)
|
156
|
+
),*
|
157
|
+
);
|
158
|
+
}
|
159
|
+
}
|
160
|
+
};
|
161
|
+
|
162
|
+
let ruby_input_receiver = if need_mut_self {
|
163
|
+
quote! { mut _ruby_self: #ruby_ty_name }
|
164
|
+
} else {
|
165
|
+
quote! { _ruby_self: #ruby_ty_name }
|
166
|
+
};
|
167
|
+
|
168
|
+
let ruby_output = match method.sig.output {
|
169
|
+
ReturnType::Type(_, ty) => match *ty {
|
170
|
+
Type::Path(TypePath {
|
171
|
+
qself: None,
|
172
|
+
path: Path {
|
173
|
+
leading_colon: None,
|
174
|
+
segments,
|
175
|
+
}
|
176
|
+
}) if segments.first().unwrap().ident.to_string() == "RubyResult" => {
|
177
|
+
match &segments.first().unwrap().arguments {
|
178
|
+
PathArguments::AngleBracketed(AngleBracketedGenericArguments {
|
179
|
+
args,
|
180
|
+
..
|
181
|
+
}) => match args.first().unwrap() {
|
182
|
+
GenericArgument::Type(ty) => ty.clone(),
|
183
|
+
_ => panic!("Method has not well-formed rerturned type, expect `RubyResult<T>` where `T` is a type"),
|
184
|
+
},
|
185
|
+
_ => panic!("Method has not well-formed returned type, expect `RubyResult<T>`"),
|
186
|
+
}
|
187
|
+
}
|
188
|
+
_ => panic!("Method must wrap their output type inside `RubyResult<T>`"),
|
189
|
+
},
|
190
|
+
_ => panic!("Method must have an output of the form `RubyResult<T>`"),
|
191
|
+
};
|
192
|
+
|
193
|
+
let ruby_method_block = if need_self {
|
194
|
+
let slf_declaration = if need_mut_self {
|
195
|
+
quote! {
|
196
|
+
let _slf = _ruby_self.upcast_mut();
|
197
|
+
}
|
198
|
+
} else {
|
199
|
+
quote! {
|
200
|
+
let _slf = _ruby_self.upcast();
|
201
|
+
}
|
202
|
+
};
|
203
|
+
let block = rename_self(ruby_method_block.into_token_stream());
|
204
|
+
|
205
|
+
quote! {
|
206
|
+
#slf_declaration
|
207
|
+
|
208
|
+
#block
|
209
|
+
}
|
210
|
+
} else {
|
211
|
+
ruby_method_block.into_token_stream()
|
212
|
+
};
|
213
|
+
|
214
|
+
let ruby_block_visibility = if need_mut_self {
|
215
|
+
quote! { mut }
|
216
|
+
} else {
|
217
|
+
quote! {}
|
218
|
+
};
|
219
|
+
|
220
|
+
ruby_items.push(quote! {
|
221
|
+
#[allow(improper_ctypes_definitions)] // Not ideal but that's how Rutie works.
|
222
|
+
#ruby_method_visibility extern "C" fn #ruby_method_name(
|
223
|
+
argc: rutie::types::Argc,
|
224
|
+
argv: *const rutie::AnyObject,
|
225
|
+
#ruby_input_receiver,
|
226
|
+
) -> #ruby_output {
|
227
|
+
#ruby_arguments_parsing
|
228
|
+
|
229
|
+
let #ruby_block_visibility block = || -> Result<_, rutie::AnyException> {
|
230
|
+
#ruby_method_block
|
231
|
+
};
|
232
|
+
|
233
|
+
match block() {
|
234
|
+
Ok(x) => x,
|
235
|
+
Err(e) => {
|
236
|
+
rutie::VM::raise_ex(e);
|
237
|
+
unreachable!()
|
238
|
+
}
|
239
|
+
}
|
240
|
+
}
|
241
|
+
});
|
242
|
+
}
|
243
|
+
|
244
|
+
_ => panic!("`impl` block only supports methods for the moment"),
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
(quote! {
|
249
|
+
pub(crate) mod #ruby_rust_module_name {
|
250
|
+
use super::*;
|
251
|
+
|
252
|
+
#(#ruby_items)*
|
253
|
+
}
|
254
|
+
})
|
255
|
+
.into()
|
256
|
+
}
|
257
|
+
|
258
|
+
fn rename_self(stream: TokenStream) -> TokenStream {
|
259
|
+
let mut output_stream = TokenStream::new();
|
260
|
+
|
261
|
+
output_stream.extend(
|
262
|
+
stream
|
263
|
+
.into_iter()
|
264
|
+
.map(|token| match token {
|
265
|
+
TokenTree::Group(group) => {
|
266
|
+
TokenTree::Group(Group::new(group.delimiter(), rename_self(group.stream())))
|
267
|
+
}
|
268
|
+
TokenTree::Ident(ident) => {
|
269
|
+
if ident.to_string() == "self" {
|
270
|
+
TokenTree::Ident(Ident::new("_slf", ident.span()))
|
271
|
+
} else {
|
272
|
+
TokenTree::Ident(ident)
|
273
|
+
}
|
274
|
+
}
|
275
|
+
TokenTree::Punct(punct) => TokenTree::Punct(punct),
|
276
|
+
TokenTree::Literal(literal) => TokenTree::Literal(literal),
|
277
|
+
})
|
278
|
+
.collect::<Vec<TokenTree>>(),
|
279
|
+
);
|
280
|
+
|
281
|
+
output_stream
|
282
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
[package]
|
2
|
+
name = "rutie-derive"
|
3
|
+
version = "0.1.0"
|
4
|
+
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
5
|
+
edition = "2018"
|
6
|
+
description = "Provide useful types to complete the `rutie-derive-macros` crate"
|
7
|
+
readme = "README.md"
|
8
|
+
repository = "https://github.com/wasmerio/wasmer-ruby"
|
9
|
+
keywords = ["ruby", "extension"]
|
10
|
+
publish = false
|
11
|
+
|
12
|
+
[dependencies]
|
13
|
+
rutie = "0.8"
|
14
|
+
rutie-derive-macros = { path = "../rutie-derive-macros", version = "0.1.0" }
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# `rutie-derive`
|
2
|
+
|
3
|
+
**Note**: This is not an official project from
|
4
|
+
[`rutie`](https://github.com/danielpclark/rutie).
|
5
|
+
|
6
|
+
We try to extend `rutie` with a new Domain Specific Language (DSL for
|
7
|
+
short) based on new procedural macros to make it easier to declare
|
8
|
+
Ruby modules, classes, methods and functions.
|
9
|
+
|
10
|
+
This crate is the front API that provides the `#[ruby*]` procedural
|
11
|
+
macros from the `rutie-derive-macros` crate, along with some extra
|
12
|
+
traits and implementations to make everything work magically.
|
13
|
+
|
14
|
+
## Ruby class
|
15
|
+
|
16
|
+
To declare a new Ruby class, use `#[rubyclass(module = "X::Y::Z")]`:
|
17
|
+
|
18
|
+
```rust
|
19
|
+
#[rubyclass(module = "Wasmer")]
|
20
|
+
pub struct Foo;
|
21
|
+
```
|
22
|
+
|
23
|
+
It will create a new type `Foo` in Rust, and a new class `Foo` in Ruby
|
24
|
+
inside the `Wasmer` module.
|
25
|
+
|
26
|
+
### Constructor
|
27
|
+
|
28
|
+
Every class has a Rust `ruby_new` associated method to create a new
|
29
|
+
instance of this Ruby type.
|
30
|
+
|
31
|
+
## Ruby methods
|
32
|
+
|
33
|
+
To declare methods attached to a class, use `#[rubymethods]`:
|
34
|
+
|
35
|
+
```rust
|
36
|
+
#[rubymethods]
|
37
|
+
impl Foo {
|
38
|
+
/// Constructor.
|
39
|
+
pub fn new() -> RubyResult<Foo> {
|
40
|
+
Ok(Foo::ruby_new(Foo))
|
41
|
+
}
|
42
|
+
|
43
|
+
// Method.
|
44
|
+
pub fn bar(&self, x: &Integer, y: &Integer) -> RubyResult<Integer> {
|
45
|
+
Ok(Integer::new(x.to_i64() + x.to_i64()))
|
46
|
+
}
|
47
|
+
}
|
48
|
+
```
|
49
|
+
|
50
|
+
Ruby methods are like Rust methods:
|
51
|
+
|
52
|
+
* Without a receiver (`&self`), it's a static method (`def self`),
|
53
|
+
* With a receiver (`&self` or `&mut self`), it's a method (`def`),
|
54
|
+
* All arguments are received by reference,
|
55
|
+
* The returned type is required to be a `RubyResult`. The error type
|
56
|
+
is `AnyException`.
|
57
|
+
|
58
|
+
### “Rust-defined” Ruby types
|
59
|
+
|
60
|
+
Arguments can be of kind “user-defined types”, let's see:
|
61
|
+
|
62
|
+
```rust
|
63
|
+
#[rubyclass(module = "Wasmer")]
|
64
|
+
pub struct Baz {
|
65
|
+
inner: i32,
|
66
|
+
};
|
67
|
+
|
68
|
+
#[rubyclass(module = "Wasmer")]
|
69
|
+
pub struct Foo;
|
70
|
+
|
71
|
+
#[rubymethods]
|
72
|
+
impl Foo {
|
73
|
+
pub fn bar(&self, baz: &Baz) -> RubyResult<…> {
|
74
|
+
let inner = &baz.inner;
|
75
|
+
|
76
|
+
…
|
77
|
+
}
|
78
|
+
}
|
79
|
+
```
|
80
|
+
|
81
|
+
## Ruby functions
|
82
|
+
|
83
|
+
Just like `#[rubymethods]`, `#[rubyfunction]` will create a Ruby
|
84
|
+
function:
|
85
|
+
|
86
|
+
```rust
|
87
|
+
#[rubyfunction]
|
88
|
+
fn hello(who: &RString) -> RubyResult<RString> {
|
89
|
+
Ok(RString::new_utf8(&format!("Hello, {}!", who.to_str())))
|
90
|
+
}
|
91
|
+
```
|
92
|
+
|
93
|
+
## License
|
94
|
+
|
95
|
+
Check the license of
|
96
|
+
[`wasmer-ruby`](https://github.com/wasmerio/wasmer-ruby/) as it is
|
97
|
+
part of this same project.
|
@@ -0,0 +1,47 @@
|
|
1
|
+
pub trait ClassInfo {
|
2
|
+
type Class;
|
3
|
+
type RubyClass;
|
4
|
+
}
|
5
|
+
|
6
|
+
pub trait UpcastRubyClass<T> {
|
7
|
+
fn upcast(&self) -> &T;
|
8
|
+
|
9
|
+
fn upcast_mut(&mut self) -> &mut T;
|
10
|
+
}
|
11
|
+
|
12
|
+
macro_rules! id_impl {
|
13
|
+
($ty:ty) => {
|
14
|
+
impl ClassInfo for $ty {
|
15
|
+
type Class = Self;
|
16
|
+
type RubyClass = Self;
|
17
|
+
}
|
18
|
+
|
19
|
+
impl UpcastRubyClass<$ty> for $ty {
|
20
|
+
fn upcast(&self) -> &$ty {
|
21
|
+
self
|
22
|
+
}
|
23
|
+
|
24
|
+
fn upcast_mut(&mut self) -> &mut $ty {
|
25
|
+
self
|
26
|
+
}
|
27
|
+
}
|
28
|
+
};
|
29
|
+
|
30
|
+
( $( $ty:ty ),+ $(,)* ) => {
|
31
|
+
$( id_impl!( $ty ); )*
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
id_impl!(
|
36
|
+
rutie::AnyObject,
|
37
|
+
rutie::Array,
|
38
|
+
rutie::Boolean,
|
39
|
+
rutie::Fixnum,
|
40
|
+
rutie::Float,
|
41
|
+
rutie::Hash,
|
42
|
+
rutie::Integer,
|
43
|
+
rutie::NilClass,
|
44
|
+
rutie::Proc,
|
45
|
+
rutie::RString,
|
46
|
+
rutie::Symbol,
|
47
|
+
);
|