1 unstable release

0.1.0 May 19, 2024

#549 in WebAssembly

MIT license

48KB
923 lines

See the documentation on the cargo doc for more information.

Building

wasm-pack build --target web --release

There's a simple example included, it can be viewed by using miniserve in that example folder.

cargo install miniserve
miniserve .

Then open index.html


lib.rs:

This is a Send + Sync abstraction for JsValue.

It makes it possible to wrap a JsValue in an Arc and use it with other wrapped JsValues. It also supports async closures and covers some trait operations. It accomplishes this by keeping JsValues on one thread and sending closures from other threads to be executed on it.

This is how to create a wrapped value

let js_v = JsArc::new(|| "Hello World!".into()).await;

js_v.with_self(|js_value| {
    web_sys::console::log_1(&js_value);
    js_value
})
.await;

After creating values, they can still be changed

let js_v = JsArc::new(|| 2.into()).await;
js_v.with_self(|one| one + &5.into()).await;

// Outputs 7
js_v.with_self(|js_v| {
    web_sys::console::log_1(&js_v);
    js_v
})
.await;

This demonstrates creating two JsValues and using them with each other

let one = JsArc::new(|| 1.into()).await;
let two = JsArc::new(|| 2.into()).await;

let three = one
   .with_other(&two, |one, two| {
       let add_result: JsValue = &one + &two;

       (one, two, add_result)
   })
   .await;

three
   .with_self(|three| {
       web_sys::console::log_1(&three);

       three
   })
   .await;

It also works with async closures

let js_v = JsArc::new(|| "Hello World!".into()).await;

js_v.with_self_async(|hello| async move {
    web_sys::console::log_1(&"Waiting 5 second then printing value".into());
    async_std::task::sleep(Duration::from_secs(5)).await;
    web_sys::console::log_1(&hello);

    hello
})
.await;

And async closures with two JsValues

let five = three
    .with_other_async(&two, |three, two| async {
        web_sys::console::log_1(&"Waiting 1 second then adding values".into());
        async_std::task::sleep(Duration::from_secs(1)).await;
        let add_result: JsValue = &three + &two;

        (three, two, add_result)
    })
    .await;

five.with_self(|five| {
    web_sys::console::log_1(&five);

    five
})
.await;

And many JsValues

let v0 = JsArc::new(|| 0.into()).await;
let v1 = JsArc::new(|| 1.into()).await;
let v2 = JsArc::new(|| 2.into()).await;
let v3 = JsArc::new(|| 3.into()).await;
let v4 = JsArc::new(|| 4.into()).await;

let ten = v0
    .with_many(vec![&v1, &v2, &v3, &v4], |mut all| {
        let [v0, v1, v2, v3, v4] = &all[..] else {
            unreachable!("Not possible");
        };

        let result = v0 + v1 + v2 + v3 + v4;

        all.push(result);
        all
    })
    .await; 

The purpose for writing it was to simplify use of JsValues across different threads.

// It works inside Arc so it can be used on different threads. JsValue does not support Send + Sync by itself.
let value_in_arc: Arc<JsArc> = Arc::new(three);
let str: Arc<JsArc> = JsArc::new(|| "hello!".into()).await.arc();

And it also supports some trait operations: Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub

let three = (&one + &two).await;
let ten = (&(&three * &three).await + &one).await;
let seven = (&ten - &three).await;

seven
    .with_self(|seven| {
        web_sys::console::log_1(&seven);

        seven
    })
    .await;

Warning

This is not tested. The syntax of this abstraction compiles, but it has not been tested with actual multithreading. Rust WASM does not support threading by default in the 2021 edition. In this untested state it can be used to pass trait restriction requirements for Send + Sync. There was not unsafe code used in writing this and the implmentation should be correct for a threading environment.

Dependencies

~1.3–3.5MB
~60K SLoC