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
@@ -0,0 +1,55 @@
1
+ //! Functions to handle error or exception correctly.
2
+
3
+ use rutie::{AnyException, Exception, VM};
4
+
5
+ pub type RubyResult<T> = Result<T, AnyException>;
6
+
7
+ #[allow(unused)]
8
+ pub(crate) fn unwrap_or_raise<Output, Function>(f: Function) -> Output
9
+ where
10
+ Function: FnOnce() -> Result<Output, AnyException>,
11
+ {
12
+ match f() {
13
+ Ok(x) => x,
14
+ Err(e) => {
15
+ VM::raise_ex(e);
16
+ unreachable!()
17
+ }
18
+ }
19
+ }
20
+
21
+ pub trait ErrorType {
22
+ fn name() -> &'static str;
23
+ }
24
+
25
+ macro_rules! declare_error {
26
+ ($name:ident) => {
27
+ pub struct $name;
28
+
29
+ impl ErrorType for $name {
30
+ fn name() -> &'static str {
31
+ stringify!($name)
32
+ }
33
+ }
34
+ };
35
+
36
+ ( $( $name:ident ),+ $(,)? ) => {
37
+ $( declare_error!($name); )*
38
+ }
39
+ }
40
+
41
+ declare_error!(
42
+ ArgumentError,
43
+ IndexError,
44
+ NameError,
45
+ RuntimeError,
46
+ TypeError,
47
+ );
48
+
49
+ pub fn to_ruby_err<Type, Error>(error: Error) -> AnyException
50
+ where
51
+ Type: ErrorType,
52
+ Error: ToString,
53
+ {
54
+ AnyException::new(Type::name(), Some(error.to_string().as_ref()))
55
+ }
@@ -0,0 +1,107 @@
1
+ use crate::{
2
+ error::{to_ruby_err, RuntimeError},
3
+ prelude::*,
4
+ };
5
+ use rutie::{Boolean, Fixnum, Symbol};
6
+ use std::convert::TryInto;
7
+
8
+ #[rubyclass(module = "Wasmer")]
9
+ pub struct Exports {
10
+ inner: wasmer::Exports,
11
+ }
12
+
13
+ impl Exports {
14
+ pub fn new(inner: wasmer::Exports) -> Self {
15
+ Self { inner }
16
+ }
17
+
18
+ pub(crate) fn inner(&self) -> &wasmer::Exports {
19
+ &self.inner
20
+ }
21
+ }
22
+
23
+ #[rubymethods]
24
+ impl Exports {
25
+ pub fn respond_to_missing(
26
+ &self,
27
+ symbol: &Symbol,
28
+ _include_private: &Boolean,
29
+ ) -> RubyResult<Boolean> {
30
+ Ok(Boolean::new(self.inner().contains(symbol.to_str())))
31
+ }
32
+
33
+ pub fn length(&self) -> RubyResult<Fixnum> {
34
+ Ok(Fixnum::new(
35
+ self.inner()
36
+ .len()
37
+ .try_into()
38
+ .map_err(to_ruby_err::<RuntimeError, _>)?,
39
+ ))
40
+ }
41
+ }
42
+
43
+ pub(crate) mod ruby_exports_extra {
44
+ use crate::{
45
+ error::{to_ruby_err, unwrap_or_raise, ArgumentError, NameError},
46
+ externals::{Function, Global, Memory, Table},
47
+ };
48
+ use rutie::{
49
+ rubysys::class,
50
+ types::{Argc, Value},
51
+ util::str_to_cstring,
52
+ AnyObject, Array, Object, Symbol,
53
+ };
54
+ use rutie_derive::UpcastRubyClass;
55
+
56
+ #[allow(improper_ctypes_definitions)] // No choice, that's how `rutie` is designed.
57
+ pub extern "C" fn method_missing(
58
+ argc: Argc,
59
+ argv: *const AnyObject,
60
+ itself: super::RubyExports,
61
+ ) -> AnyObject {
62
+ unwrap_or_raise(|| {
63
+ let arguments = Value::from(0);
64
+
65
+ unsafe {
66
+ let argv_pointer = argv as *const Value;
67
+
68
+ class::rb_scan_args(argc, argv_pointer, str_to_cstring("*").as_ptr(), &arguments)
69
+ };
70
+
71
+ let exports = itself.upcast();
72
+ let mut arguments = Array::from(arguments);
73
+
74
+ let extern_name = arguments.shift().try_convert_to::<Symbol>()?;
75
+ let extern_name = extern_name.to_str();
76
+
77
+ if arguments.length() > 1 {
78
+ return Err(to_ruby_err::<ArgumentError, _>(format!(
79
+ "`Export::method_missing` has been called with more than one argument (`{name}` plus {number_of_arguments} extra argument(s)). If you are trying to call an exported WebAssembly function, use the following form: `exports.{name}.(arguments…)`",
80
+ name = extern_name,
81
+ number_of_arguments = arguments.length(),
82
+ )));
83
+ }
84
+
85
+ Ok(match exports.inner().get_extern(extern_name) {
86
+ Some(wasmer::Extern::Function(function)) => {
87
+ Function::ruby_new(Function::raw_new(function.clone())).to_any_object()
88
+ }
89
+ Some(wasmer::Extern::Memory(memory)) => {
90
+ Memory::ruby_new(Memory::raw_new(memory.clone())).to_any_object()
91
+ }
92
+ Some(wasmer::Extern::Global(global)) => {
93
+ Global::ruby_new(Global::raw_new(global.clone())).to_any_object()
94
+ }
95
+ Some(wasmer::Extern::Table(table)) => {
96
+ Table::ruby_new(Table::raw_new(table.clone())).to_any_object()
97
+ }
98
+ None => {
99
+ return Err(to_ruby_err::<NameError, _>(format!(
100
+ "Export `{}` does not exist",
101
+ extern_name
102
+ )))
103
+ }
104
+ })
105
+ })
106
+ }
107
+ }
@@ -0,0 +1,159 @@
1
+ use crate::{
2
+ error::{to_ruby_err, TypeError},
3
+ prelude::*,
4
+ store::Store,
5
+ types::FunctionType,
6
+ values::{to_ruby_object, to_wasm_value},
7
+ };
8
+ use rutie::{util::is_method, AnyObject, Array, Object, Proc, Symbol};
9
+ use std::sync::Arc;
10
+
11
+ #[derive(Clone)]
12
+ struct Callable(Arc<dyn Fn(&[AnyObject]) -> AnyObject>);
13
+
14
+ unsafe impl Send for Callable {}
15
+ unsafe impl Sync for Callable {}
16
+
17
+ #[rubyclass(module = "Wasmer")]
18
+ pub struct Function {
19
+ inner: wasmer::Function,
20
+ }
21
+
22
+ impl Function {
23
+ pub fn raw_new(inner: wasmer::Function) -> Self {
24
+ Self { inner }
25
+ }
26
+
27
+ pub(crate) fn inner(&self) -> &wasmer::Function {
28
+ &self.inner
29
+ }
30
+ }
31
+
32
+ #[rubymethods]
33
+ impl Function {
34
+ pub fn new(
35
+ store: &Store,
36
+ function: &AnyObject,
37
+ function_type: &FunctionType,
38
+ ) -> RubyResult<AnyObject> {
39
+ let function = Callable(if let Ok(symbol) = function.try_convert_to::<Symbol>() {
40
+ Arc::new(move |arguments| symbol.to_proc().call(arguments))
41
+ } else if let Ok(proc) = function.try_convert_to::<Proc>() {
42
+ Arc::new(move |arguments| proc.call(arguments))
43
+ } else if is_method(*function.as_ref()) {
44
+ let function = function.clone();
45
+
46
+ Arc::new(move |arguments| unsafe { function.send("call", arguments) })
47
+ } else {
48
+ return Err(to_ruby_err::<TypeError, _>(
49
+ "Argument #1 of `Function.new` must be either a `Symbol`, a `Proc`, or a `Method`",
50
+ ));
51
+ });
52
+
53
+ let function_type: wasmer::FunctionType = function_type.into();
54
+
55
+ #[derive(wasmer::WasmerEnv, Clone)]
56
+ struct Environment {
57
+ ruby_callable: Callable,
58
+ result_types: Vec<wasmer::Type>,
59
+ }
60
+
61
+ let environment = Environment {
62
+ ruby_callable: function,
63
+ result_types: function_type.results().to_vec(),
64
+ };
65
+
66
+ let host_function = wasmer::Function::new_with_env(
67
+ store.inner(),
68
+ function_type,
69
+ environment,
70
+ |environment,
71
+ arguments: &[wasmer::Value]|
72
+ -> Result<Vec<wasmer::Value>, wasmer::RuntimeError> {
73
+ let arguments = arguments.iter().map(to_ruby_object).collect::<Vec<_>>();
74
+
75
+ let ruby_callable = &environment.ruby_callable.0;
76
+ let results = ruby_callable(&arguments);
77
+
78
+ let result_types = &environment.result_types;
79
+ let has_result_types = !result_types.is_empty();
80
+
81
+ Ok(if let Ok(results) = results.try_convert_to::<Array>() {
82
+ results
83
+ .into_iter()
84
+ .zip(result_types)
85
+ .map(|(value, ty)| to_wasm_value((&value, *ty)))
86
+ .collect::<RubyResult<_>>()
87
+ .map_err(|error| wasmer::RuntimeError::new(error.to_string()))?
88
+ } else if !results.is_nil() && has_result_types {
89
+ vec![to_wasm_value((&results, result_types[0]))
90
+ .map_err(|error| wasmer::RuntimeError::new(error.to_string()))?]
91
+ } else {
92
+ Vec::new()
93
+ })
94
+ },
95
+ );
96
+
97
+ Ok(Function::ruby_new(Function {
98
+ inner: host_function,
99
+ }))
100
+ }
101
+
102
+ pub fn r#type(&self) -> RubyResult<AnyObject> {
103
+ Ok(FunctionType::ruby_new(self.inner().ty().into()))
104
+ }
105
+ }
106
+
107
+ pub(crate) mod ruby_function_extra {
108
+ use crate::{
109
+ error::{to_ruby_err, unwrap_or_raise, RubyResult, RuntimeError},
110
+ values::{to_ruby_object, to_wasm_value},
111
+ };
112
+ use rutie::{
113
+ rubysys::class,
114
+ types::{Argc, Value},
115
+ util::str_to_cstring,
116
+ AnyObject, Array, NilClass, Object,
117
+ };
118
+ use rutie_derive::UpcastRubyClass;
119
+
120
+ #[allow(improper_ctypes_definitions)] // No choice, that's how `rutie` is designed.
121
+ pub extern "C" fn call(
122
+ argc: Argc,
123
+ argv: *const AnyObject,
124
+ itself: super::RubyFunction,
125
+ ) -> AnyObject {
126
+ unwrap_or_raise(|| {
127
+ let arguments = Value::from(0);
128
+
129
+ unsafe {
130
+ let argv_pointer = argv as *const Value;
131
+
132
+ class::rb_scan_args(argc, argv_pointer, str_to_cstring("*").as_ptr(), &arguments)
133
+ };
134
+
135
+ let function = itself.upcast();
136
+ let arguments: Vec<wasmer::Value> = Array::from(arguments)
137
+ .into_iter()
138
+ .zip(function.inner().ty().params())
139
+ .map(|(value, ty)| to_wasm_value((&value, *ty)))
140
+ .collect::<RubyResult<_>>()?;
141
+
142
+ let results = function
143
+ .inner()
144
+ .call(&arguments)
145
+ .map(<[_]>::into_vec)
146
+ .map_err(to_ruby_err::<RuntimeError, _>)?;
147
+
148
+ Ok(match results.len() {
149
+ 0 => NilClass::new().to_any_object(),
150
+ 1 => to_ruby_object(&results[0]),
151
+ _ => results
152
+ .iter()
153
+ .map(to_ruby_object)
154
+ .collect::<Array>()
155
+ .to_any_object(),
156
+ })
157
+ })
158
+ }
159
+ }
@@ -0,0 +1,62 @@
1
+ use crate::{
2
+ error::{to_ruby_err, RuntimeError},
3
+ prelude::*,
4
+ store::Store,
5
+ types::GlobalType,
6
+ values::{to_ruby_object, to_wasm_value, Value},
7
+ };
8
+ use rutie::{AnyObject, Boolean, NilClass};
9
+
10
+ #[rubyclass(module = "Wasmer")]
11
+ pub struct Global {
12
+ inner: wasmer::Global,
13
+ }
14
+
15
+ impl Global {
16
+ pub fn raw_new(inner: wasmer::Global) -> Self {
17
+ Self { inner }
18
+ }
19
+
20
+ pub(crate) fn inner(&self) -> &wasmer::Global {
21
+ &self.inner
22
+ }
23
+ }
24
+
25
+ #[rubymethods]
26
+ impl Global {
27
+ pub fn new(store: &Store, value: &Value, mutable: &Boolean) -> RubyResult<AnyObject> {
28
+ Ok(Global::ruby_new(Global::raw_new(if mutable.to_bool() {
29
+ wasmer::Global::new_mut(store.inner(), value.inner().clone())
30
+ } else {
31
+ wasmer::Global::new(store.inner(), value.inner().clone())
32
+ })))
33
+ }
34
+
35
+ pub fn mutable(&self) -> RubyResult<Boolean> {
36
+ Ok(Boolean::new(self.inner().ty().mutability.is_mutable()))
37
+ }
38
+
39
+ pub fn get_value(&self) -> RubyResult<AnyObject> {
40
+ Ok(to_ruby_object(&self.inner.get()))
41
+ }
42
+
43
+ pub fn set_value(&self, value: &AnyObject) -> RubyResult<NilClass> {
44
+ let ty = self.inner().ty();
45
+
46
+ if !ty.mutability.is_mutable() {
47
+ return Err(to_ruby_err::<RuntimeError, _>(
48
+ "The global variable is not mutable, cannot set a new value",
49
+ ));
50
+ }
51
+
52
+ self.inner()
53
+ .set(to_wasm_value((value, ty.ty))?)
54
+ .map_err(to_ruby_err::<RuntimeError, _>)?;
55
+
56
+ Ok(NilClass::new())
57
+ }
58
+
59
+ pub fn r#type(&self) -> RubyResult<AnyObject> {
60
+ Ok(GlobalType::ruby_new(self.inner().ty().into()))
61
+ }
62
+ }
@@ -0,0 +1,117 @@
1
+ use crate::{
2
+ error::{to_ruby_err, ArgumentError, RuntimeError},
3
+ memory::views::{Int16Array, Int32Array, Int8Array, Uint16Array, Uint32Array, Uint8Array},
4
+ prelude::*,
5
+ store::Store,
6
+ types::MemoryType,
7
+ };
8
+ use rutie::{AnyObject, Fixnum, Integer, Object};
9
+ use std::convert::{TryFrom, TryInto};
10
+
11
+ #[rubyclass(module = "Wasmer")]
12
+ pub struct Memory {
13
+ inner: wasmer::Memory,
14
+ }
15
+
16
+ impl Memory {
17
+ pub fn raw_new(inner: wasmer::Memory) -> Self {
18
+ Self { inner }
19
+ }
20
+
21
+ pub(crate) fn inner(&self) -> &wasmer::Memory {
22
+ &self.inner
23
+ }
24
+ }
25
+
26
+ fn unwrap_offset(offset: &AnyObject) -> RubyResult<usize> {
27
+ Ok(if offset.is_nil() {
28
+ 0
29
+ } else {
30
+ offset
31
+ .try_convert_to::<Integer>()?
32
+ .to_u64()
33
+ .try_into()
34
+ .map_err(to_ruby_err::<ArgumentError, _>)?
35
+ })
36
+ }
37
+
38
+ #[rubymethods]
39
+ impl Memory {
40
+ pub fn new(store: &Store, memory_type: &MemoryType) -> RubyResult<AnyObject> {
41
+ Ok(Memory::ruby_new(Memory::raw_new(
42
+ wasmer::Memory::new(store.inner(), memory_type.into())
43
+ .map_err(to_ruby_err::<RuntimeError, _>)?,
44
+ )))
45
+ }
46
+
47
+ pub fn r#type(&self) -> RubyResult<AnyObject> {
48
+ Ok(MemoryType::ruby_new(self.inner().ty().into()))
49
+ }
50
+
51
+ pub fn size(&self) -> RubyResult<Fixnum> {
52
+ Ok(Fixnum::new(self.inner().size().0.into()))
53
+ }
54
+
55
+ pub fn data_size(&self) -> RubyResult<Fixnum> {
56
+ Ok(Fixnum::new(
57
+ self.inner()
58
+ .data_size()
59
+ .try_into()
60
+ .map_err(to_ruby_err::<RuntimeError, _>)?,
61
+ ))
62
+ }
63
+
64
+ pub fn grow(&self, number_of_pages: &Fixnum) -> RubyResult<Fixnum> {
65
+ Ok(Fixnum::new(
66
+ self.inner()
67
+ .grow(
68
+ u32::try_from(number_of_pages.to_u64())
69
+ .map_err(to_ruby_err::<RuntimeError, _>)?,
70
+ )
71
+ .map_err(to_ruby_err::<RuntimeError, _>)
72
+ .and_then(|pages| pages.0.try_into().map_err(to_ruby_err::<RuntimeError, _>))?,
73
+ ))
74
+ }
75
+
76
+ pub fn uint8_view(&self, offset: &AnyObject) -> RubyResult<AnyObject> {
77
+ Ok(Uint8Array::ruby_new(Uint8Array::new(
78
+ self.inner().clone(),
79
+ unwrap_offset(offset)?,
80
+ )))
81
+ }
82
+
83
+ pub fn int8_view(&self, offset: &AnyObject) -> RubyResult<AnyObject> {
84
+ Ok(Int8Array::ruby_new(Int8Array::new(
85
+ self.inner().clone(),
86
+ unwrap_offset(offset)?,
87
+ )))
88
+ }
89
+
90
+ pub fn uint16_view(&self, offset: &AnyObject) -> RubyResult<AnyObject> {
91
+ Ok(Uint16Array::ruby_new(Uint16Array::new(
92
+ self.inner().clone(),
93
+ unwrap_offset(offset)?,
94
+ )))
95
+ }
96
+
97
+ pub fn int16_view(&self, offset: &AnyObject) -> RubyResult<AnyObject> {
98
+ Ok(Int16Array::ruby_new(Int16Array::new(
99
+ self.inner().clone(),
100
+ unwrap_offset(offset)?,
101
+ )))
102
+ }
103
+
104
+ pub fn uint32_view(&self, offset: &AnyObject) -> RubyResult<AnyObject> {
105
+ Ok(Uint32Array::ruby_new(Uint32Array::new(
106
+ self.inner().clone(),
107
+ unwrap_offset(offset)?,
108
+ )))
109
+ }
110
+
111
+ pub fn int32_view(&self, offset: &AnyObject) -> RubyResult<AnyObject> {
112
+ Ok(Int32Array::ruby_new(Int32Array::new(
113
+ self.inner().clone(),
114
+ unwrap_offset(offset)?,
115
+ )))
116
+ }
117
+ }