wasmtime 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +941 -627
  3. data/Cargo.toml +2 -14
  4. data/LICENSE +23 -21
  5. data/README.md +47 -118
  6. data/ext/Cargo.toml +17 -0
  7. data/ext/extconf.rb +6 -0
  8. data/ext/src/helpers/mod.rs +3 -0
  9. data/ext/src/helpers/wrapped_struct.rs +84 -0
  10. data/ext/src/lib.rs +9 -0
  11. data/ext/src/ruby_api/config.rs +68 -0
  12. data/ext/src/ruby_api/convert.rs +92 -0
  13. data/ext/src/ruby_api/engine.rs +66 -0
  14. data/ext/src/ruby_api/errors.rs +56 -0
  15. data/ext/src/ruby_api/externals.rs +113 -0
  16. data/ext/src/ruby_api/func.rs +388 -0
  17. data/ext/src/ruby_api/func_type.rs +139 -0
  18. data/ext/src/ruby_api/instance.rs +174 -0
  19. data/ext/src/ruby_api/linker.rs +296 -0
  20. data/ext/src/ruby_api/macros.rs +12 -0
  21. data/ext/src/ruby_api/memory.rs +142 -0
  22. data/ext/src/ruby_api/memory_type.rs +56 -0
  23. data/ext/src/ruby_api/mod.rs +48 -0
  24. data/ext/src/ruby_api/module.rs +107 -0
  25. data/ext/src/ruby_api/params.rs +42 -0
  26. data/ext/src/ruby_api/static_id.rs +57 -0
  27. data/ext/src/ruby_api/store.rs +182 -0
  28. data/ext/src/ruby_api/trap.rs +135 -0
  29. data/lib/wasmtime/version.rb +1 -1
  30. data/lib/wasmtime.rb +29 -4
  31. metadata +54 -30
  32. data/.cargo/config +0 -4
  33. data/CHANGELOG.md +0 -27
  34. data/ext/wasmtime/Makefile +0 -5
  35. data/ext/wasmtime/Rakefile +0 -3
  36. data/ext/wasmtime/extconf.rb +0 -5
  37. data/lib/tasks/compile.rake +0 -27
  38. data/lib/wasmtime/refinements.rb +0 -20
  39. data/lib/wasmtime/require.rb +0 -72
  40. data/src/export.rs +0 -19
  41. data/src/func.rs +0 -175
  42. data/src/instance.rs +0 -93
  43. data/src/lib.rs +0 -22
  44. data/src/memory.rs +0 -48
  45. data/src/ruby_type.rs +0 -32
  46. data/src/vm.rs +0 -6
data/Cargo.toml CHANGED
@@ -1,14 +1,2 @@
1
- [package]
2
- name = "wasmtime-ruby"
3
- version = "0.1.0"
4
- authors = ["David Cristofaro <david@dtcristo.com>"]
5
- edition = "2018"
6
- publish = false
7
-
8
- [lib]
9
- crate-type = ["cdylib"]
10
-
11
- [dependencies]
12
- lazy_static = "1.4.0"
13
- rutie = "0.7.0"
14
- wasmtime = "0.16.0"
1
+ [workspace]
2
+ members = ["ext"]
data/LICENSE CHANGED
@@ -1,10 +1,11 @@
1
+
1
2
  Apache License
2
3
  Version 2.0, January 2004
3
4
  http://www.apache.org/licenses/
4
5
 
5
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7
 
7
- 1. Definitions.
8
+ 1. Definitions.
8
9
 
9
10
  "License" shall mean the terms and conditions for use, reproduction,
10
11
  and distribution as defined by Sections 1 through 9 of this document.
@@ -63,14 +64,14 @@
63
64
  on behalf of whom a Contribution has been received by Licensor and
64
65
  subsequently incorporated within the Work.
65
66
 
66
- 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
68
  this License, each Contributor hereby grants to You a perpetual,
68
69
  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
