Skip to main content

web_workers_derive/
lib.rs

1use 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}