Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function Worker #267

Merged
merged 39 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7162bb9
Fix typo.
futursolo Oct 28, 2022
97679fd
Move worker into actor folder.
futursolo Oct 28, 2022
f1f9ed9
Add some oneshot implementation.
futursolo Oct 28, 2022
edcee50
Finish oneshot worker.
futursolo Nov 2, 2022
0f59a8a
Strip 'static from worker definition.
futursolo Nov 2, 2022
0b07b5d
Strip serde from message definition.
futursolo Nov 2, 2022
79cac4c
Update example.
futursolo Nov 2, 2022
1f80f79
Initial Implementation of Reactor Worker.
futursolo Nov 2, 2022
9b1a0ec
Implement Spawner and Registrar.
futursolo Nov 2, 2022
4d8b324
Rename Receiver to Source.
futursolo Nov 2, 2022
86fe859
Allow any stream.
futursolo Nov 3, 2022
ce47d0c
Split bridge into receiver and sender.
futursolo Nov 3, 2022
0281ff7
Add docs.
futursolo Nov 3, 2022
96469da
Add oneshot macro.
futursolo Nov 3, 2022
e87374f
Add reactor macro.
futursolo Nov 3, 2022
e6bcbc4
Allows synchronous function for oneshot worker.
futursolo Nov 3, 2022
948d357
Move to Sink.
futursolo Nov 5, 2022
e5f6e18
Adjust design of reactor worker.
futursolo Nov 5, 2022
4083f48
Update reactor macro.
futursolo Nov 5, 2022
814f77d
Adjust oneshot signature.
futursolo Nov 5, 2022
4f4cfb6
Fix Actor Worker.
futursolo Nov 5, 2022
bd040ae
Make a reactor example.
futursolo Nov 5, 2022
2e59b07
Switch to send.
futursolo Nov 5, 2022
adc5a93
Minor adjustments.
futursolo Nov 5, 2022
37f230a
Add some tests.
futursolo Nov 5, 2022
085c6da
Update implementation.
futursolo Nov 5, 2022
586841f
Fix CI.
futursolo Nov 5, 2022
afb77c8
Skip macros in browser tests.
futursolo Nov 5, 2022
f0656cb
Adjust implementation.
futursolo Nov 5, 2022
167b104
(some) documentation
ranile Jun 4, 2023
879570e
add tests for prime example
ranile Jun 4, 2023
4f863fb
cargo fmt
ranile Jun 4, 2023
2676cc8
update CI
ranile Jun 17, 2023
b23a893
fix macro tests
ranile Jun 17, 2023
bda4428
syn 2
ranile Jun 17, 2023
8d4310a
fix typo
ranile Jun 17, 2023
61b5783
Update crates/worker-macros/src/worker_fn.rs
ranile Jun 17, 2023
eea4160
temp: disable chrome in workers CI
ranile Jun 23, 2023
658585c
disable prime example in CI
ranile Jun 23, 2023
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
16 changes: 12 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ jobs:
if [[ "$x" == "net" ]]; then
continue
fi
if [[ "$x" == "worker-macros" ]]; then
continue
fi
ranile marked this conversation as resolved.
Show resolved Hide resolved
wasm-pack test --headless --firefox --chrome crates/$x --all-features
wasm-pack test --headless --firefox --chrome crates/$x --no-default-features
done
Expand Down Expand Up @@ -107,6 +110,11 @@ jobs:
test-worker:
name: Test gloo-worker
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# example: [ markdown, prime ]
example: [ markdown ]
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master
Expand Down Expand Up @@ -135,16 +143,16 @@ jobs:

- name: Build and Run Test Server
run: |
cargo build -p example-markdown --bin example_markdown_test_server
nohup target/debug/example_markdown_test_server examples/markdown/dist &
cargo build -p example-${{ matrix.example }} --bin example_${{ matrix.example }}_test_server
nohup target/debug/example_${{ matrix.example }}_test_server examples/${{ matrix.example }}/dist &

- name: Build Test Worker
run: |
trunk build examples/markdown/index.html
trunk build examples/${{ matrix.example }}/index.html

- name: Run tests for gloo worker
run: |
wasm-pack test --headless --firefox --chrome examples/markdown
wasm-pack test --headless --chrome --firefox examples/${{ matrix.example }}


test-net:
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@ members = [
"crates/utils",
"crates/history",
"crates/worker",
"crates/worker-macros",
"crates/net",

"examples/markdown",
"examples/clock",
"examples/prime",
]

# Passing arguments to the docsrs builder in order to properly document cfg's.
Expand Down
24 changes: 24 additions & 0 deletions crates/worker-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "gloo-worker-macros"
version = "0.1.0"
authors = ["Rust and WebAssembly Working Group"]
edition = "2021"
readme = "README.md"
description = "Convenience crate for working with Web Workers"
repository = "https://github.com/rustwasm/gloo/tree/master/crates/worker"
homepage = "https://github.com/rustwasm/gloo"
license = "MIT OR Apache-2.0"
categories = ["api-bindings", "asynchronous", "wasm"]

[lib]
proc-macro = true

[dependencies]
proc-macro-crate = "1.2.1"
proc-macro2 = "1.0.47"
quote = "1.0.21"
syn = { version = "2.0.15", features = ["full"] }

[dev-dependencies]
trybuild = "1"
gloo = { path = "../..", features = ["futures"] }
24 changes: 24 additions & 0 deletions crates/worker-macros/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div align="center">

<h1><code>gloo-worker</code></h1>

<p>
<a href="https://crates.io/crates/gloo-worker"><img src="https://img.shields.io/crates/v/gloo-worker.svg?style=flat-square" alt="Crates.io version" /></a>
<a href="https://crates.io/crates/gloo-worker"><img src="https://img.shields.io/crates/d/gloo-worker.svg?style=flat-square" alt="Download" /></a>
<a href="https://docs.rs/gloo-worker"><img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square" alt="docs.rs docs" /></a>
</p>

