wasmer 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/documentation.yml +50 -0
  3. data/.github/workflows/test.yml +34 -61
  4. data/CHANGELOG.md +89 -29
  5. data/Cargo.lock +812 -380
  6. data/Cargo.toml +7 -20
  7. data/Gemfile +2 -3
  8. data/README.md +1 -0
  9. data/Rakefile +4 -3
  10. data/crates/rutie-derive-macros/Cargo.toml +19 -0
  11. data/crates/rutie-derive-macros/README.md +4 -0
  12. data/crates/rutie-derive-macros/src/class.rs +156 -0
  13. data/crates/rutie-derive-macros/src/function.rs +178 -0
  14. data/crates/rutie-derive-macros/src/lib.rs +27 -0
  15. data/crates/rutie-derive-macros/src/methods.rs +282 -0
  16. data/crates/rutie-derive/Cargo.toml +14 -0
  17. data/crates/rutie-derive/README.md +97 -0
  18. data/crates/rutie-derive/src/lib.rs +4 -0
  19. data/crates/rutie-derive/src/upcast.rs +47 -0
  20. data/crates/rutie-test/Cargo.toml +10 -0
  21. data/crates/rutie-test/src/lib.rs +38 -0
  22. data/crates/wasmer/Cargo.toml +27 -0
  23. data/crates/wasmer/README.md +228 -0
  24. data/crates/wasmer/src/doc.rs +1512 -0
  25. data/crates/wasmer/src/error.rs +55 -0
  26. data/crates/wasmer/src/exports.rs +107 -0
  27. data/crates/wasmer/src/externals/function.rs +159 -0
  28. data/crates/wasmer/src/externals/global.rs +62 -0
  29. data/crates/wasmer/src/externals/memory.rs +117 -0
  30. data/crates/wasmer/src/externals/mod.rs +9 -0
  31. data/crates/wasmer/src/externals/table.rs +41 -0
  32. data/crates/wasmer/src/import_object.rs +78 -0
  33. data/crates/wasmer/src/instance.rs +45 -0
  34. data/crates/wasmer/src/lib.rs +307 -0
  35. data/crates/wasmer/src/memory/mod.rs +1 -0
  36. data/crates/wasmer/src/memory/views.rs +112 -0
  37. data/crates/wasmer/src/module.rs +106 -0
  38. data/crates/wasmer/src/prelude.rs +3 -0
  39. data/crates/wasmer/src/store.rs +22 -0
  40. data/crates/wasmer/src/types.rs +390 -0
  41. data/crates/wasmer/src/values.rs +84 -0
  42. data/crates/wasmer/src/wasi.rs +226 -0
  43. data/crates/wasmer/src/wat.rs +20 -0
  44. data/justfile +7 -1
  45. data/lib/wasmer.rb +29 -3
  46. data/wasmer.gemspec +6 -10
  47. metadata +45 -47
  48. data/README.md +0 -332
  49. data/lib/wasmer/version.rb +0 -3
  50. data/src/error.rs +0 -16
  51. data/src/instance/exports.rs +0 -215
  52. data/src/instance/globals.rs +0 -234
  53. data/src/instance/mod.rs +0 -141
  54. data/src/lib.rs +0 -162
  55. data/src/memory/mod.rs +0 -158
  56. data/src/memory/view.rs +0 -145
  57. data/src/module.rs +0 -28
data/Cargo.toml CHANGED
@@ -1,20 +1,7 @@
1
- [package]
2
- publish = false
3
- name = "ruby-ext-wasm"
4
- version = "0.4.0"
5
- authors = ["Ivan Enderlin <ivan.enderlin@hoa-project.net>"]
6
- edition = "2018"
7
- description = "Ruby extension to run WebAssembly binaries"
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.14"
19
- rutie = "0.7"
20
- lazy_static = "1.4"
1
+ [workspace]
2
+ members = [
3
+ "crates/rutie-derive",
4
+ "crates/rutie-derive-macros",
5
+ "crates/rutie-test",
6
+ "crates/wasmer",
7
+ ]
data/Gemfile CHANGED
@@ -3,7 +3,6 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  group :test do
6
- gem 'minitest', '~> 5.10'
7
- gem 'minitest-reporters', '~> 1.1'
8
- gem 'color_pound_spec_reporter', '~> 0.0.6'
6
+ gem 'minitest', '~> 5.14'
7
+ gem 'minitest-reporters', '~> 1.4'
9
8
  end
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/**/*_test.rb"]
19
+ t.test_files = FileList["tests/*_test.rb"]
19
20
  end
20
21
 
21
22
  task :default => :test
@@ -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,4 @@
1
+ # `rutie-derive-macros`
2
+
3
+ That's the backend of the `rutie-derive` crate. Check the
4
+ documentation there.
@@ -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
+ }
@@ -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
+ }