ruby_wasm 2.5.0.pre.1 → 2.5.1
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.
- 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 | 
             
            }
         |