Skip to content

Commit 6ba1eae

Browse files
committed
Merge branch 'main' into pub-channel
2 parents 08ea4aa + f3406b3 commit 6ba1eae

18 files changed

Lines changed: 765 additions & 471 deletions

File tree

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
- uses: dtolnay/rust-toolchain@stable
3333
- uses: Swatinem/rust-cache@v2
3434
- name: Run doctest
35-
run: cargo test --doc
35+
run: cargo test --doc --all-features
3636

3737
test:
3838
runs-on: ubuntu-latest

Cargo.lock

Lines changed: 3 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ readme = "README.md"
1111
keywords = ["webworker", "parallelism", "wasm"]
1212

1313
[workspace.dependencies]
14-
wasmworker = { version = "0.2", path = ".", features = ["serde"] }
15-
wasmworker-proc-macro = { version = "0.2", path = "proc-macro" }
14+
wasmworker = { version = "0.3", path = ".", features = ["serde", "macros"] }
15+
wasmworker-proc-macro = { version = "0.3", path = "proc-macro" }
1616

1717
[package]
1818
name = "wasmworker"
19-
version = "0.2.1"
19+
version = "0.3.0"
2020
edition = "2021"
2121

2222
description.workspace = true
@@ -68,3 +68,8 @@ default = ["serde", "codec-postcard"]
6868
serde = []
6969
codec-postcard = ["dep:postcard"]
7070
codec-pot = ["dep:pot"]
71+
macros = ["wasmworker-proc-macro"]
72+
73+
[dependencies.wasmworker-proc-macro]
74+
workspace = true
75+
optional = true

README.md

