{"_id":"kaffeerost","_rev":"2-76ca36e233960cb33e3ae7cb14724643","name":"kaffeerost","description":"Experimental utilities for integrating Rust with WebAssembly","dist-tags":{"latest":"0.0.1"},"versions":{"0.0.1":{"name":"kaffeerost","version":"0.0.1","description":"Experimental utilities for integrating Rust with WebAssembly","main":"index.js","scripts":{"rust-sample":"make --directory=examples/rust && ava examples/rust/test.js","pretest":"tsc --noEmit --project jsconfig.json && tslint --project jsconfig.json","test":"ava"},"repository":{"type":"git","url":"git+ssh://git@github.com/killercup/wasm-experiments.git"},"keywords":[],"author":{"name":"Pascal Hertleif","email":"killercup@gmail.com","url":"http://pascalhertleif.de/"},"license":"MIT","bugs":{"url":"https://github.com/killercup/wasm-experiments/issues"},"homepage":"https://github.com/killercup/wasm-experiments#readme","dependencies":{"@types/node":"^8.0.53","@types/text-encoding":"0.0.32","@types/webassembly-js-api":"0.0.1","text-encoding":"^0.6.4"},"devDependencies":{"@types/tmp":"0.0.33","ava":"^0.23.0","tmp":"0.0.33","tslint":"^5.8.0","typescript":"^2.6.1"},"ava":{"files":["tests/*.js"],"source":["src/*.js"]},"gitHead":"36e04ace73448a7867835f8682694e87f1e036ef","_id":"kaffeerost@0.0.1","_npmVersion":"5.6.0","_nodeVersion":"9.2.1","_npmUser":{"name":"killercup","email":"killercup@gmail.com"},"maintainers":[{"name":"killercup","email":"killercup@gmail.com"}],"dist":{"integrity":"sha512-a2gT79ojaioNQlo/NYHVbQml5XQLUcy+377qw/N0Ga6xTI5MPbaNoufUgvV/95zUMLfgsxI9VweESaESQqCUgA==","shasum":"c978b3b638583c20a928271c65ac0a266be9db9d","tarball":"https://registry.npmjs.org/kaffeerost/-/kaffeerost-0.0.1.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA0vVXQ/OivhljGy7/fLrL9r92im2nvuoySy4THJ0GYBAiEAqtGdFXsw7fQ2b8LQnMEewofv9toXhjK3M/B8H5tFHYc="}]},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/kaffeerost-0.0.1.tgz_1513186359528_0.34400822618044913"},"directories":{},"deprecated":"aint got time for that"}},"readme":"# WASM experiments\n\nSome experiments after seeing [Rust PR #45905].\n\n[Rust PR #45905]: https://github.com/rust-lang/rust/pull/45905\n\n## Getting Rust to compile to WASM\n\nIt's quite easy now!\nAssuming you've installed Rust with [rustup] (highly recommended), it's just:\n\n```\nrustup update\nrustup target add wasm32-unknown-unknown --toolchain nightly\nrustc +nightly --target wasm32-unknown-unknown -O hello.rs\n```\n\n[rustup]: https://www.rustup.rs\n\n## Using the `wrap` function\n\nWhile this repo first started as a playground,\nover time, a generic wrapper tool was developed.\nIts goal is to allow you to easily call Rust functions in WASM from JS.\n\nLet's see how we can use it to handle some trivial functions.\n\n### Boilerplate\n\nFirst, we'll need a way to load Rust code as WASM:\n\n```js\nconst loadRust = require(\"../src/compile\");\n```\n\nYou can also load your own `.wasm` file, of course.\nNext, the wrapper helper:\n\n```js\nconst wrap = require(\"../src/wrap\");\n```\n\nWe'll be calling this a lot.\n\nAnd, to test that this actually works (yes, this code is tested),\nlet's import the handy `ava` library.\n\n```js\nconst { test } = require(\"ava\");\n```\n\n### Easy as 1 2 3\n\nOkay, we should be good to go. Let's see if this works:\n\n```js\ntest(\"it works!\", async (t) => {\n    const instance = await loadRust(`\n        #[no_mangle]\n        pub fn is_answer(a: i32) -> bool {\n            a == 42\n        }\n    `);\n    const isAnswer = wrap(instance.exports, \"is_answer\", [\"i32\"], \"bool\");\n    t.deepEqual(isAnswer(42), true);\n});\n```\n\nLooking good!\nThe thing with this wrapper tool is that it needs to be able\nto convert between Rust and JS types.\nPrimitives like integers are easy,\nbut stuff like strings or arrays are a bit more complicated.\n\n### A-B-C? Actually not that easy\n\nLet's try to write a function that returns a Rust `String`:\n\n```js\ntest(\"get the time\", async (t) => {\n    const instance = await loadRust(`\n        #[no_mangle]\n        pub extern \"C\" fn time() -> String {\n            String::from(\"Beer o'clock\")\n        }\n    `);\n    const time = wrap(instance.exports, \"time\", [], \"String\");\n```\n\nSurprisingly, we cannot wrap this!\nThe error message will tell you why:\n\n```js\n    const error = await t.throws(() => {\n        const now = time();\n    });\n    t.is(error.message, \"Ensure failed: You need to export an `alloc` function to get strings from WASM\");\n});\n```\n\nSo, to get a Rust `String` (or any other non-primitive type basically), we need to allocate memory.\nAnd not even to store the string itself (which Rust stores on the heap),\njust to be able to tell the WASM function where to write the stack data of the `String` to\n(It's passed as an out paramter as a `String` needs three words of storage).\n\nLet's give this another go:\n\n```js\ntest(\"really get the time\", async (t) => {\n    const instance = await loadRust(`\n        use std::mem;\n        use std::os::raw::c_void;\n\n        #[no_mangle]\n        pub extern \"C\" fn alloc(size: usize) -> *mut c_void {\n            let mut buf = Vec::with_capacity(size);\n            let ptr = buf.as_mut_ptr();\n            mem::forget(buf); // This is JS' responsibility now\n            return ptr as *mut c_void;\n        }\n\n        #[no_mangle]\n        pub extern \"C\" fn time() -> String {\n            String::from(\"Beer o'clock\")\n        }\n    `);\n    const time = wrap(instance.exports, \"time\", [], \"String\");\n    t.deepEqual(time(), \"Beer o'clock\");\n});\n```\n\nFor now, this `alloc` export is something you'll just have to do. Sorry.\nIt'll get better, I promise.\n(Deallocating memory is still an open issue -- chime in [here][issue-7]!)\n\n[issue-7]: https://github.com/killercup/wasm-experiments/issues/7\n\n### Writing code yourself is way to hard, let's just use Cargo\n\nOkay, how about we try to do something useful?\nLike, I don't know, calculate a SHA1 has for some bytes.\nDo you know how to write implement SHA1 by hand? Well, me neither.\nSo, let's use a crate (Rust library)! [Here][sha1], I found one!\n\n[sha1]: https://crates.io/crates/sha1\n\nHow to use it? Let's split this up a bit.\nHere is the Rust code to load the `sha1` crate,\nuse it to munch some string slice,\nand return a fancy `String` that contains the human-readable hash.\n\n```js\ntest(\"digest some yummy bytes\", async (t) => {\n    const rustCode = `\n        extern crate sha1;\n        use sha1::Sha1;\n\n        #[no_mangle]\n        pub extern \"C\" fn digest(data: &str) -> String {\n            let mut m = Sha1::new();\n            m.update(data.as_bytes());\n            m.digest().to_string()\n        }\n```\n\nOh, and don't forget the `alloc` dance:\n\n```js\n        use std::mem;\n        use std::os::raw::c_void;\n\n        #[no_mangle]\n        pub extern \"C\" fn alloc(size: usize) -> *mut c_void {\n            let mut buf = Vec::with_capacity(size);\n            let ptr = buf.as_mut_ptr();\n            mem::forget(buf); // This is JS' responsibility now\n            return ptr as *mut c_void;\n        }\n    `;\n```\n\nand then we can compile this to WASM with a newly added list of dependencies\n(the format is `{ name: \"version\" }`):\n\n```js    \n    const instance = await loadRust(rustCode, { sha1: \"0.2\" });\n```\n\nEt voilá, we can SHA1 all the strings now!\n\n```js    \n    const digest = wrap(instance.exports, \"digest\", [\"&str\"], \"String\");\n    t.deepEqual(digest(\"foobar\"), \"8843d7f92416211de9ebb963ff4ce28125932878\");\n});\n``` \n\n### Debugging\n\nYou can enable more logging output by setting the environment variable `LOG_LEVEL`.\nThe levels are error (`0`), warn, info, debug, trace (`5`).\nThe default is `2` (info).\n","maintainers":[{"name":"killercup","email":"killercup@gmail.com"}],"time":{"modified":"2022-05-07T03:01:08.414Z","created":"2017-12-13T17:32:40.841Z","0.0.1":"2017-12-13T17:32:40.841Z"},"homepage":"https://github.com/killercup/wasm-experiments#readme","keywords":[],"repository":{"type":"git","url":"git+ssh://git@github.com/killercup/wasm-experiments.git"},"author":{"name":"Pascal Hertleif","email":"killercup@gmail.com","url":"http://pascalhertleif.de/"},"bugs":{"url":"https://github.com/killercup/wasm-experiments/issues"},"license":"MIT","readmeFilename":"README.md"}