diff --git a/Cargo.lock b/Cargo.lock index ab8ba74..9bd8c66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "arraydeque" version = "0.5.1" @@ -14,11 +29,67 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clang-sys" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] [[package]] name = "const-random" @@ -40,6 +111,15 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "crunchy" version = "0.2.4" @@ -55,6 +135,12 @@ dependencies = [ "const-random", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -64,23 +150,53 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "hashbrown" version = "0.14.5" @@ -93,7 +209,18 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", ] [[package]] @@ -105,11 +232,64 @@ dependencies = [ "hashbrown 0.15.5", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "libc" -version = "0.2.176" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nix-wasm-plugin-fib" @@ -141,6 +321,14 @@ dependencies = [ "num", ] +[[package]] +name = "nix-wasm-plugin-quickjs" +version = "0.1.0" +dependencies = [ + "nix-wasm-rust", + "rquickjs", +] + [[package]] name = "nix-wasm-plugin-test" version = "0.1.0" @@ -160,6 +348,16 @@ dependencies = [ name = "nix-wasm-rust" version = "0.1.0" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num" version = "0.4.3" @@ -249,6 +447,129 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "relative-path" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0" +dependencies = [ + "serde", +] + +[[package]] +name = "rquickjs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50dc6d6c587c339edb4769cf705867497a2baf0eca8b4645fa6ecd22f02c77a" +dependencies = [ + "rquickjs-core", + "rquickjs-macro", +] + +[[package]] +name = "rquickjs-core" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bf7840285c321c3ab20e752a9afb95548c75cd7f4632a0627cea3507e310c1" +dependencies = [ + "hashbrown 0.16.1", + "relative-path", + "rquickjs-sys", +] + +[[package]] +name = "rquickjs-macro" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7106215ff41a5677b104906a13e1a440b880f4b6362b5dc4f3978c267fad2b80" +dependencies = [ + "convert_case", + "fnv", + "ident_case", + "indexmap", + "proc-macro-crate", + "proc-macro2", + "quote", + "rquickjs-core", + "syn", +] + +[[package]] +name = "rquickjs-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27344601ef27460e82d6a4e1ecb9e7e99f518122095f3c51296da8e9be2b9d83" +dependencies = [ + "bindgen", + "cc", +] + [[package]] name = "rust-ini" version = "0.21.3" @@ -259,6 +580,58 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -268,12 +641,69 @@ dependencies = [ "crunchy", ] +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + [[package]] name = "yaml-rust2" version = "0.10.4" diff --git a/Cargo.toml b/Cargo.toml index 13cd6b1..379f3fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "nix-wasm-plugin-yaml", "nix-wasm-plugin-mandelbrot", "nix-wasm-plugin-test", + "nix-wasm-plugin-quickjs", "nix-wasm-plugin-grep", ] resolver = "2" diff --git a/flake.lock b/flake.lock index 93cf4ed..50f60e1 100644 --- a/flake.lock +++ b/flake.lock @@ -83,16 +83,16 @@ "nixpkgs-regression": "nixpkgs-regression" }, "locked": { - "lastModified": 1769002999, - "narHash": "sha256-O8ml8+RH2QQqNk7UGREWg6ivAYDxhaMd03sRVJi1kxI=", + "lastModified": 1771906938, + "narHash": "sha256-yMI4VhuahG1027I+x/xy0F5FUM7ntwB/hDouCmpwEb8=", "owner": "DeterminateSystems", "repo": "nix-src", - "rev": "57ac5202d90e678616577f98b2f656693d2f37fa", + "rev": "628d55ca372a6d9eb071804b589aaa8a6974807d", "type": "github" }, "original": { "owner": "DeterminateSystems", - "ref": "wasm", + "ref": "main", "repo": "nix-src", "type": "github" } diff --git a/flake.nix b/flake.nix index afaa954..f28090a 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,7 @@ inputs = { nixpkgs.follows = "nix/nixpkgs"; flake-schemas.url = "https://flakehub.com/f/DeterminateSystems/flake-schemas/*.tar.gz"; - nix.url = "github:DeterminateSystems/nix-src/wasm"; + nix.url = "github:DeterminateSystems/nix-src/main"; }; outputs = { self, ... }@inputs: @@ -20,6 +20,105 @@ packages = forAllSystems ({ pkgs, system }: rec { default = nix-wasm-plugins; + nix-wasm-plugin-quickjs = with pkgs; + let + quickjsCargoToml = builtins.fromTOML (builtins.readFile ./nix-wasm-plugin-quickjs/Cargo.toml); + rustPackages = pkgs.rustPackages_1_89; + rustPlatform = rustPackages.rustPlatform; + rustSysroot = runCommand "rust-sysroot" { } '' + mkdir -p $out/lib/rustlib + cp -r ${rustPackages."rustc-unwrapped"}/lib/rustlib/* $out/lib/rustlib/ + mkdir -p $out/lib/rustlib/src + ln -s ${rustPlatform.rustcSrc} $out/lib/rustlib/src/rust + ''; + rustcWithSysroot = runCommand "rustc-with-sysroot" { } '' + mkdir -p $out/bin + cat > $out/bin/rustc <<'EOF' + #!/bin/sh + exec ${rustPackages.rustc}/bin/rustc --sysroot ${rustSysroot} "$@" + EOF + chmod +x $out/bin/rustc + ''; + wasiCc = pkgs.pkgsCross.wasi32.stdenv.cc; + wasiLibc = pkgs.pkgsCross.wasi32.wasilibc; + wasiLibcDev = wasiLibc.dev; + wasiSysroot = runCommand "wasi-sysroot" { } '' + mkdir -p $out/include $out/lib/wasm32-wasip1 + cp -R ${wasiLibcDev}/include/* $out/include/ + cp -R ${wasiLibc}/lib/* $out/lib/ + cp -R ${wasiLibc}/lib/* $out/lib/wasm32-wasip1/ + ''; + wasiSdk = runCommand "wasi-sdk-compat" { } '' + mkdir -p $out/bin $out/lib/clang/19 $out/share + + ln -s ${wasiCc}/bin/wasm32-unknown-wasi-clang $out/bin/clang + ln -s ${wasiCc}/bin/wasm32-unknown-wasi-clang++ $out/bin/clang++ + ln -s ${wasiCc}/bin/wasm32-unknown-wasi-ar $out/bin/ar + ln -s ${wasiCc}/bin/wasm32-unknown-wasi-ld.lld $out/bin/ld.lld + + ln -s ${wasiCc}/resource-root/include $out/lib/clang/19/include + ln -s ${wasiSysroot} $out/share/wasi-sysroot + ''; + workspaceVendor = rustPlatform.fetchCargoVendor { + src = self; + hash = "sha256-c2jpj5YfRKIiIAwry0dOoNzAqW6YUdnHWsCe61t/New="; + }; + stdlibVendor = rustPlatform.fetchCargoVendor { + src = rustPlatform.rustcSrc; + cargoRoot = "library"; + hash = "sha256-XD+1wJ7GfnJG4qyulIdZum7VV4rtIoQRM+L0xXUHjXA="; + }; + cargoVendor = runCommand "cargo-vendor-merged" { } '' + mkdir -p $out + cp -R ${workspaceVendor}/* $out/ + mkdir -p $out/.cargo + cp -R ${workspaceVendor}/.cargo/* $out/.cargo/ + chmod -R u+w $out + cp -R ${stdlibVendor}/* $out/ + cp ${workspaceVendor}/Cargo.lock $out/Cargo.lock + cp ${workspaceVendor}/.cargo/config.toml $out/.cargo/config.toml + ''; + in rustPlatform.buildRustPackage { + pname = quickjsCargoToml.package.name; + version = quickjsCargoToml.package.version; + + cargoLock.lockFile = ./Cargo.lock; + cargoDeps = cargoVendor; + + src = self; + + buildPhase = '' + RUSTFLAGS="-L ${wasiSdk}/share/wasi-sysroot/lib/wasm32-wasip1" \ + cargo build --release -p nix-wasm-plugin-quickjs \ + --target wasm32-wasip1 -Z build-std=std,panic_abort + ''; + + installPhase = '' + mkdir -p $out + for i in target/wasm32-wasip1/release/*.wasm; do + wasm-opt -O3 --enable-bulk-memory --enable-nontrapping-float-to-int --enable-simd -o "$out/$(basename "$i")" "$i" + done + ''; + + nativeBuildInputs = [ + rustPackages.rustc.llvmPackages.lld + binaryen + llvmPackages.clang + llvmPackages.libclang + ]; + + WASI_SDK = "${wasiSdk}"; + LIBCLANG_PATH = "${llvmPackages.libclang.lib}/lib"; + RUSTC = "${rustcWithSysroot}/bin/rustc"; + CC_wasm32_wasip1 = "${wasiSdk}/bin/clang"; + AR_wasm32_wasip1 = "${wasiSdk}/bin/ar"; + CFLAGS_wasm32_wasip1 = "--sysroot=${wasiSdk}/share/wasi-sysroot -isystem ${wasiSdk}/lib/clang/19/include"; + BINDGEN_EXTRA_CLANG_ARGS_wasm32_wasip1 = "-fvisibility=default --sysroot=${wasiSdk}/share/wasi-sysroot -isystem ${wasiSdk}/lib/clang/19/include -resource-dir ${wasiSdk}/lib/clang/19"; + CARGO_TARGET_WASM32_WASIP1_LINKER = "${wasiSdk}/bin/ld.lld"; + RUSTC_BOOTSTRAP = "1"; + doCheck = false; + }; + nix-wasm-plugins = with pkgs; rustPlatform.buildRustPackage { pname = cargoToml.package.name; version = cargoToml.package.version; @@ -29,13 +128,17 @@ src = self; CARGO_BUILD_TARGET = "wasm32-unknown-unknown"; - buildPhase = "cargo build --release"; + buildPhase = "cargo build --release --workspace --exclude nix-wasm-plugin-quickjs"; checkPhase = '' + mkdir -p plugins + cp target/wasm32-unknown-unknown/release/*.wasm plugins/ + cp ${nix-wasm-plugin-quickjs}/*.wasm plugins/ + for i in nix-wasm-plugin-*/tests/*.nix; do echo "running test $i..." base="$(dirname $i)/$(basename $i .nix)" - nix eval --store dummy:// --offline --json --show-trace -I plugins=target/wasm32-unknown-unknown/release --impure --eval-cores 0 --file "$i" > "$base.out" + nix eval --store dummy:// --offline --json --show-trace -I plugins=plugins --impure --eval-cores 0 --file "$i" > "$base.out" cmp "$base.exp" "$base.out" done ''; @@ -45,6 +148,7 @@ for i in target/wasm32-unknown-unknown/release/*.wasm; do wasm-opt -O3 -o "$out/$(basename "$i")" "$i" done + cp ${nix-wasm-plugin-quickjs}/*.wasm $out/ ''; nativeBuildInputs = [ diff --git a/nix-wasm-plugin-quickjs/Cargo.toml b/nix-wasm-plugin-quickjs/Cargo.toml new file mode 100644 index 0000000..9c59c88 --- /dev/null +++ b/nix-wasm-plugin-quickjs/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "nix-wasm-plugin-quickjs" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +nix-wasm-rust = { path = "../nix-wasm-rust" } +rquickjs = { version = "0.11.0", features = ["bindgen"] } diff --git a/nix-wasm-plugin-quickjs/src/lib.rs b/nix-wasm-plugin-quickjs/src/lib.rs new file mode 100644 index 0000000..1d9c07b --- /dev/null +++ b/nix-wasm-plugin-quickjs/src/lib.rs @@ -0,0 +1,82 @@ +use nix_wasm_rust::{nix_wasm_init_v1, warn, wasi_arg, Value}; +use rquickjs::{Array, Context, Object, Runtime, Value as JsValue}; +use std::string::String as StdString; + +fn fail(context: &str, err: impl std::fmt::Display) -> ! { + warn!("quickjs {context} failed: {err}"); + panic!("quickjs {context} failed: {err}"); +} + +fn js_value_to_nix(value: JsValue) -> Value { + if value.is_null() || value.is_undefined() { + return Value::make_null(); + } + if let Some(b) = value.as_bool() { + return Value::make_bool(b); + } + if let Some(i) = value.as_int() { + return Value::make_int(i as i64); + } + if let Some(f) = value.as_float() { + return Value::make_float(f); + } + if let Some(js_str) = value.as_string() { + let s = js_str.to_string().unwrap_or_else(|err| fail("string conversion", err)); + return Value::make_string(&s); + } + if value.is_array() { + let array: Array = value + .clone() + .into_array() + .unwrap_or_else(|| fail("array conversion", "value is not an array")); + let mut items = Vec::new(); + for entry in array.into_iter() { + let entry = entry.unwrap_or_else(|err| fail("array iteration", err)); + items.push(js_value_to_nix(entry)); + } + return Value::make_list(&items); + } + if value.is_object() { + let object: Object = value + .into_object() + .unwrap_or_else(|| fail("object conversion", "value is not an object")); + let mut entries: Vec<(StdString, Value)> = Vec::new(); + for entry in object.props::() { + let (key, value) = entry.unwrap_or_else(|err| fail("object iteration", err)); + entries.push((key, js_value_to_nix(value))); + } + let attrs: Vec<(&str, Value)> = entries + .iter() + .map(|(key, value)| (key.as_str(), *value)) + .collect(); + return Value::make_attrset(&attrs); + } + + warn!("quickjs value type not supported: {:?}", value.type_of()); + panic!("quickjs value type not supported: {:?}", value.type_of()); +} + +fn eval_impl(arg: Value) -> Value { + let code = arg.get_string(); + + let runtime = Runtime::new().unwrap_or_else(|err| fail("runtime init", err)); + let context = Context::full(&runtime).unwrap_or_else(|err| fail("context init", err)); + + context.with(|ctx| { + let value: JsValue = ctx.eval(code).unwrap_or_else(|err| fail("eval", err)); + js_value_to_nix(value) + }) +} + +#[no_mangle] +pub extern "C" fn eval(arg: Value) -> Value { + nix_wasm_init_v1(); + eval_impl(arg) +} + +#[no_mangle] +pub extern "C" fn _start() { + nix_wasm_init_v1(); + let result = eval_impl(wasi_arg()); + result.return_to_nix(); +} diff --git a/nix-wasm-plugin-quickjs/tests/eval.exp b/nix-wasm-plugin-quickjs/tests/eval.exp new file mode 100644 index 0000000..2193dfa --- /dev/null +++ b/nix-wasm-plugin-quickjs/tests/eval.exp @@ -0,0 +1 @@ +{"arr":[1,"two",false],"bool":true,"float":1.5,"nil":null,"num":1,"obj":{"nested":3},"str":"hello","undef":null} diff --git a/nix-wasm-plugin-quickjs/tests/eval.nix b/nix-wasm-plugin-quickjs/tests/eval.nix new file mode 100644 index 0000000..f92bc5e --- /dev/null +++ b/nix-wasm-plugin-quickjs/tests/eval.nix @@ -0,0 +1,12 @@ +builtins.wasi '' + ({ + num: 1, + float: 1.5, + str: "hello", + bool: true, + nil: null, + undef: undefined, + arr: [1, "two", false], + obj: { nested: 3 } + }) +'' diff --git a/nix-wasm-rust/src/lib.rs b/nix-wasm-rust/src/lib.rs index 1457c8e..639754f 100644 --- a/nix-wasm-rust/src/lib.rs +++ b/nix-wasm-rust/src/lib.rs @@ -36,6 +36,16 @@ pub struct Value(ValueId); type ValueId = u32; +pub fn wasi_arg() -> Value { + let arg = std::env::args() + .nth(1) + .unwrap_or_else(|| panic("missing WASI argument")); + let value_id = arg.parse::().unwrap_or_else(|err| { + panic(&format!("invalid WASI argument '{arg}': {err}")) + }); + Value::from_raw(value_id) +} + #[repr(C)] pub enum Type { Int = 1, @@ -50,6 +60,21 @@ pub enum Type { } impl Value { + pub const fn from_raw(value: ValueId) -> Value { + Value(value) + } + + pub const fn id(self) -> ValueId { + self.0 + } + + pub fn return_to_nix(self) -> ! { + extern "C" { + fn return_to_nix(value: ValueId) -> !; + } + unsafe { return_to_nix(self.0) } + } + pub fn get_type(&self) -> Type { extern "C" { fn get_type(value: ValueId) -> Type;