wasmer 0.1.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/Cargo.toml
CHANGED
@@ -1,21 +1,7 @@
|
|
1
|
-
[
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
readme = "README.md"
|
9
|
-
repository = "https://github.com/wasmerio/ruby-ext-wasm"
|
10
|
-
keywords = ["ruby", "extension", "webassembly"]
|
11
|
-
categories = ["wasm"]
|
12
|
-
|
13
|
-
[lib]
|
14
|
-
name = "wasmer"
|
15
|
-
crate-type = ["dylib"]
|
16
|
-
|
17
|
-
[dependencies]
|
18
|
-
wasmer-runtime = "0.3.0"
|
19
|
-
wasmer-runtime-core = "0.3.0"
|
20
|
-
rutie = "0.5.4"
|
21
|
-
lazy_static = "1.3.0"
|
1
|
+
[workspace]
|
2
|
+
members = [
|
3
|
+
"crates/rutie-derive",
|
4
|
+
"crates/rutie-derive-macros",
|
5
|
+
"crates/rutie-test",
|
6
|
+
"crates/wasmer",
|
7
|
+
]
|
data/Gemfile
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2019-present Wasmer, Inc. and its affiliates.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
./crates/wasmer/README.md
|
data/Rakefile
CHANGED
@@ -1,21 +1,22 @@
|
|
1
|
-
require "rbconfig"
|
2
1
|
require "bundler/gem_tasks"
|
3
2
|
require "rake/testtask"
|
4
3
|
|
5
4
|
desc 'Build the Rust extension'
|
6
5
|
task :build_lib do
|
7
|
-
sh 'cargo build --release'
|
6
|
+
sh 'cargo build --release --manifest-path crates/wasmer/Cargo.toml'
|
8
7
|
end
|
9
8
|
|
10
9
|
desc 'Install the bundle'
|
11
10
|
task :bundle_install do
|
11
|
+
sh 'bundle config set --local path "vendor/bundle"'
|
12
12
|
sh 'bundle install'
|
13
|
+
sh 'cd vendor/bundle && ln -f -s ruby/*/gems/rutie-*/ rutie'
|
13
14
|
end
|
14
15
|
|
15
16
|
Rake::TestTask.new(test: [:bundle_install, :build_lib]) do |t|
|
16
17
|
t.libs << "tests"
|
17
18
|
t.libs << "lib"
|
18
|
-
t.test_files = FileList["tests
|
19
|
+
t.test_files = FileList["tests/*_test.rb"]
|
19
20
|
end
|
20
21
|
|
21
22
|
task :default => :test
|
data/bors.toml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
[package]
|
2
|
+
name = "rutie-derive-macros"
|
3
|
+
version = "0.1.0"
|
4
|
+
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
5
|
+
edition = "2018"
|
6
|
+
description = "Procedural macros on top of `rutie` to write Ruby extensions faster and safer"
|
7
|
+
readme = "README.md"
|
8
|
+
repository = "https://github.com/wasmerio/wasmer-ruby"
|
9
|
+
keywords = ["ruby", "extension"]
|
10
|
+
publish = false
|
11
|
+
|
12
|
+
[lib]
|
13
|
+
proc-macro = true
|
14
|
+
|
15
|
+
[dependencies]
|
16
|
+
syn = { version = "1.0", features = ["full"] }
|
17
|
+
quote = "1.0"
|
18
|
+
paste = "1.0"
|
19
|
+
proc-macro2 = "1.0"
|
@@ -0,0 +1,156 @@
|
|
1
|
+
use proc_macro2::TokenStream;
|
2
|
+
use quote::quote;
|
3
|
+
use syn::{
|
4
|
+
parse_macro_input, AttributeArgs, Data, DataStruct, DeriveInput, Generics, Ident, Lit, Meta,
|
5
|
+
MetaNameValue, NestedMeta,
|
6
|
+
};
|
7
|
+
|
8
|
+
pub fn entry(
|
9
|
+
attr: proc_macro::TokenStream,
|
10
|
+
input: proc_macro::TokenStream,
|
11
|
+
) -> proc_macro::TokenStream {
|
12
|
+
let cloned_input = input.clone();
|
13
|
+
let derive_input = parse_macro_input!(cloned_input as DeriveInput);
|
14
|
+
let arguments = parse_macro_input!(attr as AttributeArgs);
|
15
|
+
|
16
|
+
if arguments.is_empty() {
|
17
|
+
panic!("The `rubyclass` procedural macro must have a `module` argument, e.g. `#[rubyclass(module = \"foo\")`");
|
18
|
+
}
|
19
|
+
|
20
|
+
let mut ruby_module = None;
|
21
|
+
|
22
|
+
for argument in arguments.iter() {
|
23
|
+
match argument {
|
24
|
+
NestedMeta::Meta(Meta::NameValue(MetaNameValue {
|
25
|
+
path: name,
|
26
|
+
lit: Lit::Str(value),
|
27
|
+
..
|
28
|
+
})) if name.is_ident("module") => {
|
29
|
+
ruby_module = Some(value.value());
|
30
|
+
}
|
31
|
+
|
32
|
+
argument => panic!(
|
33
|
+
"Unexpected argument `{:?}` from the `rubyclass` procedural macro",
|
34
|
+
argument
|
35
|
+
),
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
let derived = match derive_input.data {
|
40
|
+
Data::Struct(ref struct_data) => derive_for_struct(
|
41
|
+
&derive_input.ident,
|
42
|
+
struct_data,
|
43
|
+
&derive_input.generics,
|
44
|
+
ruby_module.expect("The `module` argument of the `rubyclass` procedural macro is missing, e.g. `#[rubyclass(module = \"foo\")]`"),
|
45
|
+
),
|
46
|
+
|
47
|
+
Data::Enum(_) => panic!("enums are not yet supported"),
|
48
|
+
|
49
|
+
Data::Union(_) => panic!("unions are not yet supported"),
|
50
|
+
};
|
51
|
+
|
52
|
+
let input = TokenStream::from(input);
|
53
|
+
|
54
|
+
(quote! { #input #derived }).into()
|
55
|
+
}
|
56
|
+
|
57
|
+
fn derive_for_struct(
|
58
|
+
struct_name: &Ident,
|
59
|
+
_data: &DataStruct,
|
60
|
+
generics: &Generics,
|
61
|
+
ruby_module: String,
|
62
|
+
) -> proc_macro2::TokenStream {
|
63
|
+
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
64
|
+
|
65
|
+
let span = struct_name.span();
|
66
|
+
let wrapper_struct_name = Ident::new(&format!("{}Wrapper", struct_name), span);
|
67
|
+
let wrapper_const_name = Ident::new(
|
68
|
+
&format!("{}_WRAPPER", struct_name.to_string().to_uppercase()),
|
69
|
+
span,
|
70
|
+
);
|
71
|
+
let ruby_struct_name = Ident::new(&format!("Ruby{}", struct_name), span);
|
72
|
+
let ruby_sub_module_hack = Ident::new(
|
73
|
+
&format!("ruby_{}_hack", struct_name.to_string().to_lowercase()),
|
74
|
+
span,
|
75
|
+
);
|
76
|
+
|
77
|
+
let mut ruby_module_parts = ruby_module.split("::");
|
78
|
+
let ruby_module = ruby_module_parts.next().unwrap();
|
79
|
+
let ruby_nested_modules = ruby_module_parts.collect::<Vec<_>>();
|
80
|
+
|
81
|
+
quote! {
|
82
|
+
// Create the `XXXWrapper` wrapper class.
|
83
|
+
//
|
84
|
+
// Do that in a specific module because `wrappable_struct` must be imported to work correctly.
|
85
|
+
mod #ruby_sub_module_hack {
|
86
|
+
use super::*; // to get `lazy_static`, imported by the user.
|
87
|
+
use rutie::{wrappable_struct};
|
88
|
+
|
89
|
+
wrappable_struct!(#struct_name, #wrapper_struct_name, #wrapper_const_name);
|
90
|
+
}
|
91
|
+
|
92
|
+
pub use #ruby_sub_module_hack::*;
|
93
|
+
|
94
|
+
// Implement the `RubyXXX` class.
|
95
|
+
rutie::class!(#ruby_struct_name);
|
96
|
+
|
97
|
+
// Implement `rutie::VerifiedObject` so that we can cast from
|
98
|
+
// `RubyXXX` to `XXX` with `rutie::Object::try_convert_to`.
|
99
|
+
impl #impl_generics rutie::VerifiedObject for #ruby_struct_name #ty_generics
|
100
|
+
#where_clause
|
101
|
+
{
|
102
|
+
fn is_correct_type<T>(object: &T) -> bool
|
103
|
+
where T: rutie::Object
|
104
|
+
{
|
105
|
+
object.class() == rutie::Module::from_existing(#ruby_module)
|
106
|
+
#(
|
107
|
+
.get_nested_module(#ruby_nested_modules)
|
108
|
+
),*
|
109
|
+
.get_nested_class(stringify!(#struct_name))
|
110
|
+
}
|
111
|
+
|
112
|
+
fn error_message() -> &'static str {
|
113
|
+
concat!("Error converting to `", stringify!(#ruby_struct_name), "`")
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
// Implement custom `rutie_derive::ClassInfo` for `XXX`.
|
118
|
+
impl rutie_derive::ClassInfo for #struct_name {
|
119
|
+
type Class = #struct_name;
|
120
|
+
type RubyClass = #ruby_struct_name;
|
121
|
+
}
|
122
|
+
|
123
|
+
// Implement custom `rutie_derive::ClassInfo` for `RubyXXX`.
|
124
|
+
impl rutie_derive::ClassInfo for #ruby_struct_name {
|
125
|
+
type Class = #struct_name;
|
126
|
+
type RubyClass = #ruby_struct_name;
|
127
|
+
}
|
128
|
+
|
129
|
+
// Allow to unwrap from `RubyXXX` to `XXX`.
|
130
|
+
impl #impl_generics rutie_derive::UpcastRubyClass<#struct_name #ty_generics> for #ruby_struct_name
|
131
|
+
#where_clause
|
132
|
+
{
|
133
|
+
fn upcast(&self) -> &#struct_name {
|
134
|
+
rutie::Object::get_data(self, &*#wrapper_const_name)
|
135
|
+
}
|
136
|
+
|
137
|
+
fn upcast_mut(&mut self) -> &mut #struct_name {
|
138
|
+
rutie::Object::get_data_mut(self, &*#wrapper_const_name)
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
// Temporary helper to instantiate a `RubyXXX` with a `XXX`.
|
143
|
+
impl #impl_generics #struct_name #ty_generics
|
144
|
+
#where_clause
|
145
|
+
{
|
146
|
+
pub(crate) fn ruby_new(this: Self) -> rutie::AnyObject {
|
147
|
+
rutie::Module::from_existing(#ruby_module)
|
148
|
+
#(
|
149
|
+
.get_nested_module(#ruby_nested_modules)
|
150
|
+
),*
|
151
|
+
.get_nested_class(stringify!(#struct_name))
|
152
|
+
.wrap_data(this, &*#wrapper_const_name)
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
@@ -0,0 +1,178 @@
|
|
1
|
+
use proc_macro2::Ident;
|
2
|
+
use quote::quote;
|
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 function = parse_macro_input!(input as ItemFn);
|
10
|
+
|
11
|
+
if !function.attrs.is_empty() {
|
12
|
+
panic!("Functions in `#[rubyfunction]` do not support attributes for the moment");
|
13
|
+
}
|
14
|
+
|
15
|
+
let function_name = function.sig.ident.to_string();
|
16
|
+
|
17
|
+
if function.sig.constness.is_some() {
|
18
|
+
panic!("Function `{}` cannot be `const`", function_name);
|
19
|
+
}
|
20
|
+
|
21
|
+
if function.sig.asyncness.is_some() {
|
22
|
+
panic!("Function `{}` cannot be `async`", function_name);
|
23
|
+
}
|
24
|
+
|
25
|
+
if function.sig.unsafety.is_some() {
|
26
|
+
panic!("Function `{}` cannot be `unsafe`", function_name);
|
27
|
+
}
|
28
|
+
|
29
|
+
if function.sig.abi.is_some() {
|
30
|
+
panic!("Function `{}` cannot have a different ABI", function_name);
|
31
|
+
}
|
32
|
+
|
33
|
+
if !function.sig.generics.params.is_empty() {
|
34
|
+
panic!("Function `{}` cannot be generic", function_name);
|
35
|
+
}
|
36
|
+
|
37
|
+
if function.sig.variadic.is_some() {
|
38
|
+
panic!("Function `{}` cannot be variadic", function_name);
|
39
|
+
}
|
40
|
+
|
41
|
+
let ruby_function_name = &function.sig.ident;
|
42
|
+
let ruby_function_block = &function.block;
|
43
|
+
let ruby_function_visibility = &function.vis;
|
44
|
+
|
45
|
+
let ruby_arguments_parsing = {
|
46
|
+
let (ruby_input_names, ruby_input_types): (
|
47
|
+
Vec<Ident>,
|
48
|
+
Vec<Punctuated<PathSegment, Colon2>>,
|
49
|
+
) = function
|
50
|
+
.sig
|
51
|
+
.inputs
|
52
|
+
.iter()
|
53
|
+
.filter_map(|input| match input {
|
54
|
+
FnArg::Typed(PatType { pat, ty, .. }) => match (&**pat, &**ty) {
|
55
|
+
(
|
56
|
+
Pat::Ident(ident),
|
57
|
+
Type::Reference(TypeReference { elem, .. }),
|
58
|
+
) => match &**elem {
|
59
|
+
Type::Path(TypePath {
|
60
|
+
qself: None,
|
61
|
+
path: Path { segments: ty, .. },
|
62
|
+
}) => Some((ident.ident.clone(), ty.clone())),
|
63
|
+
_ => panic!(
|
64
|
+
"Typed input has an unsupported form (function `{}`)",
|
65
|
+
function_name
|
66
|
+
),
|
67
|
+
},
|
68
|
+
_ => panic!(
|
69
|
+
"Typed input has an unsupported form (function `{}`), it must be a reference type",
|
70
|
+
function_name
|
71
|
+
),
|
72
|
+
},
|
73
|
+
|
74
|
+
FnArg::Receiver(..) => unreachable!(),
|
75
|
+
})
|
76
|
+
.unzip();
|
77
|
+
|
78
|
+
if ruby_input_names.is_empty() {
|
79
|
+
quote! {}
|
80
|
+
} else {
|
81
|
+
quote! {
|
82
|
+
let ( #( #ruby_input_names ),* ) =
|
83
|
+
{
|
84
|
+
let arguments = rutie::util::parse_arguments(argc, argv);
|
85
|
+
let mut argument_nth = 0;
|
86
|
+
|
87
|
+
(
|
88
|
+
#(
|
89
|
+
{
|
90
|
+
let argument = arguments
|
91
|
+
.get(argument_nth)
|
92
|
+
.ok_or_else(|| {
|
93
|
+
<rutie::AnyException as rutie::Exception>::new(
|
94
|
+
"ArgumentError",
|
95
|
+
Some(&format!(concat!("Argument #{} (`", stringify!( #ruby_input_types ), "`) of function `", stringify!( #ruby_function_name ), "` is missing"), argument_nth)),
|
96
|
+
)
|
97
|
+
})
|
98
|
+
.and_then(|argument| {
|
99
|
+
<rutie::AnyObject as rutie::Object>
|
100
|
+
::try_convert_to::<< #ruby_input_types as rutie_derive::ClassInfo>::RubyClass>(argument)
|
101
|
+
})
|
102
|
+
.unwrap_or_else(|error| {
|
103
|
+
rutie::VM::raise_ex(error);
|
104
|
+
unreachable!()
|
105
|
+
});
|
106
|
+
|
107
|
+
argument_nth += 1;
|
108
|
+
|
109
|
+
argument
|
110
|
+
}
|
111
|
+
),*
|
112
|
+
)
|
113
|
+
};
|
114
|
+
|
115
|
+
let ( #( #ruby_input_names ),* ) =
|
116
|
+
(
|
117
|
+
#(
|
118
|
+
rutie_derive::UpcastRubyClass::<
|
119
|
+
<
|
120
|
+
< #ruby_input_types as rutie_derive::ClassInfo>::RubyClass as rutie_derive::ClassInfo
|
121
|
+
>::Class
|
122
|
+
>::upcast(&#ruby_input_names)
|
123
|
+
),*
|
124
|
+
);
|
125
|
+
}
|
126
|
+
}
|
127
|
+
};
|
128
|
+
|
129
|
+
let ruby_output = match function.sig.output {
|
130
|
+
ReturnType::Type(_, ty) => match *ty {
|
131
|
+
Type::Path(TypePath {
|
132
|
+
qself: None,
|
133
|
+
path:
|
134
|
+
Path {
|
135
|
+
leading_colon: None,
|
136
|
+
segments,
|
137
|
+
},
|
138
|
+
}) if segments.first().unwrap().ident.to_string() == "RubyResult" => {
|
139
|
+
match &segments.first().unwrap().arguments {
|
140
|
+
PathArguments::AngleBracketed(AngleBracketedGenericArguments {
|
141
|
+
args,
|
142
|
+
..
|
143
|
+
}) => match args.first().unwrap() {
|
144
|
+
GenericArgument::Type(ty) => ty.clone(),
|
145
|
+
_ => panic!("Function has not well-formed rerturned type, expect `RubyResult<T>` where `T` is a type"),
|
146
|
+
},
|
147
|
+
_ => panic!("Function has not well-formed returned type, expect `RubyResult<T>`"),
|
148
|
+
}
|
149
|
+
}
|
150
|
+
_ => panic!("Function must wrap their output type inside `RubyResult<T>`"),
|
151
|
+
},
|
152
|
+
_ => panic!("Function must have an output of the form `RubyResult<T>`"),
|
153
|
+
};
|
154
|
+
|
155
|
+
(quote! {
|
156
|
+
#[allow(improper_ctypes_definitions)] // Not ideal but that's how Rutie works.
|
157
|
+
#ruby_function_visibility extern "C" fn #ruby_function_name(
|
158
|
+
argc: rutie::types::Argc,
|
159
|
+
argv: *const rutie::AnyObject,
|
160
|
+
_: rutie::AnyObject,
|
161
|
+
) -> #ruby_output {
|
162
|
+
#ruby_arguments_parsing
|
163
|
+
|
164
|
+
let block = || -> Result<_, rutie::AnyException> {
|
165
|
+
#ruby_function_block
|
166
|
+
};
|
167
|
+
|
168
|
+
match block() {
|
169
|
+
Ok(x) => x,
|
170
|
+
Err(e) => {
|
171
|
+
rutie::VM::raise_ex(e);
|
172
|
+
unreachable!()
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
176
|
+
})
|
177
|
+
.into()
|
178
|
+
}
|