Skip to content
Merged
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
10 changes: 8 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,30 @@ jobs:

clippy:
runs-on: ubuntu-latest
strategy:
matrix:
features: ["--all-features", "--no-default-features --features serde,codec-pot"]

steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --all-features -- -D warnings
- run: cargo clippy ${{ matrix.features }} -- -D warnings

doc-test:
runs-on: ubuntu-latest
strategy:
matrix:
features: ["--all-features", "--no-default-features --features serde,macros,codec-pot"]

steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Run doctest
run: cargo test --doc --all-features
run: cargo test --doc ${{ matrix.features }}

test:
runs-on: ubuntu-latest
Expand Down
29 changes: 29 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ keywords.workspace = true
[dependencies]
futures = "0.3"
js-sys = { version = "0.3" }
postcard = { version = "1.1", features = ["alloc"] }
send_wrapper = "0.6"
serde = { version = "1.0", features = ["derive"] }
serde_bytes = "0.11"
Expand All @@ -40,6 +39,8 @@ tokio = { version = "1.4", features = ["sync"] }
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
log = "0.4"
postcard = { version = "1.1", features = ["alloc"], optional = true }
pot = { version = "3.0.1", optional = true }

[dependencies.web-sys]
features = [
Expand All @@ -63,8 +64,10 @@ version = "0.3"
wasmworker-proc-macro = { workspace = true }

[features]
default = ["serde"]
default = ["serde", "codec-postcard"]
serde = []
codec-postcard = ["dep:postcard"]
codec-pot = ["dep:pot"]
macros = ["wasmworker-proc-macro"]

[dependencies.wasmworker-proc-macro]
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ In contrast to many other libraries like [wasm-bindgen-rayon](https://github.com

- [Usage](#usage)
- [Setting up](#setting-up)
- [Serialization codec](#serialization-codec)
- [Outsourcing tasks](#outsourcing-tasks)
- [WebWorker](#webworker)
- [WebWorkerPool](#webworkerpool)
Expand Down Expand Up @@ -38,6 +39,18 @@ The `wasmworker` crate comes with a default feature called `serde`, which allows
Without the `serde` feature, only functions with the type `fn(Box<[u8]>) -> Box<[u8]>` can be run on a worker.
This is useful for users that do not want a direct serde dependency. Internally, the library always uses serde, though.

#### Serialization codec
By default, `wasmworker` uses [postcard](https://crates.io/crates/postcard) for internal serialization.
Postcard is compact and fast, making it ideal for the typical WebWorker use case (passing `Vec<T>`, structs, primitives).

For complex types like `Rc<T>` or cyclic structures, you can use [pot](https://crates.io/crates/pot) instead.
Note that pot has significantly higher serialization overhead and larger output sizes, so it should only be used when postcard cannot handle your data types.

```toml
[dependencies]
wasmworker = { version = "0.3", default-features = false, features = ["serde", "macros", "codec-pot"] }
```

You can then start using the library without further setup.
If you plan on using the global `WebWorkerPool` (using the iterator extensions or `worker_pool()`), you can *optionally* configure this pool:
```rust
Expand Down
3 changes: 2 additions & 1 deletion src/channel_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ pub struct ChannelTask<R> {

impl<R: DeserializeOwned> ChannelTask<R> {
/// Create a new `ChannelTask` from a channel and a result receiver.
pub(crate) fn new(channel: Channel, result_rx: oneshot::Receiver<Vec<u8>>) -> Self {
#[doc(hidden)]
pub fn new(channel: Channel, result_rx: oneshot::Receiver<Vec<u8>>) -> Self {
Self {
channel,
result_rx,
Expand Down
29 changes: 29 additions & 0 deletions src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
/// This wrapper function encapsulates our internal serialization format.
/// It is used internally to prepare values before sending them to a worker
/// or back to the main thread via `postMessage`.
#[cfg(feature = "codec-postcard")]
pub fn to_bytes<T: Serialize>(value: &T) -> Box<[u8]> {
postcard::to_allocvec(value)
.expect("WebWorker serialization failed")
Expand All @@ -12,6 +13,34 @@ pub fn to_bytes<T: Serialize>(value: &T) -> Box<[u8]> {
/// This wrapper function encapsulates our internal serialization format.
/// It is used internally to prepare values after receiving them from a worker
/// or the main thread via `postMessage`.
#[cfg(feature = "codec-postcard")]
pub fn from_bytes<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> T {
postcard::from_bytes(bytes).expect("WebWorker deserialization failed")
}

#[cfg(all(feature = "codec-pot", not(feature = "codec-postcard")))]
const POT_CONFIG: pot::Config = pot::Config::new().compatibility(pot::Compatibility::V4);

/// This wrapper function encapsulates our internal serialization format.
/// It is used internally to prepare values before sending them to a worker
/// or back to the main thread via `postMessage`.
#[cfg(all(feature = "codec-pot", not(feature = "codec-postcard")))]
pub fn to_bytes<T: Serialize>(value: &T) -> Box<[u8]> {
POT_CONFIG
.serialize(value)
.expect("WebWorker serialization failed")
.into()
}

/// This wrapper function encapsulates our internal serialization format.
/// It is used internally to prepare values after receiving them from a worker
/// or the main thread via `postMessage`.
#[cfg(all(feature = "codec-pot", not(feature = "codec-postcard")))]
pub fn from_bytes<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> T {
POT_CONFIG
.deserialize(bytes)
.expect("WebWorker deserialization failed")
}

#[cfg(not(any(feature = "codec-postcard", feature = "codec-pot")))]
compile_error!("No codec selected. Enable `codec-postcard` (default) or `codec-pot`.");
Loading