Repository: Shopify/ruvy Branch: main Commit: 425f0ada75d8 Files: 45 Total size: 69.0 KB Directory structure: gitextract_yv2v4z6_/ ├── .cargo/ │ └── config.toml ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── config.yml │ │ ├── feature_request.md │ │ └── question.md │ ├── dependabot.yml │ ├── pull_request_template.md │ └── workflows/ │ ├── cargo-vet.yml │ ├── ci.yml │ └── cla.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE.md ├── Makefile ├── README.md ├── crates/ │ ├── cli/ │ │ ├── Cargo.toml │ │ ├── benches/ │ │ │ ├── benchmark.rs │ │ │ └── scripts/ │ │ │ ├── hello_world/ │ │ │ │ └── hello_world.rb │ │ │ └── transformer/ │ │ │ ├── input.json │ │ │ ├── preload/ │ │ │ │ └── transformer.rb │ │ │ ├── ruby_wasm_entry.rb │ │ │ └── ruvy_entry.rb │ │ ├── build.rs │ │ ├── src/ │ │ │ └── main.rs │ │ └── tests/ │ │ └── integration_test.rs │ ├── core/ │ │ ├── Cargo.toml │ │ └── src/ │ │ ├── main.rs │ │ └── runtime.rs │ ├── ruby-wasm-assets/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── lib.rs │ └── wasm-sys/ │ ├── .cargo/ │ │ └── config │ ├── Cargo.toml │ ├── build.rs │ ├── foo.c │ ├── src/ │ │ └── lib.rs │ └── wrapper.h ├── prelude/ │ ├── custom_printer.rb │ └── inspector.rb ├── ruby_examples/ │ ├── hello_world.rb │ └── use_preludes_and_stdin.rb ├── rust-toolchain.toml └── supply-chain/ ├── audits.toml └── config.toml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .cargo/config.toml ================================================ # Cargo doesn't read directives in individual crates when invoking build # commands from the workspace root, hence adding it at the workspace root. # https://doc.rust-lang.org/cargo/reference/config.html. # Disable reference-types since Wizer (as of version 7.0.0) does not support # reference-types. Must be combined with "thin" or "fat" LTO. [target.wasm32-wasip1] rustflags = ["-C", "target-feature=-reference-types"] runner = "wasmtime" ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: File a bug report title: labels: ["bug"] assignees: --- Operating system: ... Processor architecture: ... Rust version: ... Ruvy version (commit hash): ... ## Problem and context ... ## What were you expecting to happen? ... ## What did happen? ... ## Are there steps to reproduce the problem? ... ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: true ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest a feature title: labels: ["feature"] assignees: --- ## Describe your feature ... ## What problem does it solve? ... ================================================ FILE: .github/ISSUE_TEMPLATE/question.md ================================================ --- name: Question about: Questions about Ruvy title: labels: ["question"] assignees: --- ## What is your question? ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "cargo" directory: "/" schedule: interval: "monthly" open-pull-requests-limit: 100 groups: wasmtime: patterns: - "wasmtime*" nonbreaking: update-types: - "minor" - "patch" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "monthly" ================================================ FILE: .github/pull_request_template.md ================================================ ## Description of the change ## Why am I making this change? ================================================ FILE: .github/workflows/cargo-vet.yml ================================================ name: Cargo vet dependencies on: push: branches: - main pull_request: jobs: cargo-vet: name: cargo_vet runs-on: ubuntu-latest env: CARGO_VET_VERSION: 0.9.0 steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 with: path: ${{ runner.tool_cache }}/cargo-vet key: cargo-vet-bin-${{ env.CARGO_VET_VERSION }} - name: Add the tool cache directory to the search path run: echo "${{ runner.tool_cache }}/cargo-vet/bin" >> $GITHUB_PATH - name: Ensure that the tool cache is populated with the cargo-vet binary run: cargo install --root ${{ runner.tool_cache }}/cargo-vet --version ${{ env.CARGO_VET_VERSION }} cargo-vet - name: Invoke cargo-vet run: cargo vet --locked ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: push: branches: - main pull_request: jobs: ci: runs-on: ubuntu-latest steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Install Wasmtime env: WASMTIME_VERSION: 12.0.2 run: | wget -nv https://github.com/bytecodealliance/wasmtime/releases/download/v${WASMTIME_VERSION}/wasmtime-v${WASMTIME_VERSION}-x86_64-linux.tar.xz -O /tmp/wasmtime.tar.xz mkdir /tmp/wasmtime tar xvf /tmp/wasmtime.tar.xz --strip-components=1 -C /tmp/wasmtime echo "/tmp/wasmtime" >> $GITHUB_PATH - name: Compile core run: cargo build --package=core --target=wasm32-wasip1 --release - name: Test core run: cargo test --package=core --target=wasm32-wasip1 --release - name: Test CLI run: cargo test --package=cli -- --nocapture - name: Format checks run: | cargo fmt -- --check cargo clippy --workspace --exclude=cli --exclude=ruby-wasm-assets --target=wasm32-wasip1 --all-targets -- -D clippy::correctness -D clippy::perf -D clippy::suspicious cargo clippy --package=cli --package=ruby-wasm-assets --all-targets -- -D clippy::correctness -D clippy::perf -D clippy::suspicious ================================================ FILE: .github/workflows/cla.yml ================================================ name: Contributor License Agreement (CLA) on: pull_request_target: types: [opened, synchronize] issue_comment: types: [created] jobs: cla: runs-on: ubuntu-latest if: | (github.event.issue.pull_request && !github.event.issue.pull_request.merged_at && contains(github.event.comment.body, 'signed') ) || (github.event.pull_request && !github.event.pull_request.merged) steps: - uses: Shopify/shopify-cla-action@v1 with: github-token: ${{ secrets.GITHUB_TOKEN }} cla-token: ${{ secrets.CLA_TOKEN }} ================================================ FILE: .gitignore ================================================ /target .DS_Store *.wasm wasi-sdk *~ .vscode/ ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: - Demonstrating empathy and kindness toward other people - Being respectful of differing opinions, viewpoints, and experiences - Giving and gracefully accepting constructive feedback - Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience - Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: - The use of sexualized language or imagery, and sexual attention or advances of any kind - Trolling, insulting or derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or email address, without their explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at opensource@shopify.com. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. [homepage]: https://www.contributor-covenant.org [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html [Mozilla CoC]: https://github.com/mozilla/diversity [FAQ]: https://www.contributor-covenant.org/faq [translations]: https://www.contributor-covenant.org/translations ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Ruvy Thank you for contributing to Ruvy! Any contributions to Ruvy are appreciated and encouraged. ## Code of conduct This project and everyone participating in it is govered by the [Code of Conduct document](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behaviour to opensource@shopify.com. ## Creating issues Before submitting issues, please see if there is an existing open issue. If no related issue is found, then please create a new issue. ## Opening pull requests If the change is not trivial, we encourage to open a feature request issue to discuss the change you would like to make before creating a pull request. That way we can align on your approach before you start coding it. ================================================ FILE: Cargo.toml ================================================ [workspace] members = [ "crates/wasm-sys", "crates/core", "crates/cli", "crates/ruby-wasm-assets", ] resolver = "2" [workspace.dependencies] anyhow = "1.0" [profile.release] # Either "thin" or "fat" LTO is required to remove overlong call_indirect table # indexes which aren't compatible with Wizer. lto = true ================================================ FILE: LICENSE.md ================================================ MIT License Copyright 2023-present, Shopify Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ .DEFAULT_GOAL := cli cli: core cargo build --package=cli core: cargo build --package=core --release --target=wasm32-wasip1 tests: test-cli test-core test-cli: cli cargo test --package=cli -- --nocapture test-core: cargo test --package=core --target=wasm32-wasip1 -- --nocapture fmt: fmt-ruby-wasm-assets fmt-wasm-sys fmt-core fmt-cli fmt-ruby-wasm-assets: cargo fmt --package=ruby-wasm-assets -- --check cargo clippy --package=ruby-wasm-assets -- -D clippy::correctness -D clippy::perf -D clippy::suspicious fmt-wasm-sys: cargo fmt --package=ruvy-wasm-sys -- --check cargo clippy --package=ruvy-wasm-sys --target=wasm32-wasip1 -- -D clippy::correctness -D clippy::perf -D clippy::suspicious fmt-core: cargo fmt --package=core -- --check cargo clippy --package=core --target=wasm32-wasip1 --all-targets -- -D clippy::correctness -D clippy::perf -D clippy::suspicious fmt-cli: cargo fmt --package=cli -- --check cargo clippy --package=cli --all-targets -- -D clippy::correctness -D clippy::perf -D clippy::suspicious bench: core cargo bench --package=cli ================================================ FILE: README.md ================================================ # Ruvy: A Ruby to WebAssembly toolchain **This project is no longer maintained** ## About this repo Ruvy aims to initialize the ruby VM using wizer and execute ruby code passed into the wasm. ## Build - [rustup](https://rustup.rs/) - Latest Rust stable version - wasm32-wasip1, can be installed via `rustup target add wasm32-wasip1` - cmake, depending on your operating system and architecture, it might not be installed by default. On Mac it can be installed with `homebrew` via `brew install cmake` - Rosetta 2 if running MacOS on Apple Silicon, can be installed via `softwareupdate --install-rosetta` ## Development - wasmtime-cli, can be installed via `cargo install wasmtime-cli` ### Using a different WASI SDK The following environment variables allow you to experiment with different WASI SDKs: - `RUVY_WASM_SYS_WASI_SDK_MAJOR_VERSION` sets the major version of the WASI SDK to use - `RUVY_WASM_SYS_WASI_SDK_MINOR_VERSION` sets the minor version of the WASI SDK to use - `RUVY_WASM_SYS_WASI_SDK_PATH` allows you to specify a path to WASI SDK to use ### Using a different ruby.wasm Set the `RUVY_WASM_SYS_RUBY_PATH` environment variable to a path containing an extracted release asset from https://github.com/ruby/ruby.wasm. The directory the environment variable is set to must contain an `include` and `lib` directory. ## Building After all the dependencies are installed, run `make` ## Usage A simple ruby program that prints "Hello world" to stdout ``` $ cargo run --package=cli ruby_examples/hello_world.rb $ wasmtime index.wasm Hello world ``` You can preload files by pointing to a directory of ruby files. At the moment, it just naively loads each file 1 by 1. ``` $ cargo run --package=cli -- --preload=prelude/ ruby_examples/use_preludes_and_stdin.rb $ echo "this is my input" | wasmtime index.wasm {:discount_input=>"this is my input", :value=>100.0} ``` ## Ideas for contributions Here are some ideas for welcome contributions! ### Compatibility with Shopify Functions Ruvy is **not** currently compatible with Shopify Functions. This is due to the size of the Wasm modules produced by Ruvy exceeding the maximum size of Wasm modules supported by Shopify Functions. Here are some ideas for how to make Ruvy compatible with Shopify Functions: - Shrinking the size of modules by separating the interpreter into an engine Wasm module which exports memory and functions that can be imported by a Wasm module containing Ruby source code. To see an example of implementing this approach, take a look at https://github.com/bytecodealliance/javy, specifically the [core lib.rs](https://github.com/bytecodealliance/javy/blob/3b02858c4a68c830e8e82a1b15b4c3817ad1a64a/crates/core/src/lib.rs) and [the dynamic wasm generator](https://github.com/bytecodealliance/javy/blob/3b02858c4a68c830e8e82a1b15b4c3817ad1a64a/crates/cli/src/wasm_generator/dynamic.rs). - Investigate and improve performance of Ruvy modules. One approach to consider is using YJIT to output WebAssembly. - Enable exports of named functions from Wasm that call into named functions in Ruby code so multiple functions can be exported. ### Misc - Enable using `require` and Ruby gems. At the present time, using code in the preload directory is the only way to add dependencies and large parts of the standard library are not available. It should be possible to enable `require` to work and to load both code from the standard library and from third party gems that are not native gems. A good example of showing this is fixed would be adding a Ruby example that uses the standard library's `json` library to parse and dump JSON. - Output any error messages from the Ruby VM on the standard error stream. ================================================ FILE: crates/cli/Cargo.toml ================================================ [package] name = "cli" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [[bin]] name = "ruvy" path = "src/main.rs" [dependencies] clap = { version = "4.5.53", features = ["derive"] } anyhow = { workspace = true } tokio = { version = "1", features = ["macros"] } wasmtime = "40" wasmtime-wasi = "40" wasmtime-wizer = { version = "40", features = ["wasmtime"] } [dev-dependencies] criterion = "0.8.1" ruby-wasm-assets = { path = "../ruby-wasm-assets" } [build-dependencies] anyhow = { workspace = true } [[bench]] name = "benchmark" harness = false ================================================ FILE: crates/cli/benches/benchmark.rs ================================================ use std::{ env::consts, ffi::OsStr, fmt::{self, Display}, fs, path::{Path, PathBuf}, process::{Command, ExitStatus}, str, }; use anyhow::{bail, Result}; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use wasmtime::{Engine, Linker, Module, Store}; use wasmtime_wasi::{ p1::WasiP1Ctx, p2::pipe::{MemoryInputPipe, MemoryOutputPipe}, WasiCtxBuilder, }; pub fn criterion_benchmark(c: &mut Criterion) { let engine = Engine::default(); let cases = vec![ WasmCase::new( BuildStrategy::WasiVFSRubyWasm, "benches/scripts/hello_world/hello_world.rb".into(), ) .unwrap(), WasmCase::new( BuildStrategy::Ruvy(None), "benches/scripts/hello_world/hello_world.rb".into(), ) .unwrap(), WasmCase::new( BuildStrategy::WasiVFSRubyWasm, "benches/scripts/transformer/ruby_wasm_entry.rb".into(), ) .unwrap(), WasmCase::new( BuildStrategy::Ruvy(Some("benches/scripts/transformer/preload".into())), "benches/scripts/transformer/ruvy_entry.rb".into(), ) .unwrap(), ]; for case in cases { c.bench_with_input(BenchmarkId::new("compile", &case), &case, |b, script| { b.iter(|| Module::new(&engine, &script.wasm).unwrap()) }); c.bench_with_input(BenchmarkId::new("run", &case), &case, |b, script| { b.iter_with_setup( || script.setup_for_run(&engine).unwrap(), |(linker, module, mut store)| { let instance = linker.instantiate(&mut store, &module).unwrap(); let start_func = instance .get_typed_func::<(), ()>(&mut store, "_start") .unwrap(); start_func.call(&mut store, ()).unwrap() }, ) }); } } criterion_group!(benches, criterion_benchmark); criterion_main!(benches); struct WasmCase { name: String, wasm: Vec, wasi_args: Vec, input: Vec, } impl Display for WasmCase { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.name) } } impl WasmCase { fn new(strategy: BuildStrategy, entrypoint: Entrypoint) -> Result { let name = format!("{}-{}", strategy, entrypoint.parent_dirname); let output_path = cargo_target_tmpdir().join(&name).with_extension("wasm"); let exit_status = strategy.build_wasm(&output_path, &entrypoint)?; if !exit_status.success() { bail!("Failed to build Wasm module"); } let input_file = &entrypoint.input_path; let input = if input_file.exists() { fs::read(input_file)? } else { vec![] }; Ok(Self { name, wasm: fs::read(output_path)?, wasi_args: strategy.wasi_args(&entrypoint), input, }) } fn setup_for_run( &self, engine: &Engine, ) -> Result<(Linker, Module, Store)> { let mut linker = Linker::new(engine); let wasi = WasiCtxBuilder::new() .stdin(MemoryInputPipe::new(self.input[..].to_vec())) .stdout(MemoryOutputPipe::new(usize::MAX)) .stderr(MemoryOutputPipe::new(usize::MAX)) .args(&self.wasi_args) .build_p1(); wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |cx| cx)?; let store = Store::new(engine, wasi); let module = Module::new(engine, &self.wasm)?; Ok((linker, module, store)) } } enum BuildStrategy { WasiVFSRubyWasm, Ruvy(Option), } impl BuildStrategy { fn build_wasm(&self, output_path: &Path, entrypoint: &Entrypoint) -> Result { match self { Self::WasiVFSRubyWasm => { let ruby_wasm = ruby_wasm()?; let wasi_vfs = wasi_vfs()?; Ok(Command::new(wasi_vfs) .arg("pack") .arg(&ruby_wasm) .arg("--mapdir") .arg(format!("/src::{}", entrypoint.parent_path)) // Examples online show mapping the `/usr` directory, however this // breaks when using a `minimal` instead of `full` profile of // ruby.wasm, so we don't map that directory here. .arg("-o") .arg(output_path.as_os_str()) .status()?) } Self::Ruvy(preload) => { let ruvy = env!("CARGO_BIN_EXE_ruvy"); let mut args = vec![entrypoint.path, OsStr::new("-o"), output_path.as_os_str()]; if let Some(preload) = &preload { args.push(OsStr::new("--preload")); args.push(preload.as_os_str()); } Ok(Command::new(ruvy).args(args).status()?) } } } fn wasi_args(&self, entrypoint: &Entrypoint) -> Vec { match self { Self::WasiVFSRubyWasm => vec![ // Not passing `--disable-gems` results in output about `RubyGems`, // `error_highlight`, `did_you_mean`, and `syntax_suggest` not // being loaded. We don't want that and we don't use the gems // anyway, so I'm disabling them. // If we did not want to pass `--disable-gems`, we can use the // `full` profile build of ruby.wasm and map the `/usr` directory. "--disable-gems".into(), PathBuf::from("/src") .join(entrypoint.filename) .to_string_lossy() .to_string(), ], Self::Ruvy(_) => vec![], } } } impl Display for BuildStrategy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}", match self { Self::WasiVFSRubyWasm => "rubywasm", Self::Ruvy(_) => "ruvy", } ) } } struct Entrypoint<'a> { parent_dirname: &'a str, parent_path: &'a str, filename: &'a OsStr, input_path: PathBuf, path: &'a OsStr, } impl<'a> From<&'a str> for Entrypoint<'a> { fn from(value: &'a str) -> Self { let value = Path::new(value); Entrypoint { parent_dirname: value .parent() .unwrap() .file_name() .unwrap() .to_str() .unwrap(), parent_path: value.parent().unwrap().to_str().unwrap(), filename: value.file_name().unwrap(), input_path: value.parent().unwrap().join("input.json"), path: value.as_os_str(), } } } fn cargo_target_tmpdir() -> PathBuf { PathBuf::from(env!("CARGO_TARGET_TMPDIR")) } fn ruby_wasm() -> Result { let tmpdir = cargo_target_tmpdir(); let ruby_wasm_base = ruby_wasm_assets::ruby_wasm_base_name(); let ruby_wasm_dir = tmpdir.join(&ruby_wasm_base); let ruby_wasm = ruby_wasm_dir.join("usr/local/bin/ruby"); if ruby_wasm.exists() { return Ok(ruby_wasm); } let archive = tmpdir.join(format!("{ruby_wasm_base}.tar.gz")); ruby_wasm_assets::download_ruby_wasm(&archive)?; ruby_wasm_assets::extract_tar(&archive, &ruby_wasm_dir, 1)?; Ok(ruby_wasm) } fn wasi_vfs() -> Result { let tmpdir = cargo_target_tmpdir(); const VERSION: &str = "0.4.0"; let wasi_vfs_base = format!("wasi-vfs-{VERSION}"); let directory = tmpdir.join(&wasi_vfs_base); let wasi_vfs = directory.join("wasi-vfs"); if wasi_vfs.exists() { return Ok(wasi_vfs); } let archive = tmpdir.join(format!("{wasi_vfs_base}.tar.gz")); download_wasi_vfs(&archive, VERSION)?; extract_wasi_vfs(&archive, &directory)?; Ok(wasi_vfs) } fn download_wasi_vfs(path: &Path, version: &str) -> Result<()> { let file_suffix = match (consts::OS, consts::ARCH) { ("linux", "x86_64") => "x86_64-unknown-linux-gnu", ("macos", "x86_64") => "x86_64-apple-darwin", ("macos", "aarch64") => "aarch64-apple-darwin", ("windows", "x86_64") => "x86_64-pc-windows-gnu", other => bail!("Unsupported platform tuple {:?}", other), }; ruby_wasm_assets::download(format!("https://github.com/kateinoigakukun/wasi-vfs/releases/download/v{version}/wasi-vfs-cli-{file_suffix}.zip"), path) } fn extract_wasi_vfs(archive: &Path, extract_to: &Path) -> Result<()> { let output = Command::new("unzip") .arg(archive) .arg("-d") .arg(extract_to) .output()?; if !output.status.success() { bail!( "Unpacking wasi-vfs failed: {}", String::from_utf8_lossy(&output.stderr) ); } Ok(()) } ================================================ FILE: crates/cli/benches/scripts/hello_world/hello_world.rb ================================================ puts "Hello world!" ================================================ FILE: crates/cli/benches/scripts/transformer/input.json ================================================ { "n": 1 } ================================================ FILE: crates/cli/benches/scripts/transformer/preload/transformer.rb ================================================ class Transformer def initialize(input) @input = input end def transform @input + '1' end end ================================================ FILE: crates/cli/benches/scripts/transformer/ruby_wasm_entry.rb ================================================ require_relative "preload/transformer.rb" input = STDIN.gets.strip transformer = Transformer.new(input) puts transformer.transform ================================================ FILE: crates/cli/benches/scripts/transformer/ruvy_entry.rb ================================================ input = STDIN.gets.strip transformer = Transformer::new(input) puts transformer.transform ================================================ FILE: crates/cli/build.rs ================================================ use std::{env, fs, path::Path}; use anyhow::Result; fn main() -> Result<()> { let destination = Path::new(&env::var("OUT_DIR")?).join("engine.wasm"); let is_clippy = env::var("CARGO_CFG_FEATURE").is_ok_and(|v| v == "cargo-clippy"); if is_clippy { fs::write(destination, [])?; println!("cargo:warning=using stubbed engine.wasm for static analysis"); } else { println!("cargo:rerun-if-changed=build.rs"); let engine_path = Path::new(env!("CARGO_MANIFEST_DIR")) .join("../../target/wasm32-wasip1/release/core.wasm"); println!("cargo:rerun-if-changed={}", engine_path.to_str().unwrap()); fs::copy(engine_path, destination)?; } Ok(()) } ================================================ FILE: crates/cli/src/main.rs ================================================ use anyhow::Result; use clap::Parser; use std::{fs, path::PathBuf, process}; use wasmtime::{Config, Engine, Linker, Store}; use wasmtime_wasi::{ p1::WasiP1Ctx, p2::pipe::MemoryInputPipe, DirPerms, FilePerms, WasiCtxBuilder, }; use wasmtime_wizer::Wizer; #[derive(Debug, Parser)] #[clap(name = "ruvy_cli", about = "Compile ruby code into a Wasm module.")] struct Opt { /// Path of the Ruby input file. input: PathBuf, /// Path of a directory containing Ruby files to preload to be used by the input file. #[arg(long)] preload: Option, #[arg(short, default_value = "index.wasm")] /// Desired path of the WebAssembly output file. output: PathBuf, } #[tokio::main] async fn main() -> Result<()> { let opt = Opt::parse(); let ruby_code = match fs::read_to_string(&opt.input) { Ok(code) => code, Err(err) => { eprintln!("Error reading Ruby file {}: {}", opt.input.display(), err); process::exit(1); } }; let ruby_engine = include_bytes!(concat!(env!("OUT_DIR"), "/engine.wasm")); let user_wasm = wizen(ruby_engine, &ruby_code, opt.preload).await?; fs::write(opt.output, user_wasm)?; Ok(()) } async fn wizen( ruby_engine: &[u8], ruby_code: &str, preload_path: Option, ) -> Result> { let mut cfg = Config::new(); cfg.async_support(true); let engine = Engine::new(&cfg)?; let mut store = Store::new(&engine, wasi(ruby_code, preload_path)?); let user_wasm = Wizer::new() .run(&mut store, ruby_engine, async |store, module| { let engine = store.engine(); let mut linker = Linker::new(engine); wasmtime_wasi::p1::add_to_linker_async(&mut linker, |cx| cx)?; let instance = linker.instantiate_async(store, module).await?; Ok(instance) }) .await?; Ok(user_wasm) } fn wasi(ruby_code: &str, preload_path: Option) -> Result { let mut wasi_builder = WasiCtxBuilder::new(); wasi_builder .stdin(MemoryInputPipe::new(ruby_code.as_bytes().to_owned())) .inherit_stdout() .inherit_stderr(); if let Some(preload_path) = preload_path { let guest_preload_path = preload_path.to_string_lossy(); wasi_builder .env("RUVY_PRELOAD_PATH", &guest_preload_path) .preopened_dir( &preload_path, &guest_preload_path, DirPerms::READ, FilePerms::READ, ) .map(|_| ())?; } Ok(wasi_builder.build_p1()) } ================================================ FILE: crates/cli/tests/integration_test.rs ================================================ use std::{env, path::Path, process::Command, str}; use anyhow::{bail, Result}; use wasmtime::{Engine, Linker, Module, Store}; use wasmtime_wasi::{ p1::WasiP1Ctx, p2::pipe::{MemoryInputPipe, MemoryOutputPipe}, WasiCtxBuilder, }; #[test] pub fn test_hello_world() -> Result<()> { let wasm_path = wasm_path("hello_world"); run_ruvy(&wasm_path, "../../ruby_examples/hello_world.rb", None)?; let output = run_wasm(&wasm_path, "")?; assert_eq!("Hello world\n", output); Ok(()) } #[test] pub fn test_preludes() -> Result<()> { let wasm_path = wasm_path("preludes"); run_ruvy( &wasm_path, "../../ruby_examples/use_preludes_and_stdin.rb", Some("../../prelude"), )?; let output = run_wasm(&wasm_path, "this is my input")?; assert_eq!( "{:discount_input=>\"this is my input\", :value=>100.0}\n", output ); Ok(()) } struct Context { wasi: WasiP1Ctx, out_stream: MemoryOutputPipe, } impl Context { fn new(input: &[u8]) -> Context { let out_stream = MemoryOutputPipe::new(usize::MAX); Context { wasi: WasiCtxBuilder::new() .stdin(MemoryInputPipe::new(input.to_vec())) .stdout(out_stream.clone()) .build_p1(), out_stream, } } } fn wasm_path(test_name: &str) -> String { format!("{}/{test_name}.wasm", env!("CARGO_TARGET_TMPDIR")) } fn run_ruvy(wasm_path: &str, input_path: &str, preload: Option<&str>) -> Result<()> { let mut args = vec![format!("-o{wasm_path}")]; if let Some(preload) = preload { args.push(format!("--preload={preload}")); } args.push(input_path.to_string()); let status = Command::new(env!("CARGO_BIN_EXE_ruvy")) .args(args) .status()?; if !status.success() { bail!("Failed to execute ruvy"); } Ok(()) } fn run_wasm(wasm_path: impl AsRef, input: &str) -> Result { let engine = Engine::default(); let mut linker = Linker::new(&engine); wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |cx: &mut Context| &mut cx.wasi)?; let mut store = Store::new(&engine, Context::new(input.as_bytes())); let module = Module::from_file(&engine, wasm_path)?; linker .instantiate(&mut store, &module)? .get_typed_func::<(), ()>(&mut store, "_start")? .call(&mut store, ())?; let context = store.into_data(); drop(context.wasi); let output = context.out_stream.contents(); let output = String::from_utf8(output.to_vec())?; Ok(output) } ================================================ FILE: crates/core/Cargo.toml ================================================ [package] name = "core" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] ruvy-wasm-sys = { path = "../wasm-sys" } anyhow = { workspace = true } ================================================ FILE: crates/core/src/main.rs ================================================ mod runtime; use runtime::cleanup_ruby; use std::{env, io, sync::OnceLock}; static USER_CODE: OnceLock = OnceLock::new(); fn main() { let code = USER_CODE.get().unwrap(); runtime::eval(code).unwrap(); cleanup_ruby().unwrap(); } #[export_name = "wizer-initialize"] pub extern "C" fn load_user_code() { let _wasm_ctx = WasmCtx::new(); runtime::init_ruby(); if let Ok(preload_path) = env::var("RUVY_PRELOAD_PATH") { runtime::preload_files(preload_path); } let contents = io::read_to_string(io::stdin()).unwrap(); USER_CODE.set(contents).unwrap(); } // RAII abstraction for calling Wasm ctors and dtors for exported non-main functions. struct WasmCtx; impl WasmCtx { #[must_use = "Failing to assign the return value will result in the wasm dtors being run immediately"] fn new() -> Self { unsafe { __wasm_call_ctors() }; Self } } impl Drop for WasmCtx { fn drop(&mut self) { unsafe { __wasm_call_dtors() }; } } extern "C" { // `__wasm_call_ctors` is generated by `wasm-ld` and invokes all of the global constructors. // In a Rust bin crate, the `_start` function will invoke this implicitly but no other exported // Wasm functions will invoke this. // If this is not invoked, access to environment variables and directory preopens will not be // available. // This should only be invoked at the start of exported Wasm functions that are not the `main` // function. // References: // - [Rust 1.67.0 stopped initializing the WASI environment for exported functions](https://github.com/rust-lang/rust/issues/107635) // - [Wizer header in Fastly's JS compute runtime](https://github.com/fastly/js-compute-runtime/blob/main/runtime/js-compute-runtime/third_party/wizer.h#L92) fn __wasm_call_ctors(); fn __wasm_call_dtors(); } ================================================ FILE: crates/core/src/runtime.rs ================================================ use std::fs; use anyhow::{anyhow, bail, Result}; use ruvy_wasm_sys::{rb_eval_string_protect, ruby_init, ruby_init_loadpath, VALUE}; use std::{ffi::CString, os::raw::c_char}; pub fn init_ruby() { unsafe { ruby_init(); ruby_init_loadpath(); } } pub fn eval(code: &str) -> Result { let c_code = CString::new(code)?; let mut state: i32 = 0; let result = unsafe { rb_eval_string_protect(c_code.as_ptr() as *const c_char, &mut state as *mut i32) }; if state == 0 { Ok(result) } else { Err(anyhow!("Error evaluating Ruby code. State: {}", state)) } } pub fn preload_files(path: String) { let entries = fs::read_dir(path).unwrap(); entries .map(|r| r.map(|d| d.path())) .filter(|r| r.is_ok() && r.as_deref().unwrap().is_file()) .for_each(|e| { let prelude_contents = fs::read_to_string(e.unwrap()).unwrap(); eval(&prelude_contents).unwrap(); }); } pub fn cleanup_ruby() -> Result<()> { const EXPECTED_SUCCESS_RET_VAL: i32 = 0; // ruby_cleanup expects an integer as an argument that will be returned if it ran successfully. let cleanup_status = unsafe { ruvy_wasm_sys::ruby_cleanup(EXPECTED_SUCCESS_RET_VAL) }; if cleanup_status != EXPECTED_SUCCESS_RET_VAL { bail!("ruby_cleanup did not run successfully. Return value: {cleanup_status}"); } Ok(()) } #[cfg(test)] mod tests { use super::*; use ruvy_wasm_sys::rb_num2int; #[test] fn test_int() { init_ruby(); let result = unsafe { rb_num2int(eval("1 + 1").unwrap()) }; assert_eq!(result, 2); } } ================================================ FILE: crates/ruby-wasm-assets/Cargo.toml ================================================ [package] name = "ruby-wasm-assets" version = "0.1.0" edition = "2021" [dependencies] anyhow = { workspace = true } http-body-util = "0.1.3" hyper = "1.8" hyper-tls = "0.6.0" hyper-util = { version = "0.1.19", features = ["http1"] } lazy_static = "1.5.0" tokio = { version = "1.48.0", features = ["rt"] } ================================================ FILE: crates/ruby-wasm-assets/src/lib.rs ================================================ use std::{ fs::{self, File}, io::Write, path::Path, process::Command, }; use anyhow::{anyhow, bail, Error, Result}; use http_body_util::{combinators::BoxBody, BodyExt}; use hyper::{ body::{Bytes, Incoming}, Response, }; use hyper_tls::HttpsConnector; use hyper_util::{client::legacy::Client, rt::TokioExecutor}; use lazy_static::lazy_static; use tokio::runtime::Runtime; const RUBY_WASM_VERSION: &str = "2.1.0"; const RUBY_WASM_RUBY_VERSION: &str = "3_2"; const RUBY_WASM_TARGET: &str = "wasm32-unknown-wasi"; const RUBY_WASM_PROFILE: &str = "minimal"; lazy_static! { static ref RT: Runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap(); } pub fn download(uri: String, path: &Path) -> Result<()> { RT.block_on(download_async(uri, path)) } async fn download_async(mut uri: String, path: &Path) -> Result<()> { let file_being_downloaded = path.file_name().unwrap().to_str().unwrap(); if !path.try_exists()? { let client = Client::builder(TokioExecutor::new()) .build::<_, BoxBody>(HttpsConnector::new()); let mut response: Response = loop { let response = client.get(uri.try_into()?).await?; let status = response.status(); if status.is_redirection() { uri = response.headers().get("Location").ok_or_else(|| anyhow!("Received redirect without location header when downloading {file_being_downloaded} from GitHub"))?.to_str()?.to_string(); } else if !status.is_success() { bail!("Received {status} when downloading from {file_being_downloaded}"); } else { break response; } }; let mut file = File::create(path)?; while let Some(next) = response.frame().await { let frame = next?; if let Some(chunk) = frame.data_ref() { file.write_all(chunk.as_ref())?; } } } Ok(()) } pub fn ruby_wasm_base_name() -> String { format!( "{}-ruby-{}-{}-{}", RUBY_WASM_VERSION, RUBY_WASM_RUBY_VERSION, RUBY_WASM_TARGET, RUBY_WASM_PROFILE ) } pub fn download_ruby_wasm(path: &Path) -> Result<()> { download(format!("https://github.com/ruby/ruby.wasm/releases/download/{RUBY_WASM_VERSION}/ruby-{RUBY_WASM_RUBY_VERSION}-{RUBY_WASM_TARGET}-{RUBY_WASM_PROFILE}.tar.gz"), path) } pub fn extract_tar(archive: &Path, extract_to: &Path, components_to_strip: i32) -> Result<()> { if !extract_to.exists() { fs::create_dir(extract_to)?; } let output = Command::new("tar") .args([ "-xf", archive.to_str().unwrap(), "--strip-components", &components_to_strip.to_string(), ]) .current_dir(extract_to) .output()?; if !output.status.success() { bail!( "Unpacking {} failed: {}", archive.to_string_lossy(), String::from_utf8_lossy(&output.stderr) ); } Ok(()) } ================================================ FILE: crates/wasm-sys/.cargo/config ================================================ [build] target = "wasm32-wasip1" ================================================ FILE: crates/wasm-sys/Cargo.toml ================================================ [package] name = "ruvy-wasm-sys" version = "0.1.0" edition = "2021" [build-dependencies] anyhow = { workspace = true } bindgen = "0.72.1" cc = "1.2" ruby-wasm-assets = { path = "../ruby-wasm-assets" } ================================================ FILE: crates/wasm-sys/build.rs ================================================ use anyhow::{bail, Result}; use std::{env, fs, path::PathBuf}; const WASI_SDK_VERSION_MAJOR: usize = 20; const WASI_SDK_VERSION_MINOR: usize = 0; fn main() -> Result<()> { let wasi_sdk_path = wasi_sdk_path()?; let wasi_sdk_path = wasi_sdk_path.to_string_lossy(); let sysroot = format!("--sysroot={}/share/wasi-sysroot", &wasi_sdk_path); let sysroot_lib = format!("{}/share/wasi-sysroot/lib/wasm32-wasi", &wasi_sdk_path); let ruby_wasm_dir = ruby_wasm_path()?; let lib_dir = ruby_wasm_dir.join("lib"); let include_dir = ruby_wasm_dir.join("include"); let include_dir = fs::read_dir(include_dir)? .find(|e| { e.as_ref() .unwrap() .file_name() .to_str() .unwrap() .starts_with("ruby-") }) .unwrap()? .path(); let include_config_dir = include_dir.join("wasm32-wasi"); env::set_var("CC", format!("{}/bin/clang", &wasi_sdk_path)); env::set_var("LD", format!("{}/bin/clang", &wasi_sdk_path)); env::set_var("AR", format!("{}/bin/ar", &wasi_sdk_path)); env::set_var("CFLAGS", &sysroot); // Ruby lib directory println!("cargo:rustc-link-search={}", lib_dir.display()); // WASI Sysroot directory println!("cargo:rustc-link-search={}", sysroot_lib); cc::Build::new() .file("foo.c") .flag_if_supported("-fdeclspec") .cargo_metadata(true) .include(&include_dir) .include(&include_config_dir) .target("wasm32-wasip1") .compile("ruvy"); let bindings = bindgen::Builder::default() .header("wrapper.h") .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) .clang_args(&[ "-fvisibility=default", "--target=wasm32-wasip1", &sysroot, &format!("-I{}", include_dir.display()), &format!("-I{}", include_config_dir.display()), ]) .generate() .unwrap(); println!("cargo:rustc-link-lib=static=ruby-static"); println!("cargo:rustc-link-lib=static=m"); println!("cargo:rustc-link-lib=static=wasi-emulated-signal"); println!("cargo:rustc-link-lib=static=wasi-emulated-mman"); println!("cargo:rustc-link-lib=static=wasi-emulated-process-clocks"); println!("cargo:rustc-link-lib=static=c"); println!("cargo:rustc-link-lib=static=crypt"); println!("cargo:rustc-link-lib=static=pthread"); println!("cargo:rustc-link-lib=static=rt"); println!("cargo:rustc-link-lib=static=dl"); println!("cargo:rustc-link-lib=static=resolv"); println!("cargo:rustc-link-lib=static=util"); println!("cargo:rerun-if-changed=build.rs"); let out_dir = PathBuf::from(env::var("OUT_DIR")?); bindings.write_to_file(out_dir.join("bindings.rs"))?; Ok(()) } fn wasi_sdk_path() -> Result { const WASI_SDK_PATH_ENV_VAR: &str = "RUVY_WASM_SYS_WASI_SDK_PATH"; println!("cargo:rerun-if-env-changed={WASI_SDK_PATH_ENV_VAR}"); if let Ok(path) = env::var(WASI_SDK_PATH_ENV_VAR) { return Ok(path.into()); } download_wasi_sdk() } fn download_wasi_sdk() -> Result { let mut wasi_sdk_dir: PathBuf = env::var("OUT_DIR")?.into(); wasi_sdk_dir.push("wasi-sdk"); fs::create_dir_all(&wasi_sdk_dir)?; const MAJOR_VERSION_ENV_VAR: &str = "RUVY_WASM_SYS_WASI_SDK_MAJOR_VERSION"; const MINOR_VERSION_ENV_VAR: &str = "RUVY_WASM_SYS_WASI_SDK_MINOR_VERSION"; println!("cargo:rerun-if-env-changed={MAJOR_VERSION_ENV_VAR}"); println!("cargo:rerun-if-env-changed={MINOR_VERSION_ENV_VAR}"); let major_version = env::var(MAJOR_VERSION_ENV_VAR).unwrap_or(WASI_SDK_VERSION_MAJOR.to_string()); let minor_version = env::var(MINOR_VERSION_ENV_VAR).unwrap_or(WASI_SDK_VERSION_MINOR.to_string()); let mut archive_path = wasi_sdk_dir.clone(); archive_path.push(format!("wasi-sdk-{major_version}-{minor_version}.tar.gz")); let file_suffix = match (env::consts::OS, env::consts::ARCH) { ("linux", "x86") | ("linux", "x86_64") => "linux", ("macos", "x86") | ("macos", "x86_64") | ("macos", "aarch64") => "macos", ("windows", "x86") => "mingw-x86", ("windows", "x86_64") => "mingw", other => bail!("Unsupported platform tuple {:?}", other), }; let uri = format!("https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-{major_version}/wasi-sdk-{major_version}.{minor_version}-{file_suffix}.tar.gz"); ruby_wasm_assets::download(uri, &archive_path)?; ruby_wasm_assets::extract_tar(&archive_path, &wasi_sdk_dir, 1)?; Ok(wasi_sdk_dir) } fn ruby_wasm_path() -> Result { const RUBY_WASM_PATH_ENV_VAR: &str = "RUVY_WASM_SYS_RUBY_PATH"; println!("cargo:rerun-if-env-changed={RUBY_WASM_PATH_ENV_VAR}"); if let Ok(path) = env::var(RUBY_WASM_PATH_ENV_VAR) { return Ok(path.into()); } println!( "cargo:warning=RUVY_WASM_SYS_RUBY_PATH variable was not set. \ Attempting to download and install default ruby.wasm" ); download_ruby_wasm() } fn download_ruby_wasm() -> Result { let mut ruby_wasm_dir: PathBuf = env::var("OUT_DIR")?.into(); ruby_wasm_dir.push("ruby-wasm"); fs::create_dir_all(&ruby_wasm_dir)?; let mut archive_path = ruby_wasm_dir.clone(); let ruby_wasm_version = ruby_wasm_assets::ruby_wasm_base_name(); archive_path.push(&ruby_wasm_version); archive_path.set_extension("tar.gz"); ruby_wasm_assets::download_ruby_wasm(&archive_path)?; // Need to strip archive name, `usr`, and `local`. ruby_wasm_assets::extract_tar(&archive_path, &ruby_wasm_dir, 3)?; println!( "cargo:warning={} installed at {}", ruby_wasm_version, ruby_wasm_dir.display() ); Ok(ruby_wasm_dir) } ================================================ FILE: crates/wasm-sys/foo.c ================================================ #include "./wrapper.h" #include // XXX https://github.com/WebAssembly/wasi-libc/commit/659ff414560721b1660a19685110e484a081c3d4 pid_t getpid(void) { // Return an arbitrary value, greater than 1 which is special. return 42; } void asyncify_stop_rewind() { } void asyncify_start_unwind(int x) { } ================================================ FILE: crates/wasm-sys/src/lib.rs ================================================ #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(warnings)] #![allow(clippy::all)] include!(concat!(env!("OUT_DIR"), "/bindings.rs")); ================================================ FILE: crates/wasm-sys/wrapper.h ================================================ #include ================================================ FILE: prelude/custom_printer.rb ================================================ def custom_print(input) puts input end ================================================ FILE: prelude/inspector.rb ================================================ module Inspector class << self def inspect(input) input.inspect end end end ================================================ FILE: ruby_examples/hello_world.rb ================================================ puts "Hello world" ================================================ FILE: ruby_examples/use_preludes_and_stdin.rb ================================================ input = STDIN.gets.strip class Discount attr_reader :input def initialize(input) @input = input end end output = { discount_input: Discount.new(input).input, value: 100.0 } custom_print(Inspector.inspect(output)) ================================================ FILE: rust-toolchain.toml ================================================ [toolchain] channel = "1.92.0" components = ["clippy", "rustfmt"] targets = ["wasm32-wasip1"] profile = "default" ================================================ FILE: supply-chain/audits.toml ================================================ # cargo-vet audits file [audits] [[trusted.aho-corasick]] criteria = "safe-to-deploy" user-id = 189 # Andrew Gallant (BurntSushi) start = "2019-03-28" end = "2024-10-03" [[trusted.ambient-authority]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2021-04-14" end = "2024-09-21" [[trusted.anstream]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2023-03-16" end = "2024-12-01" [[trusted.anstyle]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2022-05-18" end = "2024-10-03" [[trusted.anstyle-parse]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2023-03-08" end = "2024-12-01" [[trusted.anstyle-query]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2023-04-13" end = "2024-12-01" [[trusted.anstyle-wincon]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2023-03-08" end = "2024-12-01" [[trusted.anyhow]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-10-05" end = "2025-11-04" [[trusted.async-trait]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-07-23" end = "2026-12-01" [[trusted.byteorder]] criteria = "safe-to-deploy" user-id = 189 # Andrew Gallant (BurntSushi) start = "2019-06-09" end = "2024-10-03" [[trusted.bytes]] criteria = "safe-to-deploy" user-id = 6741 # Alice Ryhl (Darksonn) start = "2021-01-11" end = "2026-04-07" [[trusted.cap-fs-ext]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2020-12-11" end = "2026-03-03" [[trusted.cap-net-ext]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2023-04-07" end = "2025-01-03" [[trusted.cap-primitives]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2020-08-07" end = "2026-03-03" [[trusted.cap-rand]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2020-09-24" end = "2026-03-03" [[trusted.cap-std]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2020-06-25" end = "2026-03-03" [[trusted.cap-time-ext]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2020-09-21" end = "2026-03-03" [[trusted.cc]] criteria = "safe-to-deploy" user-id = 2915 # Amanieu d'Antras (Amanieu) start = "2024-02-20" end = "2025-03-01" [[trusted.cc]] criteria = "safe-to-deploy" user-id = 55123 # rust-lang-owner start = "2022-10-29" end = "2026-07-02" [[trusted.clap]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2021-12-08" end = "2026-01-06" [[trusted.clap_builder]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2023-03-28" end = "2026-12-01" [[trusted.clap_derive]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2021-12-08" end = "2026-02-03" [[trusted.clap_lex]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2022-04-15" end = "2026-01-06" [[trusted.cranelift-bitset]] criteria = "safe-to-deploy" user-id = 73222 # wasmtime-publish start = "2024-07-22" end = "2025-09-16" [[trusted.cxx]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-12-28" end = "2025-11-01" [[trusted.cxx-build]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2020-04-30" end = "2025-11-01" [[trusted.cxxbridge-flags]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2020-08-30" end = "2025-11-01" [[trusted.cxxbridge-macro]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2020-01-08" end = "2025-11-01" [[trusted.equivalent]] criteria = "safe-to-deploy" user-id = 539 # Josh Stone (cuviper) start = "2023-02-05" end = "2025-01-02" [[trusted.errno]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2023-08-29" end = "2025-01-03" [[trusted.fs-set-times]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2020-09-15" end = "2026-12-01" [[trusted.hashbrown]] criteria = "safe-to-deploy" user-id = 2915 # Amanieu d'Antras (Amanieu) start = "2019-04-02" end = "2025-01-02" [[trusted.hashbrown]] criteria = "safe-to-deploy" user-id = 55123 # rust-lang-owner start = "2025-04-30" end = "2026-12-01" [[trusted.http]] criteria = "safe-to-deploy" user-id = 359 # Sean McArthur (seanmonstar) start = "2019-04-05" end = "2024-09-21" [[trusted.http-body-util]] criteria = "safe-to-deploy" user-id = 359 # Sean McArthur (seanmonstar) start = "2022-10-25" end = "2025-04-01" [[trusted.httparse]] criteria = "safe-to-deploy" user-id = 359 # Sean McArthur (seanmonstar) start = "2019-07-03" end = "2026-04-07" [[trusted.hyper]] criteria = "safe-to-deploy" user-id = 359 # Sean McArthur (seanmonstar) start = "2019-03-01" end = "2026-04-07" [[trusted.hyper-tls]] criteria = "safe-to-deploy" user-id = 359 # Sean McArthur (seanmonstar) start = "2019-03-19" end = "2024-09-21" [[trusted.hyper-util]] criteria = "safe-to-deploy" user-id = 359 # Sean McArthur (seanmonstar) start = "2022-01-15" end = "2026-04-07" [[trusted.indexmap]] criteria = "safe-to-deploy" user-id = 539 # Josh Stone (cuviper) start = "2020-01-15" end = "2026-12-01" [[trusted.io-extras]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2021-11-09" end = "2026-03-03" [[trusted.io-lifetimes]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2021-06-12" end = "2024-09-21" [[trusted.is-terminal]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2022-01-22" end = "2024-09-21" [[trusted.itoa]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-05-02" end = "2024-09-21" [[trusted.jobserver]] criteria = "safe-to-deploy" user-id = 1 # Alex Crichton (alexcrichton) start = "2019-03-15" end = "2024-09-21" [[trusted.js-sys]] criteria = "safe-to-deploy" user-id = 1 # Alex Crichton (alexcrichton) start = "2019-03-04" end = "2025-01-03" [[trusted.lazy_static]] criteria = "safe-to-deploy" user-id = 539 # Josh Stone (cuviper) start = "2024-06-21" end = "2025-07-02" [[trusted.libc]] criteria = "safe-to-deploy" user-id = 51017 start = "2020-03-17" end = "2025-05-01" [[trusted.libc]] criteria = "safe-to-deploy" user-id = 55123 # rust-lang-owner start = "2024-08-15" end = "2026-08-01" [[trusted.libm]] criteria = "safe-to-deploy" user-id = 2915 # Amanieu d'Antras (Amanieu) start = "2022-02-06" end = "2025-09-16" [[trusted.libm]] criteria = "safe-to-deploy" user-id = 55123 # rust-lang-owner start = "2024-10-26" end = "2026-12-01" [[trusted.linux-raw-sys]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2021-06-12" end = "2026-03-03" [[trusted.memchr]] criteria = "safe-to-deploy" user-id = 189 # Andrew Gallant (BurntSushi) start = "2019-07-07" end = "2024-10-03" [[trusted.num_cpus]] criteria = "safe-to-deploy" user-id = 359 # Sean McArthur (seanmonstar) start = "2019-06-10" end = "2024-09-21" [[trusted.paste]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-03-19" end = "2024-09-21" [[trusted.prettyplease]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2022-01-04" end = "2024-10-27" [[trusted.proc-macro2]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-04-23" end = "2026-12-01" [[trusted.quote]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-04-09" end = "2026-12-01" [[trusted.regex]] criteria = "safe-to-deploy" user-id = 189 # Andrew Gallant (BurntSushi) start = "2019-02-27" end = "2024-10-03" [[trusted.regex-automata]] criteria = "safe-to-deploy" user-id = 189 # Andrew Gallant (BurntSushi) start = "2019-02-25" end = "2024-10-03" [[trusted.regex-syntax]] criteria = "safe-to-deploy" user-id = 189 # Andrew Gallant (BurntSushi) start = "2019-03-30" end = "2024-10-03" [[trusted.rustix]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2021-10-29" end = "2026-03-03" [[trusted.rustversion]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-07-08" end = "2025-11-01" [[trusted.ryu]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-05-02" end = "2024-09-21" [[trusted.scopeguard]] criteria = "safe-to-deploy" user-id = 2915 # Amanieu d'Antras (Amanieu) start = "2020-02-16" end = "2024-09-21" [[trusted.scratch]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2020-09-17" end = "2025-11-01" [[trusted.semver]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2021-05-25" end = "2026-12-01" [[trusted.serde]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-03-01" end = "2026-03-03" [[trusted.serde_core]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2025-09-13" end = "2026-12-01" [[trusted.serde_derive]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-03-01" end = "2026-03-03" [[trusted.serde_json]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-02-28" end = "2024-09-21" [[trusted.serde_spanned]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2023-01-20" end = "2025-05-01" [[trusted.serde_yaml]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-05-02" end = "2026-12-01" [[trusted.slab]] criteria = "safe-to-deploy" user-id = 6741 # Alice Ryhl (Darksonn) start = "2021-10-13" end = "2026-08-01" [[trusted.smallvec]] criteria = "safe-to-deploy" user-id = 2017 # Matt Brubeck (mbrubeck) start = "2019-10-28" end = "2026-03-12" [[trusted.socket2]] criteria = "safe-to-deploy" user-id = 6025 # Thomas de Zeeuw (Thomasdezeeuw) start = "2020-09-09" end = "2026-08-01" [[trusted.syn]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-03-01" end = "2026-03-03" [[trusted.system-interface]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2020-10-27" end = "2026-12-01" [[trusted.target-lexicon]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) start = "2019-03-06" end = "2026-03-03" [[trusted.termcolor]] criteria = "safe-to-deploy" user-id = 189 # Andrew Gallant (BurntSushi) start = "2019-06-04" end = "2024-10-03" [[trusted.thiserror]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-10-09" end = "2026-09-05" [[trusted.thiserror-impl]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-10-09" end = "2026-09-05" [[trusted.tokio]] criteria = "safe-to-deploy" user-id = 6741 # Alice Ryhl (Darksonn) start = "2020-12-25" end = "2026-02-03" [[trusted.tokio]] criteria = "safe-to-deploy" user-id = 10 start = "2019-03-02" end = "2025-06-03" [[trusted.tokio-macros]] criteria = "safe-to-deploy" user-id = 6741 # Alice Ryhl (Darksonn) start = "2020-10-26" end = "2026-12-01" [[trusted.toml]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2022-12-14" end = "2026-12-01" [[trusted.toml_datetime]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2022-10-21" end = "2026-12-01" [[trusted.toml_edit]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2021-09-13" end = "2025-05-01" [[trusted.toml_parser]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2025-07-08" end = "2026-12-01" [[trusted.toml_writer]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2025-07-08" end = "2026-12-01" [[trusted.unicase]] criteria = "safe-to-deploy" user-id = 359 # Sean McArthur (seanmonstar) start = "2019-03-05" end = "2024-09-21" [[trusted.unicode-ident]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2021-10-02" end = "2024-09-21" [[trusted.unsafe-libyaml]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2022-07-03" end = "2026-12-01" [[trusted.walkdir]] criteria = "safe-to-deploy" user-id = 189 # Andrew Gallant (BurntSushi) start = "2019-06-09" end = "2024-10-03" [[trusted.want]] criteria = "safe-to-deploy" user-id = 359 # Sean McArthur (seanmonstar) start = "2019-03-19" end = "2024-09-21" [[trusted.wasm-bindgen]] criteria = "safe-to-deploy" user-id = 1 # Alex Crichton (alexcrichton) start = "2019-03-04" end = "2025-01-03" [[trusted.wasm-bindgen-backend]] criteria = "safe-to-deploy" user-id = 1 # Alex Crichton (alexcrichton) start = "2019-03-04" end = "2025-01-03" [[trusted.wasm-bindgen-macro]] criteria = "safe-to-deploy" user-id = 1 # Alex Crichton (alexcrichton) start = "2019-03-04" end = "2025-01-03" [[trusted.wasm-bindgen-macro-support]] criteria = "safe-to-deploy" user-id = 1 # Alex Crichton (alexcrichton) start = "2019-03-04" end = "2025-01-03" [[trusted.wasm-bindgen-shared]] criteria = "safe-to-deploy" user-id = 1 # Alex Crichton (alexcrichton) start = "2019-03-04" end = "2025-01-03" [[trusted.wasm-encoder]] criteria = "safe-to-deploy" user-id = 73222 # wasmtime-publish start = "2024-02-15" end = "2025-05-01" [[trusted.wasmparser]] criteria = "safe-to-deploy" user-id = 73222 # wasmtime-publish start = "2024-02-15" end = "2025-05-01" [[trusted.wasmprinter]] criteria = "safe-to-deploy" user-id = 73222 # wasmtime-publish start = "2024-02-15" end = "2025-05-01" [[trusted.wasmtime-slab]] criteria = "safe-to-deploy" user-id = 73222 # wasmtime-publish start = "2024-03-20" end = "2025-05-01" [[trusted.wasmtime-versioned-export-macros]] criteria = "safe-to-deploy" user-id = 73222 # wasmtime-publish start = "2023-08-21" end = "2026-03-03" [[trusted.wast]] criteria = "safe-to-deploy" user-id = 73222 # wasmtime-publish start = "2024-02-15" end = "2025-05-01" [[trusted.wat]] criteria = "safe-to-deploy" user-id = 73222 # wasmtime-publish start = "2024-02-15" end = "2025-05-01" [[trusted.winapi-util]] criteria = "safe-to-deploy" user-id = 189 # Andrew Gallant (BurntSushi) start = "2020-01-11" end = "2024-10-03" [[trusted.windows-core]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2021-11-15" end = "2025-01-03" [[trusted.windows-link]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2024-07-17" end = "2026-09-05" [[trusted.windows-sys]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2021-11-15" end = "2026-09-05" [[trusted.windows-targets]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2022-09-09" end = "2026-09-05" [[trusted.windows_aarch64_gnullvm]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2022-09-01" end = "2026-09-05" [[trusted.windows_aarch64_msvc]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2021-11-05" end = "2026-09-05" [[trusted.windows_i686_gnu]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2021-10-28" end = "2026-09-05" [[trusted.windows_i686_gnullvm]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2024-04-02" end = "2026-03-03" [[trusted.windows_i686_msvc]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2021-10-27" end = "2026-09-05" [[trusted.windows_x86_64_gnu]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2021-10-28" end = "2026-09-05" [[trusted.windows_x86_64_gnullvm]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2022-09-01" end = "2026-09-05" [[trusted.windows_x86_64_msvc]] criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2021-10-27" end = "2026-09-05" [[trusted.winnow]] criteria = "safe-to-deploy" user-id = 6743 # Ed Page (epage) start = "2023-02-22" end = "2026-12-01" [[trusted.wit-parser]] criteria = "safe-to-deploy" user-id = 73222 # wasmtime-publish start = "2024-02-15" end = "2025-05-01" [[trusted.wizer]] criteria = "safe-to-deploy" user-id = 696 # Nick Fitzgerald (fitzgen) start = "2021-01-07" end = "2026-03-03" ================================================ FILE: supply-chain/config.toml ================================================ # cargo-vet config file [cargo-vet] version = "0.9" [imports.bytecode-alliance] url = "https://raw.githubusercontent.com/bytecodealliance/wasmtime/main/supply-chain/audits.toml" [imports.embark-studios] url = "https://raw.githubusercontent.com/EmbarkStudios/rust-ecosystem/main/audits.toml" [imports.google] url = [ "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/main/cargo-vet/audits.toml?format=TEXT", "https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/third_party/rust_crates/supply-chain/audits.toml?format=TEXT", ] [imports.isrg] url = "https://raw.githubusercontent.com/divviup/libprio-rs/main/supply-chain/audits.toml" [imports.mozilla] url = "https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml" [[exemptions.addr2line]] version = "0.19.0" criteria = "safe-to-deploy" [[exemptions.bindgen]] version = "0.72.1" criteria = "safe-to-deploy" [[exemptions.bitflags]] version = "1.3.2" criteria = "safe-to-deploy" [[exemptions.bitflags]] version = "2.10.0" criteria = "safe-to-deploy" [[exemptions.block-buffer]] version = "0.10.4" criteria = "safe-to-deploy" [[exemptions.cc]] version = "1.2.51" criteria = "safe-to-deploy" [[exemptions.ciborium]] version = "0.2.1" criteria = "safe-to-run" [[exemptions.ciborium-io]] version = "0.2.1" criteria = "safe-to-run" [[exemptions.ciborium-ll]] version = "0.2.1" criteria = "safe-to-run" [[exemptions.clang-sys]] version = "1.6.1" criteria = "safe-to-deploy" [[exemptions.cpp_demangle]] version = "0.3.5" criteria = "safe-to-deploy" [[exemptions.cpufeatures]] version = "0.2.9" criteria = "safe-to-deploy" [[exemptions.crc32fast]] version = "1.3.2" criteria = "safe-to-deploy" [[exemptions.criterion]] version = "0.8.0" criteria = "safe-to-run" [[exemptions.crossbeam-deque]] version = "0.8.3" criteria = "safe-to-deploy" [[exemptions.crossbeam-epoch]] version = "0.9.15" criteria = "safe-to-deploy" [[exemptions.crossbeam-utils]] version = "0.8.16" criteria = "safe-to-deploy" [[exemptions.digest]] version = "0.10.7" criteria = "safe-to-deploy" [[exemptions.directories-next]] version = "2.0.0" criteria = "safe-to-deploy" [[exemptions.dirs-sys-next]] version = "0.1.2" criteria = "safe-to-deploy" [[exemptions.either]] version = "1.9.0" criteria = "safe-to-deploy" [[exemptions.fallible-iterator]] version = "0.2.0" criteria = "safe-to-deploy" [[exemptions.fd-lock]] version = "4.0.0" criteria = "safe-to-deploy" [[exemptions.find-msvc-tools]] version = "0.1.6" criteria = "safe-to-deploy" [[exemptions.foldhash]] version = "0.1.4" criteria = "safe-to-deploy" [[exemptions.futures-task]] version = "0.3.21" criteria = "safe-to-deploy" [[exemptions.futures-util]] version = "0.3.21" criteria = "safe-to-deploy" [[exemptions.generic-array]] version = "0.14.7" criteria = "safe-to-deploy" [[exemptions.getrandom]] version = "0.2.10" criteria = "safe-to-deploy" [[exemptions.getrandom]] version = "0.3.4" criteria = "safe-to-deploy" [[exemptions.hermit-abi]] version = "0.3.9" criteria = "safe-to-deploy" [[exemptions.im-rc]] version = "15.1.0" criteria = "safe-to-deploy" [[exemptions.ipnet]] version = "2.8.0" criteria = "safe-to-deploy" [[exemptions.itertools]] version = "0.10.5" criteria = "safe-to-deploy" [[exemptions.itertools]] version = "0.13.0" criteria = "safe-to-deploy" [[exemptions.libloading]] version = "0.7.4" criteria = "safe-to-deploy" [[exemptions.litemap]] version = "0.7.5" criteria = "safe-to-deploy" [[exemptions.maybe-owned]] version = "0.3.4" criteria = "safe-to-deploy" [[exemptions.memoffset]] version = "0.8.0" criteria = "safe-to-deploy" [[exemptions.minimal-lexical]] version = "0.2.1" criteria = "safe-to-deploy" [[exemptions.mio]] version = "0.8.0" criteria = "safe-to-deploy" [[exemptions.nom]] version = "7.1.3" criteria = "safe-to-deploy" [[exemptions.object]] version = "0.36.0" criteria = "safe-to-deploy" [[exemptions.once_cell]] version = "1.18.0" criteria = "safe-to-deploy" [[exemptions.oorandom]] version = "11.1.3" criteria = "safe-to-run" [[exemptions.openssl]] version = "0.10.72" criteria = "safe-to-deploy" [[exemptions.openssl-sys]] version = "0.9.107" criteria = "safe-to-deploy" [[exemptions.petgraph]] version = "0.6.5" criteria = "safe-to-deploy" [[exemptions.pkg-config]] version = "0.3.27" criteria = "safe-to-deploy" [[exemptions.plotters]] version = "0.3.5" criteria = "safe-to-run" [[exemptions.plotters-backend]] version = "0.3.5" criteria = "safe-to-run" [[exemptions.plotters-svg]] version = "0.3.5" criteria = "safe-to-run" [[exemptions.ppv-lite86]] version = "0.2.17" criteria = "safe-to-deploy" [[exemptions.r-efi]] version = "5.3.0" criteria = "safe-to-deploy" [[exemptions.rand]] version = "0.8.5" criteria = "safe-to-deploy" [[exemptions.rand_xoshiro]] version = "0.6.0" criteria = "safe-to-deploy" [[exemptions.redox_syscall]] version = "0.2.16" criteria = "safe-to-deploy" [[exemptions.redox_users]] version = "0.4.3" criteria = "safe-to-deploy" [[exemptions.rustc-demangle]] version = "0.1.23" criteria = "safe-to-deploy" [[exemptions.schannel]] version = "0.1.22" criteria = "safe-to-deploy" [[exemptions.security-framework]] version = "2.9.2" criteria = "safe-to-deploy" [[exemptions.security-framework-sys]] version = "2.9.1" criteria = "safe-to-deploy" [[exemptions.sha2]] version = "0.10.7" criteria = "safe-to-deploy" [[exemptions.sized-chunks]] version = "0.6.5" criteria = "safe-to-deploy" [[exemptions.stable_deref_trait]] version = "1.2.0" criteria = "safe-to-deploy" [[exemptions.strsim]] version = "0.11.0" criteria = "safe-to-deploy" [[exemptions.tempfile]] version = "3.8.0" criteria = "safe-to-deploy" [[exemptions.tower-service]] version = "0.3.2" criteria = "safe-to-deploy" [[exemptions.tracing]] version = "0.1.43" criteria = "safe-to-deploy" [[exemptions.tracing-attributes]] version = "0.1.31" criteria = "safe-to-deploy" [[exemptions.tracing-core]] version = "0.1.35" criteria = "safe-to-deploy" [[exemptions.typenum]] version = "1.16.0" criteria = "safe-to-deploy" [[exemptions.uuid]] version = "1.4.1" criteria = "safe-to-deploy" [[exemptions.wasi]] version = "0.11.0+wasi-snapshot-preview1" criteria = "safe-to-deploy" [[exemptions.web-sys]] version = "0.3.64" criteria = "safe-to-run" [[exemptions.winapi]] version = "0.3.9" criteria = "safe-to-deploy" [[exemptions.winapi-i686-pc-windows-gnu]] version = "0.4.0" criteria = "safe-to-deploy" [[exemptions.winapi-x86_64-pc-windows-gnu]] version = "0.4.0" criteria = "safe-to-deploy" [[exemptions.winx]] version = "0.36.2" criteria = "safe-to-deploy" [[exemptions.witx]] version = "0.9.1" criteria = "safe-to-deploy" [[exemptions.zerofrom]] version = "0.1.6" criteria = "safe-to-deploy" [[exemptions.zerofrom-derive]] version = "0.1.6" criteria = "safe-to-deploy" [[exemptions.zstd]] version = "0.13.1" criteria = "safe-to-deploy" [[exemptions.zstd-safe]] version = "7.1.0" criteria = "safe-to-deploy" [[exemptions.zstd-sys]] version = "2.0.10+zstd.1.5.6" criteria = "safe-to-deploy"