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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.cargo/config +1 -1
  3. data/.github/workflows/documentation.yml +50 -0
  4. data/.github/workflows/test.yml +73 -0
  5. data/.gitignore +3 -1
  6. data/CHANGELOG.md +225 -0
  7. data/Cargo.lock +747 -708
  8. data/Cargo.toml +7 -21
  9. data/Gemfile +2 -3
  10. data/LICENSE +21 -0
  11. data/README.md +1 -0
  12. data/Rakefile +4 -3
  13. data/bors.toml +6 -0
  14. data/crates/rutie-derive-macros/Cargo.toml +19 -0
  15. data/crates/rutie-derive-macros/README.md +4 -0
  16. data/crates/rutie-derive-macros/src/class.rs +156 -0
  17. data/crates/rutie-derive-macros/src/function.rs +178 -0
  18. data/crates/rutie-derive-macros/src/lib.rs +27 -0
  19. data/crates/rutie-derive-macros/src/methods.rs +282 -0
  20. data/crates/rutie-derive/Cargo.toml +14 -0
  21. data/crates/rutie-derive/README.md +97 -0
  22. data/crates/rutie-derive/src/lib.rs +4 -0
  23. data/crates/rutie-derive/src/upcast.rs +47 -0
  24. data/crates/rutie-test/Cargo.toml +10 -0
  25. data/crates/rutie-test/src/lib.rs +38 -0
  26. data/crates/wasmer/Cargo.toml +27 -0
  27. data/crates/wasmer/README.md +229 -0
  28. data/crates/wasmer/src/doc.rs +1512 -0
  29. data/crates/wasmer/src/error.rs +55 -0
  30. data/crates/wasmer/src/exports.rs +107 -0
  31. data/crates/wasmer/src/externals/function.rs +159 -0
  32. data/crates/wasmer/src/externals/global.rs +62 -0
  33. data/crates/wasmer/src/externals/memory.rs +117 -0
  34. data/crates/wasmer/src/externals/mod.rs +9 -0
  35. data/crates/wasmer/src/externals/table.rs +41 -0
  36. data/crates/wasmer/src/import_object.rs +78 -0
  37. data/crates/wasmer/src/instance.rs +45 -0
  38. data/crates/wasmer/src/lib.rs +307 -0
  39. data/crates/wasmer/src/memory/mod.rs +1 -0
  40. data/crates/wasmer/src/memory/views.rs +112 -0
  41. data/crates/wasmer/src/module.rs +106 -0
  42. data/crates/wasmer/src/prelude.rs +3 -0
  43. data/crates/wasmer/src/store.rs +22 -0
  44. data/crates/wasmer/src/types.rs +396 -0
  45. data/crates/wasmer/src/values.rs +84 -0
  46. data/crates/wasmer/src/wasi.rs +226 -0
  47. data/crates/wasmer/src/wat.rs +20 -0
  48. data/justfile +20 -2
  49. data/lib/wasmer.rb +29 -3
  50. data/wasmer.gemspec +8 -12
  51. metadata +53 -49
  52. data/.circleci/config.yml +0 -70
  53. data/README.md +0 -279
  54. data/lib/wasmer/version.rb +0 -3
  55. data/src/instance.rs +0 -282
  56. data/src/lib.rs +0 -98
  57. data/src/memory/mod.rs +0 -120
  58. data/src/memory/view.rs +0 -127
  59. 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
+ }