70
  copyright license to reproduce, prepare Derivative Works of,
70
71
  publicly display, publicly perform, sublicense, and distribute the
71
72
  Work and such Derivative Works in Source or Object form.
72
73
 
73
- 3. Grant of Patent License. Subject to the terms and conditions of
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
75
  this License, each Contributor hereby grants to You a perpetual,
75
76
  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
77
  (except as stated in this section) patent license to make, have made,
@@ -86,7 +87,7 @@
86
87
  granted to You under this License for that Work shall terminate
87
88
  as of the date such litigation is filed.
88
89
 
89
- 4. Redistribution. You may reproduce and distribute copies of the
90
+ 4. Redistribution. You may reproduce and distribute copies of the
90
91
  Work or Derivative Works thereof in any medium, with or without
91
92
  modifications, and in Source or Object form, provided that You
92
93
  meet the following conditions:
@@ -127,7 +128,7 @@
127
128
  reproduction, and distribution of the Work otherwise complies with
128
129
  the conditions stated in this License.
129
130
 
130
- 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
132
  any Contribution intentionally submitted for inclusion in the Work
132
133
  by You to the Licensor shall be under the terms and conditions of
133
134
  this License, without any additional terms or conditions.
@@ -135,12 +136,12 @@
135
136
  the terms of any separate license agreement you may have executed
136
137
  with Licensor regarding such Contributions.
137
138
 
138
- 6. Trademarks. This License does not grant permission to use the trade
139
+ 6. Trademarks. This License does not grant permission to use the trade
139
140
  names, trademarks, service marks, or product names of the Licensor,
140
141
  except as required for reasonable and customary use in describing the
141
142
  origin of the Work and reproducing the content of the NOTICE file.
142
143
 
143
- 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
145
  agreed to in writing, Licensor provides the Work (and each
145
146
  Contributor provides its Contributions) on an "AS IS" BASIS,
146
147
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
@@ -150,7 +151,7 @@
150
151
  appropriateness of using or redistributing the Work and assume any
151
152
  risks associated with Your exercise of permissions under this License.
152
153
 
153
- 8. Limitation of Liability. In no event and under no legal theory,
154
+ 8. Limitation of Liability. In no event and under no legal theory,
154
155
  whether in tort (including negligence), contract, or otherwise,
155
156
  unless required by applicable law (such as deliberate and grossly
156
157
  negligent acts) or agreed to in writing, shall any Contributor be
@@ -162,7 +163,7 @@
162
163
  other commercial damages or losses), even if such Contributor
163
164
  has been advised of the possibility of such damages.
164
165
 
165
- 9. Accepting Warranty or Additional Liability. While redistributing
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
167
  the Work or Derivative Works thereof, You may choose to offer,
167
168
  and charge a fee for, acceptance of support, warranty, indemnity,
168
169
  or other liability obligations and/or rights consistent with this
@@ -173,9 +174,9 @@
173
174
  incurred by, or claims asserted against, such Contributor by reason
174
175
  of your accepting any such warranty or additional liability.
175
176
 
176
- END OF TERMS AND CONDITIONS
177
+ END OF TERMS AND CONDITIONS
177
178
 
178
- APPENDIX: How to apply the Apache License to your work.
179
+ APPENDIX: How to apply the Apache License to your work.
179
180
 
180
181
  To apply the Apache License to your work, attach the following
181
182
  boilerplate notice, with the fields enclosed by brackets "[]"
@@ -186,19 +187,19 @@
186
187
  same "printed page" as the copyright notice for easier
187
188
  identification within third-party archives.
188
189
 
189
- Copyright [yyyy] [name of copyright owner]
190
+ Copyright [yyyy] [name of copyright owner]
190
191
 
191
- Licensed under the Apache License, Version 2.0 (the "License");
192
- you may not use this file except in compliance with the License.
193
- You may obtain a copy of the License at
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
194
195
 
195
196
  http://www.apache.org/licenses/LICENSE-2.0
