web_workers_derive/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Data, DeriveInput, Fields};
4
5#[proc_macro_derive(MessageSend)]
6pub fn derive_message_send(input: TokenStream) -> TokenStream {
7 let input = parse_macro_input!(input as DeriveInput);
8 let name = input.ident;
9 let generics = input.generics;
10 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
11
12 let expanded = match input.data {
13 Data::Struct(data) => match data.fields {
14 Fields::Named(fields) => {
15 let field_names: Vec<_> = fields.named.iter().map(|f| f.ident.as_ref().unwrap()).collect();
16 let field_tys: Vec<_> = fields.named.iter().map(|f| &f.ty).collect();
17 quote! {
18 impl #impl_generics ::web_workers::web::message::MessageSend for #name #ty_generics #where_clause {
19 type Send = (<(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::Send,);
20 fn send<E: ::std::iter::Extend<::wasm_bindgen::JsValue>>(self, transfer: &mut E) -> ::web_workers::web::message::RawMessage<Self::Send> {
21 let #name { #(#field_names,)* } = self;
22 let inner = (#(#field_names,)*);
23 let msg = <(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::send(inner, transfer);
24 ::web_workers::web::message::RawMessage { serialize: msg.serialize, send: msg.send.map(|s| (s,)) }
25 }
26 fn receive(serialized: Option<::wasm_bindgen::JsValue>, sent: Option<Self::Send>) -> Self {
27 let (inner_send,) = sent.expect("expected Send for struct");
28 let inner = <(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::receive(serialized, Some(inner_send));
29 let (#(#field_names,)*) = inner;
30 Self { #(#field_names,)* }
31 }
32 }
33 }
34 }
35 Fields::Unnamed(fields) => {
36 let field_tys: Vec<_> = fields.unnamed.iter().map(|f| &f.ty).collect();
37 let n = field_tys.len();
38 let idents: Vec<_> = (0..n).map(|i| quote::format_ident!("__field{}", i)).collect();
39 quote! {
40 impl #impl_generics ::web_workers::web::message::MessageSend for #name #ty_generics #where_clause {
41 type Send = (<(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::Send,);
42 fn send<E: ::std::iter::Extend<::wasm_bindgen::JsValue>>(self, transfer: &mut E) -> ::web_workers::web::message::RawMessage<Self::Send> {
43 let #name(#(#idents,)*) = self;
44 let inner = (#(#idents,)*);
45 let msg = <(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::send(inner, transfer);
46 ::web_workers::web::message::RawMessage { serialize: msg.serialize, send: msg.send.map(|s| (s,)) }
47 }
48 fn receive(serialized: Option<::wasm_bindgen::JsValue>, sent: Option<Self::Send>) -> Self {
49 let (inner_send,) = sent.expect("expected Send for tuple struct");
50 let inner = <(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::receive(serialized, Some(inner_send));
51 let (#(#idents,)*) = inner;
52 Self(#(#idents,)*)
53 }
54 }
55 }
56 }
57 Fields::Unit => quote! {
58 impl #impl_generics ::web_workers::web::message::MessageSend for #name #ty_generics #where_clause {
59 type Send = ();
60 fn send<E: ::std::iter::Extend<::wasm_bindgen::JsValue>>(self, _: &mut E) -> ::web_workers::web::message::RawMessage<Self::Send> {
61 ::web_workers::web::message::RawMessage { serialize: None, send: None }
62 }
63 fn receive(_serialized: Option<::wasm_bindgen::JsValue>, _sent: Option<Self::Send>) -> Self { Self }
64 }
65 },
66 },
67 Data::Enum(_) => {
68 return syn::Error::new_spanned(name, "MessageSend derive for enums not yet supported - implement manually via tuple delegation").to_compile_error().into();
69 }
70 Data::Union(_) => {
71 return syn::Error::new_spanned(name, "MessageSend derive does not support unions").to_compile_error().into();
72 }
73 };
74
75 expanded.into()
76}