ruby_wasm 2.5.0.pre.1 → 2.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +13 -9
- data/Cargo.lock +705 -451
- data/Gemfile +1 -1
- data/README.md +12 -19
- data/Rakefile +9 -9
- data/benchmarks/vm_deep_call.rb +2 -2
- data/docs/cheat_sheet.md +8 -8
- data/ext/ruby_wasm/Cargo.toml +6 -5
- data/ext/ruby_wasm/src/lib.rs +208 -7
- data/lib/ruby_wasm/build/executor.rb +4 -0
- data/lib/ruby_wasm/build/product/crossruby.rb +57 -23
- data/lib/ruby_wasm/build/product/libyaml.rb +5 -3
- data/lib/ruby_wasm/build/product/openssl.rb +7 -2
- data/lib/ruby_wasm/build/product/product.rb +3 -3
- data/lib/ruby_wasm/build/product/ruby_source.rb +3 -3
- data/lib/ruby_wasm/build/product/wasi_vfs.rb +1 -39
- data/lib/ruby_wasm/build/product/zlib.rb +5 -3
- data/lib/ruby_wasm/build/target.rb +24 -0
- data/lib/ruby_wasm/build/toolchain.rb +1 -1
- data/lib/ruby_wasm/build.rb +7 -3
- data/lib/ruby_wasm/cli.rb +171 -13
- data/lib/ruby_wasm/feature_set.rb +30 -0
- data/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.command.wasm +0 -0
- data/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.reactor.wasm +0 -0
- data/lib/ruby_wasm/packager/component_adapter.rb +14 -0
- data/lib/ruby_wasm/packager/core.rb +192 -4
- data/lib/ruby_wasm/packager/file_system.rb +20 -17
- data/lib/ruby_wasm/packager.rb +21 -83
- data/lib/ruby_wasm/rake_task.rb +2 -0
- data/lib/ruby_wasm/version.rb +1 -1
- data/lib/ruby_wasm.rb +2 -0
- data/package-lock.json +410 -133
- data/package.json +3 -3
- data/{tasks → rakelib}/ci.rake +3 -3
- data/{tasks → rakelib}/doc.rake +6 -1
- data/{tasks → rakelib}/format.rake +3 -2
- data/{tasks → rakelib}/gem.rake +4 -1
- data/{tasks → rakelib}/packaging.rake +34 -17
- data/{tasks → rakelib}/version.rake +2 -0
- data/sig/ruby_wasm/build.rbs +36 -31
- data/sig/ruby_wasm/cli.rbs +30 -3
- data/sig/ruby_wasm/ext.rbs +28 -3
- data/sig/ruby_wasm/feature_set.rbs +12 -0
- data/sig/ruby_wasm/packager.rbs +44 -7
- metadata +16 -15
- data/builders/wasm32-unknown-emscripten/Dockerfile +0 -43
- data/builders/wasm32-unknown-emscripten/entrypoint.sh +0 -7
- data/builders/wasm32-unknown-wasi/Dockerfile +0 -47
- data/builders/wasm32-unknown-wasi/entrypoint.sh +0 -7
- data/ruby_wasm.gemspec +0 -32
- /data/{tasks → rakelib}/check.rake +0 -0
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -17,17 +17,17 @@ Try ruby.wasm in [TryRuby](https://try.ruby-lang.org/playground#code=puts+RUBY_D
|
|
17
17
|
- [Complete Examples](https://github.com/ruby/ruby.wasm/tree/main/packages/npm-packages/ruby-wasm-wasi/example)
|
18
18
|
- [Community Showcase](https://github.com/ruby/ruby.wasm/wiki/Showcase)
|
19
19
|
|
20
|
-
## Quick Example: Ruby on browser
|
20
|
+
## Quick Example: Ruby on Web browser
|
21
21
|
|
22
22
|
Create and save `index.html` page with the following contents:
|
23
23
|
|
24
24
|
```html
|
25
25
|
<html>
|
26
|
-
<script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.
|
26
|
+
<script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.1/dist/browser.script.iife.js"></script>
|
27
27
|
<script type="text/ruby">
|
28
28
|
require "js"
|
29
29
|
|
30
|
-
puts RUBY_VERSION #
|
30
|
+
puts RUBY_VERSION # (Printed to the Web browser console)
|
31
31
|
JS.global[:document].write "Hello, world!"
|
32
32
|
</script>
|
33
33
|
</html>
|
@@ -35,25 +35,26 @@ Create and save `index.html` page with the following contents:
|
|
35
35
|
|
36
36
|
## Quick Example: How to package your Ruby application as a WASI application
|
37
37
|
|
38
|
-
Dependencies: [
|
38
|
+
Dependencies: [wasmtime](https://github.com/bytecodealliance/wasmtime)
|
39
39
|
|
40
40
|
```console
|
41
|
+
$ gem install ruby_wasm
|
41
42
|
# Download a prebuilt Ruby release
|
42
|
-
$ curl -LO https://github.com/ruby/ruby.wasm/releases/latest/download/ruby-3.
|
43
|
-
$ tar xfz ruby-3.
|
43
|
+
$ curl -LO https://github.com/ruby/ruby.wasm/releases/latest/download/ruby-3.3-wasm32-unknown-wasip1-full.tar.gz
|
44
|
+
$ tar xfz ruby-3.3-wasm32-unknown-wasip1-full.tar.gz
|
44
45
|
|
45
46
|
# Extract ruby binary not to pack itself
|
46
|
-
$ mv 3.
|
47
|
+
$ mv ruby-3.3-wasm32-unknown-wasip1-full/usr/local/bin/ruby ruby.wasm
|
47
48
|
|
48
49
|
# Put your app code
|
49
50
|
$ mkdir src
|
50
51
|
$ echo "puts 'Hello'" > src/my_app.rb
|
51
52
|
|
52
53
|
# Pack the whole directory under /usr and your app dir
|
53
|
-
$
|
54
|
+
$ rbwasm pack ruby.wasm --dir ./src::/src --dir ./ruby-3.3-wasm32-unknown-wasip1-full/usr::/usr -o my-ruby-app.wasm
|
54
55
|
|
55
56
|
# Run the packed scripts
|
56
|
-
$ wasmtime my-ruby-app.wasm
|
57
|
+
$ wasmtime my-ruby-app.wasm /src/my_app.rb
|
57
58
|
Hello
|
58
59
|
```
|
59
60
|
|
@@ -109,8 +110,8 @@ A _build_ is a combination of ruby version, _profile_, and _target_.
|
|
109
110
|
</thead>
|
110
111
|
<tbody>
|
111
112
|
<tr>
|
112
|
-
<td><code>wasm32-unknown-
|
113
|
-
<td>Targeting WASI
|
113
|
+
<td><code>wasm32-unknown-wasip1</code></td>
|
114
|
+
<td>Targeting <a href="https://github.com/WebAssembly/WASI/tree/main/legacy/preview1">WASI Preview1</a> compatible environments <br>(e.g. Node.js, browsers with polyfill, <a href="https://github.com/bytecodealliance/wasmtime">wasmtime</a>, and so on)</td>
|
114
115
|
</tr>
|
115
116
|
<tr>
|
116
117
|
<td><code>wasm32-unknown-emscripten</code></td>
|
@@ -137,14 +138,6 @@ A _build_ is a combination of ruby version, _profile_, and _target_.
|
|
137
138
|
<td><code>full</code></td>
|
138
139
|
<td>All standard extension libraries</td>
|
139
140
|
</tr>
|
140
|
-
<tr>
|
141
|
-
<td><code>*-js</code></td>
|
142
|
-
<td>Enabled JS interoperability, only usable with npm package</td>
|
143
|
-
</tr>
|
144
|
-
<tr>
|
145
|
-
<td><code>*-debug</code></td>
|
146
|
-
<td>With DWARF info and <a href="https://webassembly.github.io/spec/core/appendix/custom.html#name-section" rel="nofollow"><code>name</code> section</a> for debugging</td>
|
147
|
-
</tr>
|
148
141
|
</tbody>
|
149
142
|
</table>
|
150
143
|
|
data/Rakefile
CHANGED
@@ -7,8 +7,7 @@ $LOAD_PATH << File.join(File.dirname(__FILE__), "lib")
|
|
7
7
|
require "bundler/gem_tasks"
|
8
8
|
require "ruby_wasm/rake_task"
|
9
9
|
require "ruby_wasm/packager"
|
10
|
-
|
11
|
-
Dir.glob("tasks/**.rake").each { |f| import f }
|
10
|
+
require "ruby_wasm/cli"
|
12
11
|
|
13
12
|
BUILD_SOURCES = %w[3.3 3.2 head]
|
14
13
|
BUILD_PROFILES = %w[full minimal]
|
@@ -16,7 +15,7 @@ BUILD_PROFILES = %w[full minimal]
|
|
16
15
|
BUILDS =
|
17
16
|
BUILD_SOURCES
|
18
17
|
.product(BUILD_PROFILES)
|
19
|
-
.map { |src, profile| [src, "wasm32-unknown-
|
18
|
+
.map { |src, profile| [src, "wasm32-unknown-wasip1", profile] } +
|
20
19
|
BUILD_SOURCES.map { |src| [src, "wasm32-unknown-emscripten", "full"] }
|
21
20
|
|
22
21
|
NPM_PACKAGES = [
|
@@ -30,25 +29,26 @@ NPM_PACKAGES = [
|
|
30
29
|
name: "ruby-head-wasm-wasi",
|
31
30
|
ruby_version: "head",
|
32
31
|
gemfile: "packages/npm-packages/ruby-wasm-wasi/Gemfile",
|
33
|
-
target: "wasm32-unknown-
|
32
|
+
target: "wasm32-unknown-wasip1"
|
34
33
|
},
|
35
34
|
{
|
36
35
|
name: "ruby-3.3-wasm-wasi",
|
37
36
|
ruby_version: "3.3",
|
38
37
|
gemfile: "packages/npm-packages/ruby-wasm-wasi/Gemfile",
|
39
|
-
target: "wasm32-unknown-
|
38
|
+
target: "wasm32-unknown-wasip1"
|
40
39
|
},
|
41
40
|
{
|
42
41
|
name: "ruby-3.2-wasm-wasi",
|
43
42
|
ruby_version: "3.2",
|
44
43
|
gemfile: "packages/npm-packages/ruby-wasm-wasi/Gemfile",
|
45
|
-
target: "wasm32-unknown-
|
46
|
-
}
|
44
|
+
target: "wasm32-unknown-wasip1"
|
45
|
+
},
|
46
|
+
{ name: "ruby-wasm-wasi", target: "wasm32-unknown-wasip1" }
|
47
47
|
]
|
48
48
|
|
49
49
|
STANDALONE_PACKAGES = [
|
50
|
-
{ name: "ruby", build: "head-wasm32-unknown-
|
51
|
-
{ name: "irb", build: "head-wasm32-unknown-
|
50
|
+
{ name: "ruby", build: "head-wasm32-unknown-wasip1-full" },
|
51
|
+
{ name: "irb", build: "head-wasm32-unknown-wasip1-full" }
|
52
52
|
]
|
53
53
|
|
54
54
|
LIB_ROOT = File.dirname(__FILE__)
|
data/benchmarks/vm_deep_call.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
#
|
3
3
|
# Example runs
|
4
4
|
# $ ruby vm_deep_call.rb
|
5
|
-
# $ RUBY_EXE="wasmtime run --
|
6
|
-
# $ RUBY_EXE="wasmtime run --env RUBY_FIBER_MACHINE_STACK_SIZE=20971520 --
|
5
|
+
# $ RUBY_EXE="wasmtime run --dir /::/ head-wasm32-unknown-wasi-minimal/usr/local/bin/ruby --" ruby vm_deep_call.rb
|
6
|
+
# $ RUBY_EXE="wasmtime run --env RUBY_FIBER_MACHINE_STACK_SIZE=20971520 --dir /::/ head-wasm32-unknown-wasi-minimal/usr/local/bin/ruby --" ruby vm_deep_call.rb
|
7
7
|
|
8
8
|
def vm_rec n
|
9
9
|
vm_rec n - 1 if n > 0
|
data/docs/cheat_sheet.md
CHANGED
@@ -38,7 +38,7 @@ The easiest way to run Ruby on browser is to use `browser.script.iife.js` script
|
|
38
38
|
|
39
39
|
```html
|
40
40
|
<html>
|
41
|
-
<script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.
|
41
|
+
<script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.1/dist/browser.script.iife.js"></script>
|
42
42
|
<script type="text/ruby">
|
43
43
|
require "js"
|
44
44
|
JS.global[:document].write "Hello, world!"
|
@@ -51,8 +51,8 @@ If you want to control Ruby VM from JavaScript, you can use `@ruby/wasm-wasi` pa
|
|
51
51
|
```html
|
52
52
|
<html>
|
53
53
|
<script type="module">
|
54
|
-
import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.
|
55
|
-
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.
|
54
|
+
import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.5.1/dist/browser/+esm";
|
55
|
+
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.1/dist/ruby+stdlib.wasm");
|
56
56
|
const module = await WebAssembly.compileStreaming(response);
|
57
57
|
const { vm } = await DefaultRubyVM(module);
|
58
58
|
|
@@ -69,11 +69,11 @@ If you want to control Ruby VM from JavaScript, you can use `@ruby/wasm-wasi` pa
|
|
69
69
|
|
70
70
|
```html
|
71
71
|
<html>
|
72
|
-
<script src="https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.
|
72
|
+
<script src="https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.5.1/dist/browser.umd.js"></script>
|
73
73
|
<script>
|
74
74
|
const main = async () => {
|
75
75
|
const { DefaultRubyVM } = window["ruby-wasm-wasi"];
|
76
|
-
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.
|
76
|
+
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.1/dist/ruby+stdlib.wasm");
|
77
77
|
const module = await WebAssembly.compileStreaming(response);
|
78
78
|
const { vm } = await DefaultRubyVM(module);
|
79
79
|
|
@@ -128,7 +128,7 @@ end
|
|
128
128
|
|
129
129
|
```html
|
130
130
|
<html>
|
131
|
-
<script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.
|
131
|
+
<script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.1/dist/browser.script.iife.js"></script>
|
132
132
|
<script type="text/ruby" data-eval="async">
|
133
133
|
require "js"
|
134
134
|
|
@@ -143,8 +143,8 @@ Or using `@ruby/wasm-wasi` package API `RubyVM#evalAsync`:
|
|
143
143
|
```html
|
144
144
|
<html>
|
145
145
|
<script type="module">
|
146
|
-
import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.
|
147
|
-
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.
|
146
|
+
import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.5.1/dist/browser/+esm";
|
147
|
+
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.1/dist/ruby+stdlib.wasm");
|
148
148
|
const module = await WebAssembly.compileStreaming(response);
|
149
149
|
const { vm } = await DefaultRubyVM(module);
|
150
150
|
|
data/ext/ruby_wasm/Cargo.toml
CHANGED
@@ -10,8 +10,9 @@ publish = false
|
|
10
10
|
crate-type = ["cdylib"]
|
11
11
|
|
12
12
|
[dependencies]
|
13
|
-
magnus = "0.6.2"
|
14
|
-
|
15
|
-
|
16
|
-
wasi-
|
17
|
-
|
13
|
+
magnus = { version = "0.6.2", features = ["bytes"] }
|
14
|
+
bytes = "1"
|
15
|
+
wizer = "4.0.0"
|
16
|
+
wasi-vfs-cli = { git = "https://github.com/kateinoigakukun/wasi-vfs/", tag = "0.5.2" }
|
17
|
+
structopt = "0.3.26"
|
18
|
+
wit-component = "0.203.0"
|
data/ext/ruby_wasm/src/lib.rs
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
use std::path::PathBuf;
|
1
|
+
use std::{collections::HashMap, path::PathBuf};
|
2
2
|
|
3
3
|
use magnus::{
|
4
4
|
eval, exception, function, method,
|
@@ -6,12 +6,13 @@ use magnus::{
|
|
6
6
|
value::{self, InnerValue},
|
7
7
|
wrap, Error, ExceptionClass, RModule, Ruby,
|
8
8
|
};
|
9
|
+
use structopt::StructOpt;
|
9
10
|
use wizer::Wizer;
|
10
11
|
|
11
12
|
static RUBY_WASM: value::Lazy<RModule> =
|
12
13
|
value::Lazy::new(|ruby| ruby.define_module("RubyWasmExt").unwrap());
|
13
14
|
|
14
|
-
fn preinit(core_module:
|
15
|
+
fn preinit(core_module: bytes::Bytes) -> Result<bytes::Bytes, Error> {
|
15
16
|
let rbwasm_error = eval("RubyWasmExt::Error")?;
|
16
17
|
let rbwasm_error = ExceptionClass::from_value(rbwasm_error).unwrap();
|
17
18
|
let mut wizer = Wizer::new();
|
@@ -25,6 +26,7 @@ fn preinit(core_module: Vec<u8>) -> Result<Vec<u8>, Error> {
|
|
25
26
|
wizer
|
26
27
|
.run(&core_module)
|
27
28
|
.map_err(|e| Error::new(rbwasm_error, format!("failed to run wizer: {}", e)))
|
29
|
+
.map(|output| output.into())
|
28
30
|
}
|
29
31
|
|
30
32
|
struct WasiVfsInner {
|
@@ -35,22 +37,188 @@ struct WasiVfsInner {
|
|
35
37
|
struct WasiVfs(std::cell::RefCell<WasiVfsInner>);
|
36
38
|
|
37
39
|
impl WasiVfs {
|
40
|
+
fn run_cli(args: Vec<String>) -> Result<(), Error> {
|
41
|
+
wasi_vfs_cli::App::from_iter(args).execute().map_err(|e| {
|
42
|
+
Error::new(
|
43
|
+
exception::standard_error(),
|
44
|
+
format!("failed to run wasi vfs cli: {}", e),
|
45
|
+
)
|
46
|
+
})
|
47
|
+
}
|
48
|
+
|
38
49
|
fn new() -> Self {
|
39
50
|
Self(std::cell::RefCell::new(WasiVfsInner { map_dirs: vec![] }))
|
40
51
|
}
|
41
52
|
|
42
53
|
fn map_dir(&self, guest_dir: String, host_dir: String) {
|
43
|
-
self.0
|
54
|
+
self.0
|
55
|
+
.borrow_mut()
|
56
|
+
.map_dirs
|
57
|
+
.push((guest_dir.into(), host_dir.into()));
|
58
|
+
}
|
59
|
+
|
60
|
+
fn pack(&self, wasm_bytes: bytes::Bytes) -> Result<bytes::Bytes, Error> {
|
61
|
+
let output_bytes = wasi_vfs_cli::pack(&wasm_bytes, self.0.borrow().map_dirs.clone())
|
62
|
+
.map_err(|e| {
|
63
|
+
Error::new(
|
64
|
+
exception::standard_error(),
|
65
|
+
format!("failed to pack wasi vfs: {}", e),
|
66
|
+
)
|
67
|
+
})?;
|
68
|
+
Ok(output_bytes.into())
|
44
69
|
}
|
70
|
+
}
|
45
71
|
|
46
|
-
|
47
|
-
|
72
|
+
#[wrap(class = "RubyWasmExt::ComponentLink")]
|
73
|
+
struct ComponentLink(std::cell::RefCell<Option<wit_component::Linker>>);
|
74
|
+
|
75
|
+
impl ComponentLink {
|
76
|
+
fn new() -> Self {
|
77
|
+
Self(std::cell::RefCell::new(Some(
|
78
|
+
wit_component::Linker::default(),
|
79
|
+
)))
|
80
|
+
}
|
81
|
+
fn linker(
|
82
|
+
&self,
|
83
|
+
body: impl FnOnce(wit_component::Linker) -> Result<wit_component::Linker, Error>,
|
84
|
+
) -> Result<(), Error> {
|
85
|
+
let mut linker = self.0.take().ok_or_else(|| {
|
48
86
|
Error::new(
|
49
87
|
exception::standard_error(),
|
50
|
-
|
88
|
+
"linker is already consumed".to_string(),
|
51
89
|
)
|
52
90
|
})?;
|
53
|
-
|
91
|
+
linker = body(linker)?;
|
92
|
+
self.0.replace(Some(linker));
|
93
|
+
Ok(())
|
94
|
+
}
|
95
|
+
|
96
|
+
fn library(&self, name: String, module: bytes::Bytes, dl_openable: bool) -> Result<(), Error> {
|
97
|
+
self.linker(|linker| {
|
98
|
+
linker.library(&name, &module, dl_openable).map_err(|e| {
|
99
|
+
Error::new(
|
100
|
+
exception::standard_error(),
|
101
|
+
format!("failed to link library: {}", e),
|
102
|
+
)
|
103
|
+
})
|
104
|
+
})
|
105
|
+
}
|
106
|
+
fn adapter(&self, name: String, module: bytes::Bytes) -> Result<(), Error> {
|
107
|
+
self.linker(|linker| {
|
108
|
+
linker.adapter(&name, &module).map_err(|e| {
|
109
|
+
Error::new(
|
110
|
+
exception::standard_error(),
|
111
|
+
format!("failed to link adapter: {}", e),
|
112
|
+
)
|
113
|
+
})
|
114
|
+
})
|
115
|
+
}
|
116
|
+
fn validate(&self, validate: bool) -> Result<(), Error> {
|
117
|
+
self.linker(|linker| Ok(linker.validate(validate)))
|
118
|
+
}
|
119
|
+
fn stack_size(&self, size: u32) -> Result<(), Error> {
|
120
|
+
self.linker(|linker| Ok(linker.stack_size(size)))
|
121
|
+
}
|
122
|
+
fn stub_missing_functions(&self, stub: bool) -> Result<(), Error> {
|
123
|
+
self.linker(|linker| Ok(linker.stub_missing_functions(stub)))
|
124
|
+
}
|
125
|
+
fn use_built_in_libdl(&self, use_libdl: bool) -> Result<(), Error> {
|
126
|
+
self.linker(|linker| Ok(linker.use_built_in_libdl(use_libdl)))
|
127
|
+
}
|
128
|
+
fn encode(&self) -> Result<bytes::Bytes, Error> {
|
129
|
+
// Take the linker out of the cell and consume it
|
130
|
+
let linker = self.0.borrow_mut().take().ok_or_else(|| {
|
131
|
+
Error::new(
|
132
|
+
exception::standard_error(),
|
133
|
+
"linker is already consumed".to_string(),
|
134
|
+
)
|
135
|
+
})?;
|
136
|
+
let encoded = linker.encode().map_err(|e| {
|
137
|
+
Error::new(
|
138
|
+
exception::standard_error(),
|
139
|
+
format!("failed to encode linker: {}", e),
|
140
|
+
)
|
141
|
+
})?;
|
142
|
+
Ok(encoded.into())
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
#[wrap(class = "RubyWasmExt::ComponentEncode")]
|
147
|
+
struct ComponentEncode(std::cell::RefCell<Option<wit_component::ComponentEncoder>>);
|
148
|
+
|
149
|
+
impl ComponentEncode {
|
150
|
+
fn new() -> Self {
|
151
|
+
Self(std::cell::RefCell::new(Some(
|
152
|
+
wit_component::ComponentEncoder::default(),
|
153
|
+
)))
|
154
|
+
}
|
155
|
+
|
156
|
+
fn encoder(
|
157
|
+
&self,
|
158
|
+
body: impl FnOnce(
|
159
|
+
wit_component::ComponentEncoder,
|
160
|
+
) -> Result<wit_component::ComponentEncoder, Error>,
|
161
|
+
) -> Result<(), Error> {
|
162
|
+
let mut encoder = self.0.take().ok_or_else(|| {
|
163
|
+
Error::new(
|
164
|
+
exception::standard_error(),
|
165
|
+
"encoder is already consumed".to_string(),
|
166
|
+
)
|
167
|
+
})?;
|
168
|
+
encoder = body(encoder)?;
|
169
|
+
self.0.replace(Some(encoder));
|
170
|
+
Ok(())
|
171
|
+
}
|
172
|
+
|
173
|
+
fn validate(&self, validate: bool) -> Result<(), Error> {
|
174
|
+
self.encoder(|encoder| Ok(encoder.validate(validate)))
|
175
|
+
}
|
176
|
+
|
177
|
+
fn adapter(&self, name: String, module: bytes::Bytes) -> Result<(), Error> {
|
178
|
+
self.encoder(|encoder| {
|
179
|
+
encoder.adapter(&name, &module).map_err(|e| {
|
180
|
+
Error::new(
|
181
|
+
exception::standard_error(),
|
182
|
+
format!("failed to encode adapter: {}", e),
|
183
|
+
)
|
184
|
+
})
|
185
|
+
})
|
186
|
+
}
|
187
|
+
|
188
|
+
fn module(&self, module: bytes::Bytes) -> Result<(), Error> {
|
189
|
+
self.encoder(|encoder| {
|
190
|
+
encoder.module(&module).map_err(|e| {
|
191
|
+
Error::new(
|
192
|
+
exception::standard_error(),
|
193
|
+
format!("failed to encode module: {}", e),
|
194
|
+
)
|
195
|
+
})
|
196
|
+
})
|
197
|
+
}
|
198
|
+
|
199
|
+
fn realloc_via_memory_grow(&self, realloc: bool) -> Result<(), Error> {
|
200
|
+
self.encoder(|encoder| Ok(encoder.realloc_via_memory_grow(realloc)))
|
201
|
+
}
|
202
|
+
|
203
|
+
fn import_name_map(&self, map: HashMap<String, String>) -> Result<(), Error> {
|
204
|
+
self.encoder(|encoder| Ok(encoder.import_name_map(map)))
|
205
|
+
}
|
206
|
+
|
207
|
+
fn encode(&self) -> Result<bytes::Bytes, Error> {
|
208
|
+
// Take the encoder out of the cell and consume it
|
209
|
+
let encoder = self.0.borrow_mut().take().ok_or_else(|| {
|
210
|
+
Error::new(
|
211
|
+
exception::standard_error(),
|
212
|
+
"encoder is already consumed".to_string(),
|
213
|
+
)
|
214
|
+
})?;
|
215
|
+
let encoded = encoder.encode().map_err(|e| {
|
216
|
+
Error::new(
|
217
|
+
exception::standard_error(),
|
218
|
+
format!("failed to encode component: {}", e),
|
219
|
+
)
|
220
|
+
})?;
|
221
|
+
Ok(encoded.into())
|
54
222
|
}
|
55
223
|
}
|
56
224
|
|
@@ -63,7 +231,40 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
63
231
|
|
64
232
|
let wasi_vfs = module.define_class("WasiVfs", ruby.class_object())?;
|
65
233
|
wasi_vfs.define_singleton_method("new", function!(WasiVfs::new, 0))?;
|
234
|
+
wasi_vfs.define_singleton_method("run_cli", function!(WasiVfs::run_cli, 1))?;
|
66
235
|
wasi_vfs.define_method("map_dir", method!(WasiVfs::map_dir, 2))?;
|
67
236
|
wasi_vfs.define_method("pack", method!(WasiVfs::pack, 1))?;
|
237
|
+
|
238
|
+
let component_link = module.define_class("ComponentLink", ruby.class_object())?;
|
239
|
+
component_link.define_singleton_method("new", function!(ComponentLink::new, 0))?;
|
240
|
+
component_link.define_method("library", method!(ComponentLink::library, 3))?;
|
241
|
+
component_link.define_method("adapter", method!(ComponentLink::adapter, 2))?;
|
242
|
+
component_link.define_method("validate", method!(ComponentLink::validate, 1))?;
|
243
|
+
component_link.define_method("stack_size", method!(ComponentLink::stack_size, 1))?;
|
244
|
+
component_link.define_method(
|
245
|
+
"stub_missing_functions",
|
246
|
+
method!(ComponentLink::stub_missing_functions, 1),
|
247
|
+
)?;
|
248
|
+
component_link.define_method(
|
249
|
+
"use_built_in_libdl",
|
250
|
+
method!(ComponentLink::use_built_in_libdl, 1),
|
251
|
+
)?;
|
252
|
+
component_link.define_method("encode", method!(ComponentLink::encode, 0))?;
|
253
|
+
|
254
|
+
let component_encode = module.define_class("ComponentEncode", ruby.class_object())?;
|
255
|
+
component_encode.define_singleton_method("new", function!(ComponentEncode::new, 0))?;
|
256
|
+
component_encode.define_method("validate", method!(ComponentEncode::validate, 1))?;
|
257
|
+
component_encode.define_method("adapter", method!(ComponentEncode::adapter, 2))?;
|
258
|
+
component_encode.define_method("module", method!(ComponentEncode::module, 1))?;
|
259
|
+
component_encode.define_method(
|
260
|
+
"realloc_via_memory_grow",
|
261
|
+
method!(ComponentEncode::realloc_via_memory_grow, 1),
|
262
|
+
)?;
|
263
|
+
component_encode.define_method(
|
264
|
+
"import_name_map",
|
265
|
+
method!(ComponentEncode::import_name_map, 1),
|
266
|
+
)?;
|
267
|
+
component_encode.define_method("encode", method!(ComponentEncode::encode, 0))?;
|
268
|
+
|
68
269
|
Ok(())
|
69
270
|
}
|