196
197
 
197
- Unless required by applicable law or agreed to in writing, software
198
- distributed under the License is distributed on an "AS IS" BASIS,
199
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
- See the License for the specific language governing permissions and
201
- limitations under the License.
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
202
203
 
203
204
 
204
205
  --- LLVM Exceptions to the Apache 2.0 License ----
@@ -216,3 +217,4 @@ conflicts with the conditions of the GPLv2, you may retroactively and
216
217
  prospectively choose to deem waived or otherwise exclude such Section(s) of
217
218
  the License, but only in their entirety and only with respect to the Combined
218
219
  Software.
220
+
data/README.md CHANGED
@@ -1,147 +1,76 @@
1
1
  <div align="center">
2
- <h1>wasmtime-ruby</h1>
2
+ <h1><code>wasmtime-rb</code></h1>
3
+
3
4
  <p>
4
- <strong>
5
- Ruby bindings for <a href="https://github.com/bytecodealliance/wasmtime">Wasmtime</a>, a WebAssembly runtime
6
- </strong>
5
+ <strong>Ruby embedding of
6
+ <a href="https://github.com/bytecodealliance/wasmtime">Wasmtime</a></strong>
7
7
  </p>
8
+
9
+ <strong>A <a href="https://bytecodealliance.org/">Bytecode Alliance</a> project</strong>
10
+
8
11
  <p>
9
- <a href="https://rubygems.org/gems/wasmtime">
10
- <img src="https://img.shields.io/gem/v/wasmtime" alt="RubyGems version badge" />
11
- </a>
12
- <a href="https://github.com/dtcristo/wasmtime-ruby/actions?query=workflow%3ACI">
13
- <img src="https://img.shields.io/github/workflow/status/dtcristo/wasmtime-ruby/CI" alt="CI status badge" />
12
+ <a href="https://github.com/bytecodealliance/wasmtime-rb/actions?query=workflow%3ACI">
13
+ <img src="https://github.com/bytecodealliance/wasmtime-rb/workflows/CI/badge.svg" alt="CI status"/>
14
14
  </a>
15
15
  </p>
16
16
  </div>
17
17
 
18
- ## Introduction
18
+ ## Status
19
19
 