<h3>
<a href="https://docs.rs/gloo-worker">API Docs</a>
<span> | </span>
<a href="https://github.com/rustwasm/gloo/blob/master/CONTRIBUTING.md">Contributing</a>
<span> | </span>
<a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>
</h3>

<sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
</div>

Gloo workers are a way to offload tasks to web workers. These are run concurrently using
[web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers).
It provides a neat abstraction over the browser's Web Workers API which can be consumed from anywhere.
30 changes: 30 additions & 0 deletions crates/worker-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use proc_macro::TokenStream;
use syn::parse_macro_input;

mod oneshot;
mod reactor;
mod worker_fn;

use oneshot::{oneshot_impl, OneshotFn};
use reactor::{reactor_impl, ReactorFn};
use worker_fn::{WorkerFn, WorkerName};

#[proc_macro_attribute]
pub fn reactor(attr: TokenStream, item: TokenStream) -> TokenStream {
let item = parse_macro_input!(item as WorkerFn<ReactorFn>);
let attr = parse_macro_input!(attr as WorkerName);

reactor_impl(attr, item)
.unwrap_or_else(|err| err.to_compile_error())
.into()
}

#[proc_macro_attribute]
pub fn oneshot(attr: TokenStream, item: TokenStream) -> TokenStream {
let item = parse_macro_input!(item as WorkerFn<OneshotFn>);
let attr = parse_macro_input!(attr as WorkerName);

oneshot_impl(attr, item)
.unwrap_or_else(|err| err.to_compile_error())
.into()
}
133 changes: 133 additions & 0 deletions crates/worker-macros/src/oneshot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{parse_quote, Ident, ReturnType, Signature, Type};

use crate::worker_fn::{WorkerFn, WorkerFnType, WorkerName};

pub struct OneshotFn {}

impl WorkerFnType for OneshotFn {
type OutputType = Type;
type RecvType = Type;

fn attr_name() -> &'static str {
"oneshot"
}

fn worker_type_name() -> &'static str {
"oneshot"
}

fn parse_recv_type(sig: &Signature) -> syn::Result<Self::RecvType> {
let mut inputs = sig.inputs.iter();
let arg = inputs
.next()
.ok_or_else(|| syn::Error::new_spanned(&sig.ident, "expected 1 argument"))?;

let ty = Self::extract_fn_arg_type(arg)?;

Self::assert_no_left_argument(inputs, 1)?;

Ok(ty)
}

fn parse_output_type(sig: &Signature) -> syn::Result<Self::OutputType> {
let ty = match &sig.output {
ReturnType::Default => {
parse_quote! { () }
}
ReturnType::Type(_, ty) => *ty.clone(),
};

Ok(ty)
}
}

pub fn oneshot_impl(
name: WorkerName,
mut worker_fn: WorkerFn<OneshotFn>,
) -> syn::Result<TokenStream> {
worker_fn.merge_worker_name(name)?;

let struct_attrs = worker_fn.filter_attrs_for_worker_struct();
let oneshot_impl_attrs = worker_fn.filter_attrs_for_worker_impl();
let phantom_generics = worker_fn.phantom_generics();
let oneshot_name = worker_fn.worker_name();
let fn_name = worker_fn.inner_fn_ident();
let inner_fn = worker_fn.print_inner_fn();

let WorkerFn {
recv_type: input_type,
generics,
output_type,
vis,
is_async,
..
} = worker_fn;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let fn_generics = ty_generics.as_turbofish();

let in_ident = Ident::new("_input", Span::mixed_site());

let fn_call = if is_async {
quote! { #fn_name #fn_generics (#in_ident).await }
} else {
quote! { #fn_name #fn_generics (#in_ident) }
};
let crate_name = WorkerFn::<OneshotFn>::worker_crate_name();

let quoted = quote! {
#(#struct_attrs)*
#[allow(unused_parens)]
#vis struct #oneshot_name #generics #where_clause {
inner: ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #output_type>>>,
_marker: ::std::marker::PhantomData<(#phantom_generics)>,
}

// we cannot disable any lints here because it will be applied to the function body
// as well.
#(#oneshot_impl_attrs)*
impl #impl_generics ::#crate_name::oneshot::Oneshot for #oneshot_name #ty_generics #where_clause {
type Input = #input_type;

fn create(#in_ident: Self::Input) -> Self {
#inner_fn

Self {
inner: ::std::boxed::Box::pin(
async move {
#fn_call
}
),
_marker: ::std::marker::PhantomData,
}
}
}

impl #impl_generics ::std::future::Future for #oneshot_name #ty_generics #where_clause {
type Output = #output_type;

fn poll(mut self: ::std::pin::Pin<&mut Self>, cx: &mut ::std::task::Context<'_>) -> ::std::task::Poll<Self::Output> {
::std::future::Future::poll(::std::pin::Pin::new(&mut self.inner), cx)
}
}

impl #impl_generics ::#crate_name::Registrable for #oneshot_name #ty_generics #where_clause {
type Registrar = ::#crate_name::oneshot::OneshotRegistrar<Self>;

fn registrar() -> Self::Registrar {
::#crate_name::oneshot::OneshotRegistrar::<Self>::new()
}
}

impl #impl_generics ::#crate_name::Spawnable for #oneshot_name #ty_generics #where_clause {
type Spawner = ::#crate_name::oneshot::OneshotSpawner<Self>;

fn spawner() -> Self::Spawner {
::#crate_name::oneshot::OneshotSpawner::<Self>::new()
}
}
};

Ok(quoted)
}
Loading