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