Lines changed: 67 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
# wasmworker
2+
3+
[![Crates.io](https://img.shields.io/crates/v/wasmworker)](https://crates.io/crates/wasmworker)
4+
[![docs.rs](https://img.shields.io/docsrs/wasmworker)](https://docs.rs/wasmworker)
5+
[![CI](https://github.com/paberr/wasmworker/actions/workflows/test.yml/badge.svg)](https://github.com/paberr/wasmworker/actions/workflows/test.yml)
6+
[![Crates.io Downloads](https://img.shields.io/crates/d/wasmworker)](https://crates.io/crates/wasmworker)
7+
[![License](https://img.shields.io/crates/l/wasmworker)](https://github.com/paberr/wasmworker#license)
8+
29
`wasmworker` is a library that provides easy access to parallelization on web targets when compiled to WebAssembly using [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen).
310
In contrast to many other libraries like [wasm-bindgen-rayon](https://github.com/RReverser/wasm-bindgen-rayon), this library does not require SharedArrayBuffer support.
411

@@ -10,20 +17,18 @@ In contrast to many other libraries like [wasm-bindgen-rayon](https://github.com
1017
- [Iterator extension](#iterator-extension)
1118
- [Async functions with channels](#async-functions-with-channels)
1219
- [Bundler support (Vite)](#bundler-support-vite)
20+
- [Idle timeout](#idle-timeout)
1321
- [FAQ](#faq)
1422

1523
## Usage
16-
The library consists of two crates:
17-
- `wasmworker`: The main crate that also offers access to the webworker, as well as the worker pool and iterator extensions.
18-
- `wasmworker-proc-macro`: This crate is needed to expose functions towards the web workers via the `#[webworker_fn]` macro.
1924

2025
### Setting up
21-
To use this library, include both dependencies to your `Cargo.toml`.
26+
To use this library, add the following dependency to your `Cargo.toml`.
27+
Enable the `macros` feature to get access to the `#[webworker_fn]` and `#[webworker_channel_fn]` attribute macros.
2228

2329
```toml
2430
[dependencies]
25-
wasmworker = "0.2"
26-
wasmworker-proc-macro = "0.2"
31+
wasmworker = { version = "0.3", features = ["macros"] }
2732
```
2833

2934
The `wasmworker` crate comes with a default feature called `serde`, which allows running any function on a web worker under the following two conditions:
@@ -35,7 +40,7 @@ This is useful for users that do not want a direct serde dependency. Internally,
3540

3641
You can then start using the library without further setup.
3742
If you plan on using the global `WebWorkerPool` (using the iterator extensions or `worker_pool()`), you can *optionally* configure this pool:
38-
```rust,no_run
43+
```rust
3944
// Importing it publicly will also expose the function on the JavaScript side.
4045
// You can instantiate the pool both via Rust and JS.
4146
pub use wasmworker::{init_worker_pool, WorkerPoolOptions};
@@ -45,7 +50,6 @@ async fn startup() {
4550
options.num_workers = Some(2); // Default is navigator.hardwareConcurrency
4651
init_worker_pool(options).await.expect("Worker pool already initialized");
4752
}
48-
# fn main() {}
4953
```
5054

5155
### Outsourcing tasks
@@ -55,11 +59,12 @@ The library offers three ways of outsourcing function calls onto concurrent work
5559
3. `par_map`: an extension to regular iterators, which allows to execute a function on every element of the iterator in parallel using the default worker pool.
5660

5761
All approaches require the functions that should be executed to be annotated with the `#[webworker_fn]` macro.
58-
This macro ensures that the functions are available to the web worker instances:
62+
This macro ensures that the functions are available to the web worker instances.
63+
To execute such a function, pass its `WebWorkerFn` handle (obtained via the `webworker!()` macro) to a worker:
5964

60-
```rust,no_run
65+
```rust
6166
use serde::{Deserialize, Serialize};
62-
use wasmworker_proc_macro::webworker_fn;
67+
use wasmworker::{webworker, webworker_fn};
6368

6469
/// An arbitrary type that is (de)serializable.
6570
#[derive(Serialize, Deserialize)]
@@ -71,65 +76,52 @@ pub fn sort_vec(mut v: VecType) -> VecType {
7176
v.0.sort();
7277
v
7378
}
74-
# fn main() {}
75-
```
76-
77-
Whenever we want to execute a function, we need to pass the corresponding `WebWorkerFn` object to the worker.
78-
This object describes the function to the worker and can be safely obtained via the `webworker!()` macro:
79-
80-
```rust,no_run
81-
# use serde::{Deserialize, Serialize};
82-
# use wasmworker_proc_macro::webworker_fn;
83-
# #[derive(Serialize, Deserialize)]
84-
# pub struct VecType(Vec<u8>);
85-
# #[webworker_fn]
86-
# pub fn sort_vec(mut v: VecType) -> VecType { v.0.sort(); v }
87-
use wasmworker::webworker;
8879

89-
# fn main() {
80+
// Obtain a type-safe handle to the function:
9081
let ww_sort = webworker!(sort_vec);
91-
# }
9282
```
9383

9484
#### WebWorker
9585
We can instantiate our own workers and run functions on them:
96-
```rust,no_run
97-
# use serde::{Deserialize, Serialize};
98-
# use wasmworker_proc_macro::webworker_fn;
99-
# #[derive(Serialize, Deserialize, PartialEq, Debug)]
100-
# pub struct VecType(Vec<u8>);
101-
# #[webworker_fn]
102-
# pub fn sort_vec(mut v: VecType) -> VecType { v.0.sort(); v }
103-
use wasmworker::{webworker, WebWorker};
104-
105-
# async fn example() {
86+
```rust
87+
use serde::{Deserialize, Serialize};
88+
use wasmworker::{webworker, webworker_fn, WebWorker};
89+
90+
#[derive(Serialize, Deserialize)]
91+
pub struct VecType(Vec<u8>);
92+
93+
#[webworker_fn]
94+
pub fn sort_vec(mut v: VecType) -> VecType {
95+
v.0.sort();
96+
v
97+
}
98+
10699
let worker = WebWorker::new(None).await.expect("Couldn't create worker");
107-
let res = worker.run(webworker!(sort_vec), &VecType(vec![5, 2, 8])).await;
108-
assert_eq!(res.0, vec![2, 5, 8]);
109-
# }
110-
# fn main() {}
100+
let sorted = worker.run(webworker!(sort_vec), &VecType(vec![3, 1, 2])).await;
101+
assert_eq!(sorted.0, vec![1, 2, 3]);
111102
```
112103

113104
#### WebWorkerPool
114105
Most of the time, we probably want to schedule tasks to a pool of workers, though.
115106
The default worker pool is instantiated on first use and can be configured using `init_worker_pool()` as described above.
116107
It uses a round-robin scheduler (with the second option being a load based scheduler), a number of `navigator.hardwareConcurrency` separate workers, and the default inferred path.
117108

118-
```rust,no_run
119-
# use serde::{Deserialize, Serialize};
120-
# use wasmworker_proc_macro::webworker_fn;
121-
# #[derive(Serialize, Deserialize, PartialEq, Debug)]
122-
# pub struct VecType(Vec<u8>);
123-
# #[webworker_fn]
124-
# pub fn sort_vec(mut v: VecType) -> VecType { v.0.sort(); v }
125-
use wasmworker::{webworker, worker_pool};
109+
```rust
110+
use serde::{Deserialize, Serialize};
111+
use wasmworker::{webworker, webworker_fn, worker_pool};
112+
113+
#[derive(Serialize, Deserialize)]
114+
pub struct VecType(Vec<u8>);
115+
116+
#[webworker_fn]
117+
pub fn sort_vec(mut v: VecType) -> VecType {
118+
v.0.sort();
119+
v
120+
}
126121

127-
# async fn example() {
128122
let worker_pool = worker_pool().await;
129-
let res = worker_pool.run(webworker!(sort_vec), &VecType(vec![5, 2, 8])).await;
130-
assert_eq!(res.0, vec![2, 5, 8]);
131-
# }
132-
# fn main() {}
123+
let sorted = worker_pool.run(webworker!(sort_vec), &VecType(vec![3, 1, 2])).await;
124+
assert_eq!(sorted.0, vec![1, 2, 3]);
133125
```
134126

135127
#### Iterator extension
@@ -153,7 +145,7 @@ First, define an async function with the `#[webworker_channel_fn]` macro:
153145

154146
```rust,ignore
155147
use wasmworker::Channel;
156-
use wasmworker_proc_macro::webworker_channel_fn;
148+
use wasmworker::webworker_channel_fn;
157149
158150
#[derive(Serialize, Deserialize)]
159151
pub struct Progress { pub percent: u8 }
@@ -245,36 +237,43 @@ No Rust-side changes are needed — `import.meta.url` resolves correctly when th
245237
If your build setup places the wasm-bindgen glue or WASM binary at non-standard locations
246238
(e.g., hashed filenames, nested directories), you can override the paths explicitly:
247239

248-
```rust,no_run
240+
```rust
249241
use wasmworker::{init_worker_pool, WorkerPoolOptions};
250242

251-
# async fn example() -> Result<(), wasmworker::AlreadyInitialized> {
252243
let mut options = WorkerPoolOptions::new();
253244
// Path to the wasm-bindgen glue file (used by worker blob's import())
254245
options.path = Some("/assets/myapp.js".to_string());
255246
// Path to the WASM binary (passed to wasm-bindgen's init function)
256247
options.path_bg = Some("/assets/myapp_bg.wasm".to_string());
257-
init_worker_pool(options).await?;
258-
# Ok(())
259-
# }
260-
# fn main() {}
248+
init_worker_pool(options).await.unwrap();
261249
```
262250

263251
#### Precompiling WASM
264252

265253
To reduce bandwidth (fetch WASM once instead of once per worker), you can precompile and share the module:
266254

267-
```rust,no_run
268-
# use wasmworker::{init_worker_pool, WorkerPoolOptions};
269-
# async fn example() -> Result<(), wasmworker::AlreadyInitialized> {
255+
```rust
256+
use wasmworker::{init_worker_pool, WorkerPoolOptions};
257+
270258
let mut options = WorkerPoolOptions::new();
271259
options.precompile_wasm = Some(true);
272-
init_worker_pool(options).await?;
273-
# Ok(())
274-
# }
275-
# fn main() {}
260+
init_worker_pool(options).await.unwrap();
276261
```
277262

263+
### Idle timeout
264+
265+
Workers can be automatically terminated after a period of inactivity and transparently recreated when new tasks arrive. This is useful for freeing resources in applications where worker usage is intermittent:
266+
267+
```rust
268+
use wasmworker::{init_worker_pool, WorkerPoolOptions};
269+
270+
let mut options = WorkerPoolOptions::new();
271+
options.idle_timeout_ms = Some(5000); // Terminate idle workers after 5 seconds
272+
init_worker_pool(options).await.unwrap();
273+
```
274+
275+
You can inspect the pool state using `num_active_workers()` to see how many workers are currently alive.
276+
278277
## FAQ
279278
1. _Why would you not want to use SharedArrayBuffers?_
280279

demo/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ tokio = { version = "1.43", features = ["sync"] }
2626
wasm-bindgen = "0.2"
2727
wasm-bindgen-futures = "0.4"
2828
wasmworker = { workspace = true }
29-
wasmworker-proc-macro = { workspace = true }
3029

3130
[dependencies.web-sys]
3231
features = [

demo/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use send_wrapper::SendWrapper;
22
use serde::{Deserialize, Serialize};
33
use tokio::sync::OnceCell;
44
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, UnwrapThrowExt};
5+
use wasmworker::webworker_fn;
56
use wasmworker::{iter_ext::IteratorExt, webworker, worker_pool, WebWorker};
6-
use wasmworker_proc_macro::webworker_fn;
77
use web_sys::{HtmlElement, HtmlInputElement};
88

99
/// A wrapper type to demonstrate serde functionality.

proc-macro/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "wasmworker-proc-macro"
3-
version = "0.2.1"
3+
version = "0.3.0"
44
edition = "2021"
55

66
description.workspace = true

0 commit comments

Comments
 (0)