1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! A wrapper library around `hotdrink-rs` for compilation to WebAssembly.
//!
//! [![Crates.io][crates-badge]][crates-url]
//! [![docs.rs](https://docs.rs/hotdrink-wasm/badge.svg)](https://docs.rs/hotdrink-wasm)
//!
//! [crates-badge]: https://img.shields.io/crates/v/hotdrink-wasm.svg
//! [crates-url]: https://crates.io/crates/hotdrink-wasm
//!
//! # Prerequisites
//!
//! The project uses multiple nightly features, and must be built using nightly Rust.
//! I recommend using `rustup`, which can be downloaded [here](https://rustup.rs/),
//!
//! You also need `wasm-pack` to compile your project to WebAssembly, which can be downloaded [here](https://rustwasm.github.io/wasm-pack/installer/).
//!
//! The standard library must be recompiled with atomics enabled to use Web Workers as threads,
//! which means that we need the standard library source code.
//! This can be downloaded with `rustup component add rust-src`.
//!
//! # Usage
//!
//! Add the following to your `Cargo.toml`:
//!
//! ```toml
//! hotdrink-wasm = "0.1.1"
//! ```
//!
//! ## Single threaded
//!
//! ```rust
//! use hotdrink_rs::{component, model::ConstraintSystem};
//! use hotdrink_wasm::{component_type_wrapper, constraint_system_wrapper};
//! use wasm_bindgen::{JsValue, prelude::wasm_bindgen};
//!
//! component_type_wrapper! {
//!     pub struct ValueWrapper {
//!         #[derive(Clone, Debug)]
//!         pub enum Value {
//!             i32,
//!             String
//!         }
//!     }
//! }
//!
//! constraint_system_wrapper!(MyCs, ValueWrapper, Value);
//!
//! #[wasm_bindgen]
//! pub fn make_cs() -> Result<MyCs, JsValue> {
//!     let mut cs = ConstraintSystem::new();
//!     cs.add_component(component! {
//!         component MyComponent {
//!             let a: i32 = 0, b: String = "";
//!             // <contraints>
//!         }
//!     });
//!     MyCs::wrap(cs)
//! }
//! ```
//!
//! After producing a JavaScript module in www/pkg with
//! ```bash
//! wasm-pack build --out-dir www/pkg --release
//! ```
//! you can use the wrapper like this:
//!
//! ```javascript
//! let cs = wasm.make_cs();
//! cs.subscribe("MyComponent", "a",
//!     new_value => console.log("a =", new_value),
//!     () => console.log("a is pending"),
//!     err => console.log("a failed:", err)
//! );
//! cs.set_variable("MyComponent", "a", wasm.ValueWrapper.i32(5));
//! cs.set_variable("MyComponent", "b", wasm.ValueWrapper.String("Hello"));
//! cs.update();
//! ```
//!
//! ## Multithreaded
//!
//! Remember to add the `thread` feature flag in your `Cargo.toml`.
//!
//! ```toml
//! hotdrink-wasm = { version = "0.1.1", features = ["thread"] }
//! ```
//!
//! To use a multithreaded constraint system, you would create it like this instead:
//!
//! ```rust
//! use hotdrink_wasm::{component_type_wrapper};
//! #[cfg(feature = "thread")]
//! use hotdrink_wasm::{constraint_system_wrapper_threaded, thread::{StaticPool, TerminationStrategy}};
//!
//! component_type_wrapper! {
//!     pub struct ValueWrapper {
//!         #[derive(Clone, Debug)]
//!         pub enum Value {
//!             i32,
//!             String
//!         }
//!     }
//! }
//!
//! #[cfg(feature = "thread")]
//! constraint_system_wrapper_threaded!(
//!     MyCs,
//!     ValueWrapper,
//!     Value,
//!     StaticPool, // Or DynamicPool
//!     4,          // Number of threads
//!     TerminationStrategy::UnusedResultAndNotDone
//! );
//! ```
//!
//! To use Web Workers from Rust, the we must compile with `--target no-modules`.
//!
//! ```bash
//! wasm-pack build --out-dir www/pkg --target no-modules --release
//! ```
//!
//! This will produce WebAssembly code and JS wrappers in www/pkg, which can then be imported there.
//! See wasm-pack's documentation for more information.

#![warn(
    missing_copy_implementations,
    missing_debug_implementations,
    rust_2018_idioms,
    missing_docs
)]
#![feature(test)]
#![feature(result_flattening)]
#![feature(stmt_expr_attributes)]
#![feature(drain_filter)]
#![feature(concat_idents)]

pub mod event;
pub mod macros;
pub mod thread;
pub mod util;

/// Check how long it takes for a web worker running Wasm to start.
#[cfg(feature = "thread")]
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn bench_web_worker_init() {
    use js_sys::Date;
    use thread::worker::generic_worker::GenericWorker;
    let start = Date::now();
    let worker = GenericWorker::new("TestWorker").unwrap();
    worker
        .execute(Box::new(move |_| {
            let end = Date::now();
            log::info!("Spawning web worker took {}ms", end - start);
        }))
        .unwrap();
}