Skip to content
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ test-results/
playwright-report/
blob-report/
playwright/.cache/
.DS_Store
118 changes: 16 additions & 102 deletions Cargo.lock

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

8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ readme = "README.md"
keywords = ["webworker", "parallelism", "wasm"]

[workspace.dependencies]
wasmworker = { version = "0.1", path = ".", features = ["serde"]}
wasmworker = { version = "0.1", path = ".", features = ["serde"] }
wasmworker-proc-macro = { version = "0.1", path = "proc-macro" }

[package]
Expand All @@ -30,7 +30,7 @@ keywords.workspace = true
[dependencies]
futures = "0.3"
js-sys = { version = "0.3" }
postcard = { version = "1.0", features = ["alloc"] }
pot = "3.0"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for switching the serialisation?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched, because for complex structure, like Rc and others, postcard just failed. That's why I went this way. Also pot is self-describing. Which is theoretically not needed here, but handles complex cases like above cleanly.

send_wrapper = "0.6"
serde = { version = "1.0", features = ["derive"] }
serde_bytes = "0.11"
Expand All @@ -39,6 +39,7 @@ thiserror = "2.0"
tokio = { version = "1.4", features = ["sync"] }
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
log = "*"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
log = "*"
log = "0.4"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah makes sense!


[dependencies.web-sys]
features = [
Expand All @@ -52,6 +53,9 @@ features = [
"BlobPropertyBag",
"Url",
"Navigator",
"MessagePort",
"MessageChannel",
"Response",
]
version = "0.3"

Expand Down
2 changes: 1 addition & 1 deletion demo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async fn worker() -> &'static WebWorker {
WORKER
.get_or_init(move || async {
SendWrapper::new(
WebWorker::with_path(None, None)
WebWorker::with_path(None, None, None)
.await
.expect_throw("Couldn't instantiate WebWorker"),
)
Expand Down
1 change: 1 addition & 0 deletions proc-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ proc-macro = true
[dependencies]
syn = { version = "2.0", features = ["full", "extra-traits"] }
quote = "1.0"
log = "*"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
log = "*"
log = "0.4"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah makes sense!

34 changes: 29 additions & 5 deletions proc-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,48 @@

use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, ItemFn};
use syn::{parse_macro_input, token::Async, ItemFn};

/// A procedural macro that exports a function for use with a webworker.
#[proc_macro_attribute]
pub fn webworker_fn(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemFn);
let mut input = parse_macro_input!(item as ItemFn);
let fn_name = &input.sig.ident;

// make the input function always async
input.sig.asyncness = Some(Async::default());

// the core function should have 2 inputs always
let output = if input.sig.inputs.len() == 1 {
let func_vis = &input.vis; // like pub
let func_block = &input.block; // { some statement or expression here }
let func_name = &input.sig.ident; // function nameinput
let func_generics = &input.sig.generics;
let func_inputs = &input.sig.inputs;
let func_output = &input.sig.output;
quote! {
#func_vis async fn #func_name #func_generics(#func_inputs, channel: Option<wasmworker::Channel>) #func_output {
#func_block
}
}
} else {
quote! {
#input
}
};

// Generate a module with the wrapper function
let wrapper_fn_name = format_ident!("__webworker_{}", fn_name);
let mod_code = quote! {
pub mod #fn_name {
pub const __WEBWORKER: () = ();
const _: () = {
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn #wrapper_fn_name(arg: Box<[u8]>) -> Box<[u8]> {
pub async fn #wrapper_fn_name(arg: Box<[u8]>, port: wasm_bindgen::JsValue) -> Box<[u8]> {
use wasm_bindgen::JsCast;
let arg = wasmworker::convert::from_bytes(&arg);
let res = super::#fn_name(arg);
let channel = port.dyn_into::<wasmworker::MessagePort>().ok().map(wasmworker::Channel::from);
let res = super::#fn_name(arg, channel).await;
let res = wasmworker::convert::to_bytes(&res);
res
}
Expand All @@ -31,7 +55,7 @@ pub fn webworker_fn(_attr: TokenStream, item: TokenStream) -> TokenStream {

// Combine everything into the final output
let expanded = quote! {
#input
#output

#mod_code
};
Expand Down
Loading