20
- This project provides Ruby bindings for [Wasmtime](https://github.com/bytecodealliance/wasmtime),
21
- a [WebAssembly](https://webassembly.org/) runtime. This allows you to execute
22
- WASM modules from within Ruby executing at near-native speeds in a safe
23
- sandboxed environment.
20
+ The Wasmtime Ruby bindings are still under development, [some features](https://github.com/bytecodealliance/wasmtime-rb/issues?q=is%3Aissue+is%3Aopen+label%3A%22missing+feature%22) are still missing.
24
21
 
25
- This is pretty experimental and not production ready right now. There are quite
26
- a few things that aren't built yet, see [TODO](#todo) section below.
22
+ ## Installation
27
23
 
28
- **Note:** [WebAssembly Interface Types](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md)
29
- support has been [temporarily removed](https://github.com/bytecodealliance/wasmtime/pull/1292)
30
- from Wasmtime. Only 32 and 64-bit integers and floats are currently supported.
24
+ Install from RubyGems
31
25
 
32
- ## Usage
33
-
34
- Install the `wasmtime` gem. Pre-compiled binaries are available for
35
- `x86_64-linux` and `x86_64-darwin-19`. Compiling the native extension requires
36
- [Rust with rustup](https://rustup.rs/).
37
-
38
- ```sh
26
+ ```shell
39
27
  gem install wasmtime
40
28
  ```
41
29
 
42
- WASM has two formats `.wasm` (binary) and `.wat` (human-readable text). Both
43
- formats are supported. With the following `fibonacci.wat` file in your current
44
- directory.
45
-
46
- ```wat
47
- ;; fibonacci.wat
48
- (module
49
- (export "fib" (func $fib))
50
- (func $fib (param $n i32) (result i32)
51
- (if (i32.lt_s (get_local $n) (i32.const 2))
52
- (return (i32.const 1))
53
- )
54
- (return
55
- (i32.add
56
- (call $fib (i32.sub (get_local $n) (i32.const 2)))
57
- (call $fib (i32.sub (get_local $n) (i32.const 1)))
58
- )
59
- )
60
- )
61
- )
62
- ```
30
+ Or use in your Gemfile:
63
31
 
64
- In a ruby file, `require 'wasmtime/require'` to activate the Wasmtime require
65
- patch, allowing you to require any `.wasm` or `.wat` module as if it were a
66
- Ruby file. Doing so will internally create a `Wasmtime::Instance` and define a
67
- Ruby module with functions for each export.
68
-
69
- Finally, invoke the `fib` export like so.
70
-
71
- ```rb
72
- require 'wasmtime/require'
73
- require_relative 'fibonacci'
74
-
75
- puts Fibonacci.fib(11) #=> 89
76
- ```
77
-
78
- If you don't like all the magic in the example above, you can do the same
79
- without the require patch. If your project is going to be a dependency of others
80
- use this approach too.
81
-
82
- ```rb
83
- require 'wasmtime'
84
-
85
- instance = Wasmtime::Instance.new('fibonacci.wat')
86
- puts instance.exports['fib'].call(11) #=> 89
32
+ ```ruby
33
+ gem "wasmtime", "~> 0.3.0"
87
34
  ```
88
35
 
89
- ## Benchmarks
90
-
91
- None yet. But they will be impressive.
92
-
93
- ## Examples
94
-
95
- More usage examples are provided in `examples/`. To run some of these, you first
96
- need to compile the test WASM modules.
97
-
98
- Install some Rust tools.
99
-
100
- - [rustup](https://rustup.rs/) - Rust toolchain manager
101
- - [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) - WASM module bundler
102
-
103
- Install Ruby dependencies.
104
-
105
- ```sh
106
- bundle install
107
- ```
108
-
109
- Build the WASM modules.
110
-
111
- ```sh
112
- bundle exec rake wasm
113
- ```
36
+ ## Usage
114
37
 
115
- Run an example.
38
+ Example usage:
116
39
 
117
- ```sh
118
- ruby examples/fibonacci.rb
119
- ```
40
+ ```ruby
41
+ require "wasmtime"
120
42
 
121
- ## Development
43
+ # Create an engine. Generally, you only need a single engine and can
44
+ # re-use it a throughout your program
45
+ engine = Wasmtime::Engine.new
122
46
 
123
- Compile Rust native extension.
47
+ # Compile a Wasm module from either Wasm or WAT. The compiled module is
48
+ # specific to the Engine's configuration.
49
+ mod = Wasmtime::Module.new(engine, <<~WAT)
50
+ (module
51
+ (func $hello (import "" "hello"))
52
+ (func (export "run") (call $hello))
53
+ )
54
+ WAT
124
55
 
125
- ```sh
126
- bundle exec rake compile
127
- ```
56
+ # Create a store. Store can keep state to be re-used in Funcs.
57
+ store = Wasmtime::Store.new(engine, {count: 0})
128
58
 
129
- Run test suite.
59
+ # Define a Wasm function from Ruby code.
60
+ func = Wasmtime::Func.new(store, Wasmtime::FuncType.new([], [])) do |caller|
61
+ puts "Hello from Func!"
62
+ puts "Ran #{caller[:count]} time(s)"
63
+ end
130
64
 
131
- ```sh
132
- bundle exec rake spec
133
- ```
65
+ # Build the Wasm instance by providing its imports
66
+ instance = Wasmtime::Instance.new(store, mod, [func])
134
67
 
135
- Format source code.
68
+ # Run the `run` export.
69
+ instance.invoke("run")
136
70
 
137
- ```sh
138
- bundle exec rake format
71
+ # Or: get the `run` export and call it
72
+ instance.export("run").call
139
73
  ```
140
74
 
141
- ## TODO
142
-
143
- - Add support for raw memory access and other types of exports
144
- - Add support for imports
145
- - Implement more of the Wasmtime API
146
- - Add benchmarks for WASM program against ones in pure Ruby and true native
147
- - Add support for WASM Interface Types when they are supported in Wasmtime
75
+ For more, see [examples](https://github.com/bytecodealliance/wasmtime-rb/tree/main/examples)
76
+ or the [API documentation](https://bytecodealliance.github.io/wasmtime-rb/latest/).
data/ext/Cargo.toml ADDED
@@ -0,0 +1,17 @@
1
+ [package]
2
+ name = "ext"
3
+ version = "0.1.0"
4
+ edition = "2018"
5
+ authors = ["Ian Ker-Seymer <hello@ianks.com>"]
6
+ license = "Apache-2.0"
7
+ publish = false
8
+
9
+ [lib]
10
+ crate-type = ["cdylib"]
11
+
12
+ [dependencies]
13
+ lazy_static = "1.4.0"
14
+ magnus = { git = "https://github.com/matsadler/magnus", features = ["rb-sys-interop"] }
15
+ rb-sys = "~0.9.44"
16
+ wasmtime = "3.0.0"
17
+ anyhow = "*" # Use whatever Wasmtime uses
data/ext/extconf.rb ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+ require "rb_sys/mkmf"
5
+
6
+ create_rust_makefile("ext")
@@ -0,0 +1,3 @@
1
+ mod wrapped_struct;
2
+
3
+ pub use wrapped_struct::WrappedStruct;
@@ -0,0 +1,84 @@
1
+ use magnus::{error::Error, exception, gc, value::Value, RTypedData, TryConvert, TypedData};
2
+ use std::{marker::PhantomData, ops::Deref};
3
+
4
+ /// A small wrapper for `RTypedData` that keeps track of the concrete struct
5
+ /// type, and the underlying [`Value`] for GC purposes.
6
+ #[derive(Debug)]
7
+ #[repr(transparent)]
8
+ pub struct WrappedStruct<T: TypedData> {
9
+ inner: RTypedData,
10
+ phantom: PhantomData<T>,
11
+ }
12
+
13
+ impl<T: TypedData> Clone for WrappedStruct<T> {
14
+ fn clone(&self) -> Self {
15
+ Self {
16
+ inner: self.inner,
17
+ phantom: PhantomData,
18
+ }
19
+ }
20
+ }
21
+ impl<T: TypedData> Copy for WrappedStruct<T> {}
22
+
23
+ impl<T: TypedData> WrappedStruct<T> {
24
+ /// Gets the underlying struct.
25
+ pub fn get(&self) -> Result<&T, Error> {
26
+ self.inner.try_convert()
27
+ }
28
+
29
+ /// Get the Ruby [`Value`] for this struct.
30
+ pub fn to_value(self) -> Value {
31
+ self.inner.into()
32
+ }
33
+
34
+ /// Marks the Ruby [`Value`] for GC.
35
+ pub fn mark(&self) {
36
+ gc::mark(&self.inner.into());
37
+ }
38
+ }
39
+
40
+ impl<T: TypedData> From<WrappedStruct<T>> for Value {
41
+ fn from(wrapped_struct: WrappedStruct<T>) -> Self {
42
+ wrapped_struct.to_value()
43
+ }
44
+ }
45
+
46
+ impl<T: TypedData> Deref for WrappedStruct<T> {
47
+ type Target = RTypedData;
48
+
49
+ fn deref(&self) -> &Self::Target {
50
+ &self.inner
51
+ }
52
+ }
53
+
54
+ impl<T: TypedData> From<T> for WrappedStruct<T> {
55
+ fn from(t: T) -> Self {
56
+ Self {
57
+ inner: RTypedData::wrap(t),
58
+ phantom: PhantomData,
59
+ }
60
+ }
61
+ }
62
+
63
+ impl<T> TryConvert for WrappedStruct<T>
64
+ where
65
+ T: TypedData,
66
+ {
67
+ fn try_convert(val: Value) -> Result<Self, Error> {
68
+ let inner = RTypedData::from_value(val).ok_or_else(|| {
69
+ Error::new(
70
+ exception::type_error(),
71
+ format!(
72
+ "no implicit conversion of {} into {}",
73
+ unsafe { val.classname() },
74
+ T::class()
75
+ ),
76
+ )
77
+ })?;
78
+
79
+ Ok(Self {
80
+ inner,
81
+ phantom: PhantomData,
82
+ })
83
+ }
84
+ }
data/ext/src/lib.rs ADDED
@@ -0,0 +1,9 @@
1
+ use magnus::Error;
2
+
3
+ mod helpers;
4
+ mod ruby_api;
5
+
6
+ #[magnus::init]
7
+ fn init() -> Result<(), Error> {
8
+ ruby_api::init()
9
+ }
@@ -0,0 +1,68 @@
1
+ use super::root;
2
+ use magnus::{function, method, Error, Module, Object};
3
+ use std::cell::RefCell;
4
+ use wasmtime::Config as ConfigImpl;
5
+
6
+ /// @yard
7
+ /// Wasmtime {Engine} configuration.
8
+ /// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html Wasmtime's Rust doc
9
+ #[derive(Clone, Debug)]
10
+ #[magnus::wrap(class = "Wasmtime::Config")]
11
+ pub struct Config {
12
+ inner: RefCell<ConfigImpl>,
13
+ }
14
+
15
+ impl Config {
16
+ /// @yard
17
+ /// @return [Config]
18
+ pub fn new() -> Self {
19
+ Self {
20
+ inner: RefCell::new(ConfigImpl::new()),
21
+ }
22
+ }
23
+
24
+ pub fn get(&self) -> ConfigImpl {
25
+ self.inner.borrow().clone()
26
+ }
27
+
28
+ /// @yard
29
+ /// @def epoch_interruption=(enabled)
30
+ /// @param enabled [Boolean]
31
+ pub fn set_epoch_interruption(&self, enabled: bool) {
32
+ self.inner.borrow_mut().epoch_interruption(enabled);
33
+ }
34
+
35
+ /// @yard
36
+ /// @def max_wasm_stack=(size)
37
+ /// @param size [Integer]
38
+ pub fn set_max_wasm_stack(&self, size: usize) {
39
+ self.inner.borrow_mut().max_wasm_stack(size);
40
+ }
41
+
42
+ /// @yard
43
+ /// @def wasm_multi_memory=(enabled)
44
+ /// @param enabled [Boolean]
45
+ pub fn set_wasm_multi_memory(&self, enabled: bool) {
46
+ self.inner.borrow_mut().wasm_multi_memory(enabled);
47
+ }
48
+ }
49
+
50
+ pub fn init() -> Result<(), Error> {
51
+ let class = root().define_class("Config", Default::default())?;
52
+
53
+ class.define_singleton_method("new", function!(Config::new, 0))?;
54
+
55
+ class.define_method(
56
+ "epoch_interruption=",
57
+ method!(Config::set_epoch_interruption, 1),
58
+ )?;
59
+
60
+ class.define_method("max_wasm_stack=", method!(Config::set_max_wasm_stack, 1))?;
61
+
62
+ class.define_method(
63
+ "wasm_multi_memory=",
64
+ method!(Config::set_wasm_multi_memory, 1),
65
+ )?;
66
+
67
+ Ok(())
68
+ }
@@ -0,0 +1,92 @@
1
+ use crate::{err, error};
2
+ use magnus::{Error, TypedData, Value};
3
+ use wasmtime::{ExternRef, Val, ValType};
4
+
5
+ use super::{func::Func, memory::Memory, store::StoreContextValue};
6
+
7
+ pub trait ToRubyValue {
8
+ fn to_ruby_value(&self, store: &StoreContextValue) -> Result<Value, Error>;
9
+ }
10
+
11
+ impl ToRubyValue for Val {
12
+ fn to_ruby_value(&self, store: &StoreContextValue) -> Result<Value, Error> {
13
+ match self {
14
+ Val::I32(i) => Ok(Value::from(*i)),
15
+ Val::I64(i) => Ok(Value::from(*i)),
16
+ Val::F32(f) => Ok(Value::from(f32::from_bits(*f))),
17
+ Val::F64(f) => Ok(Value::from(f64::from_bits(*f))),
18
+ Val::ExternRef(eref) => match eref {
19
+ None => Ok(magnus::QNIL.into()),
20
+ Some(eref) => eref
21
+ .data()
22
+ .downcast_ref::<OnStackValue>()
23
+ .map(|v| v.0)
24
+ .ok_or_else(|| error!("failed to extract externref")),
25
+ },
26
+ Val::FuncRef(funcref) => match funcref {
27
+ None => Ok(magnus::QNIL.into()),
28
+ Some(funcref) => Ok(Func::from_inner(*store, *funcref).into()),
29
+ },
30
+ Val::V128(_) => err!("converting from v128 to Ruby unsupported"),
31
+ }
32
+ }
33
+ }
34
+ pub trait ToWasmVal {
35
+ fn to_wasm_val(&self, ty: &ValType) -> Result<Val, Error>;
36
+ }
37
+
38
+ impl ToWasmVal for Value {
39
+ fn to_wasm_val(&self, ty: &ValType) -> Result<Val, Error> {
40
+ match ty {
41
+ ValType::I32 => Ok(self.try_convert::<i32>()?.into()),
42
+ ValType::I64 => Ok(self.try_convert::<i64>()?.into()),
43
+ ValType::F32 => Ok(self.try_convert::<f32>()?.into()),
44
+ ValType::F64 => Ok(self.try_convert::<f64>()?.into()),
45
+ ValType::ExternRef => {
46
+ let extern_ref_value = match self.is_nil() {
47
+ true => None,
48
+ false => Some(ExternRef::new(OnStackValue::from(*self))),
49
+ };
50
+
51
+ Ok(Val::ExternRef(extern_ref_value))
52
+ }
53
+ ValType::FuncRef => Ok(Val::FuncRef(Some(*self.try_convert::<&Func>()?.inner()))),
54
+ ValType::V128 => err!("converting from Ruby to v128 not supported"),
55
+ }
56
+ }
57
+ }
58
+
59
+ struct OnStackValue(Value);
60
+ impl From<Value> for OnStackValue {
61
+ fn from(v: Value) -> Self {
62
+ Self(v)
63
+ }
64
+ }
65
+ unsafe impl Send for OnStackValue {}
66
+ unsafe impl Sync for OnStackValue {}
67
+
68
+ pub trait ToExtern {
69
+ fn to_extern(&self) -> Result<wasmtime::Extern, Error>;
70
+ }
71
+
72
+ impl ToExtern for Value {
73
+ fn to_extern(&self) -> Result<wasmtime::Extern, Error> {
74
+ if self.is_kind_of(Func::class()) {
75
+ Ok(self.try_convert::<&Func>()?.into())
76
+ } else if self.is_kind_of(Memory::class()) {
77
+ Ok(self.try_convert::<&Memory>()?.into())
78
+ } else {
79
+ Err(Error::new(
80
+ magnus::exception::type_error(),
81
+ format!("unexpected extern: {}", self.inspect()),
82
+ ))
83
+ }
84
+ }
85
+ }
86
+
87
+ pub trait WrapWasmtimeType<'a, T>
88
+ where
89
+ T: TypedData,
90
+ {
91
+ fn wrap_wasmtime_type(&self, store: StoreContextValue<'a>) -> Result<T, Error>;
92
+ }