Skip to content

Implement array! and json! proc macros to make creation/instantiation easier #4515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ exclude = ["crates/msrv/resolver", "crates/msrv/lib", "crates/msrv/cli"]
members = [
"benchmarks",
"crates/cli",
"crates/creation-macros",
"crates/js-sys",
"crates/test",
"crates/test/sample",
Expand Down
38 changes: 38 additions & 0 deletions crates/creation-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
authors = ["The wasm-bindgen Developers"]
categories = ["wasm"]
description = """
Convenience macros for creating Javascript objects and arrays. For more
information see https://github.com/rustwasm/wasm-bindgen.
"""
documentation = "https://rustwasm.github.io/wasm-bindgen/"
edition = "2021"
homepage = "https://rustwasm.github.io/wasm-bindgen/"
include = ["/LICENSE-*", "/src"]
license = "MIT OR Apache-2.0"
name = "wasm-bindgen-creation-macros"
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/creation-macros"
rust-version = "1.76"
version = "0.2.100"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0.95"
quote = "1.0.40"
syn = "2.0.101"

[dev-dependencies]
js-sys = { path = "../js-sys" }
wasm-bindgen = { path = "../../" }

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = { path = '../test' }

[lints]
workspace = true

[[test]]
name = "creation"
path = "tests/creation.rs"
1 change: 1 addition & 0 deletions crates/creation-macros/LICENSE-APACHE
1 change: 1 addition & 0 deletions crates/creation-macros/LICENSE-MIT
147 changes: 147 additions & 0 deletions crates/creation-macros/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# wasm-bindgen-creation-macros

This crate provides procedural macros for the `wasm-bindgen` project, specifically focused on code generation and WebAssembly bindings creation.

## Overview

The `json!` and `array!` macros help in the creation of `js_sys::Object` and `js_sys::Array`, respectively. Specifically, they cut down on the verbose repetitive code needed to initialize `Object` and `Array` objects using plain Rust. Both macros support the use of any literals or variables that implement [`Into<JsValue>`](https://docs.rs/wasm-bindgen/latest/wasm_bindgen/struct.JsValue.html#trait-implementations). That includes rust strings, floating point numbers and integers, etc.

### Examples

```rust
use wasm_bindgen::prelude::*;
use js_sys::{Array, Object};
use wasm_bindgen_creation_macros::{array, json};

fn create_person() -> Object {
let address = json! {
street: "123 Main St",
city: "Tech City",
country: "Rustland"
};

json! {
name: "Alice",
age: 30,
hobbies: ["reading", "coding", "hiking"],
address: address, // Note the use of a variable!
fav_floats: [ 1.618, 3.14, 2.718 ],
nested_obj: {
num: 42,
inner_obj: {
msg: "Arbitrary nesting is supported!"
}
}
}
}

fn create_numbers() -> Array {
// variables work in array! as well.
const FIVE: u32 = 5;
array![1, 2, 3, 4, FIVE]
}

// Since variables are supported, array! and json! can be
// used together to create complex objects.
fn mix_and_match() -> Object {
let evens = array![2, 4, 6, 8];
let odds = array![1, 3, 6, 7];

let rust = json! {
language: "Rust",
mascot: "Crab"
};

let go = json! {
language: "Go",
mascot: "Gopher"
};

let languages_array = array![ rust, go, { language: "Python", mascot: "Snakes" } ];

json! {
evens: evens,
odds: odds,
languages: languages_array
}
}
```

## A Note on Parsing

The parser used is not sophisticated; Rust values that are not **simple** Rust literals should be stored in a variable first, then the variable should be added to the macro. Attempting to pass non-simple rust syntax will cause compilation to fail.

```rust
use wasm_bindgen::prelude::*;
use js_sys::{Array, Object};
use wasm_bindgen_creation_macros::{array, json};

pub struct CustomJsValue(u32);

impl Into<JsValue> for CustomJsValue {
fn into(self) -> JsValue {
self.0.into()
}
}

// WILL NOT COMPILE
fn incorrect() -> Object {
json! {
custom: CustomJsValue(42)
}
}

// Do this instead
fn correct() -> Object {
let custom = CustomJsValue(42);
json! {
js_value: custom
}
}

// WILL NOT COMPILE
fn also_invalid() -> Object {
json! {
array: array![1, 2, 3]
}
}

// Do this instead
fn also_correct() -> Object {
let array = array![1, 2, 3];
json! {
array: array
}

}
```

Also, `json!` does not (currently) support string literal JSON keys.


```rust
use wasm_bindgen::prelude::*;
use js_sys::{Array, Object};
use wasm_bindgen_creation_macros::{array, json};

// WILL NOT COMPILE
fn incorrect() -> Object {
json! {
"key": 42
}
}

// Do this instead
fn correct() -> Object {
json! {
key: 42
}
}
```

## Testing
To run the test suite, run `cargo test --target wasm32-unknown-unknown`.

```bash
cargo test --target wasm32-unknown-unknown
```
Loading
Loading