Watt

Build Status Latest Version Rust Documentation

Watt is a runtime for executing Rust procedural macros compiled as WebAssembly.

toml [dependencies] watt = "0.3"

Compiler support: requires rustc 1.35+


Rationale


Getting started

Start by implementing and testing your proc macro as you normally would, using whatever dependencies you want (syn, quote, etc). You will end up with something that looks like:

```rust extern crate proc_macro;

use proc_macro::TokenStream;

[proc_macro]

pub fn my_macro(input: TokenStream) -> TokenStream { /* ... */ } ```

#[proc_macro_derive] and #[proc_macro_attribute] are supported as well; everything is analogous to what will be shown here for #[proc_macro].

When your macro is ready, there are just a few changes we need to make to the signature and the Cargo.toml. In your lib.rs, change each of your macro entry points to a no_mangle extern "C" function, and change the TokenStream in the signature from proc_macro to proc_macro2.

It will look like:

```rust use proc_macro2::TokenStream;

[no_mangle]

pub extern "C" fn my_macro(input: TokenStream) -> TokenStream { /* same as before */ } ```

Now in your macro's Cargo.toml which used to contain this:

toml [lib] proc-macro = true

change it instead to say:

```toml [lib] crate-type = ["cdylib"]

[patch.crates-io] proc-macro2 = { git = "https://github.com/dtolnay/watt" } ```

This crate will be the binary that we compile to Wasm. Compile it by running:

console $ cargo build --release --target wasm32-unknown-unknown

Next we need to make a small proc-macro shim crate to hand off the compiled Wasm bytes into the Watt runtime. In a new Cargo.toml, put:

```toml [lib] proc-macro = true

[dependencies] watt = "0.3" ```

And in its src/lib.rs put:

```rust extern crate proc_macro;

use proc_macro::TokenStream; use watt::WasmMacro;

static MACRO: WasmMacro = WasmMacro::new(WASM); static WASM: &[u8] = includebytes("mymacro.wasm");

[proc_macro]

pub fn mymacro(input: TokenStream) -> TokenStream { MACRO.procmacro("my_macro", input) } ```

Finally, copy the compiled Wasm binary from target/wasm32-unknown-unknown/release/my_macro.wasm under your implementation crate, to the src directory of your shim crate, and it's ready to publish!


Remaining work


This can't be real

To assist in convincing you that this is real, here is serde_derive compiled to Wasm. It was compiled from the commit serde-rs/serde@37bf6984. Feel free to try it out as:

```rust // [dependencies] // serde = "1.0" // serde_json = "1.0" // wa-serde-derive = "0.1"

use waserdederive::Serialize;

[derive(Serialize)]

struct Watt { msg: &'static str, }

fn main() { let w = Watt { msg: "hello from wasm!" }; println!("{}", serdejson::tostring(&w).unwrap()); } ```


Acknowledgements

The current underlying Wasm runtime is a fork of the [Rust-WASM] project by Yoann Blein and Hugo Guiroux, a simple and spec-compliant WebAssembly interpreter.


License

Everything outside of the runtime directory is licensed under either of Apache License, Version 2.0 or MIT license at your option. The runtime directory is licensed under the ISC license.


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.