use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};
#[proc_macro_derive(MessageSend)]
pub fn derive_message_send(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let generics = input.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let expanded = match input.data {
Data::Struct(data) => match data.fields {
Fields::Named(fields) => {
let field_names: Vec<_> = fields.named.iter().map(|f| f.ident.as_ref().unwrap()).collect();
let field_tys: Vec<_> = fields.named.iter().map(|f| &f.ty).collect();
quote! {
impl #impl_generics ::web_workers::web::message::MessageSend for #name #ty_generics #where_clause {
type Send = (<(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::Send,);
fn send<E: ::std::iter::Extend<::wasm_bindgen::JsValue>>(self, transfer: &mut E) -> ::web_workers::web::message::RawMessage<Self::Send> {
let #name { #(#field_names,)* } = self;
let inner = (#(#field_names,)*);
let msg = <(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::send(inner, transfer);
::web_workers::web::message::RawMessage { serialize: msg.serialize, send: msg.send.map(|s| (s,)) }
}
fn receive(serialized: Option<::wasm_bindgen::JsValue>, sent: Option<Self::Send>) -> Self {
let (inner_send,) = sent.expect("expected Send for struct");
let inner = <(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::receive(serialized, Some(inner_send));
let (#(#field_names,)*) = inner;
Self { #(#field_names,)* }
}
}
}
}
Fields::Unnamed(fields) => {
let field_tys: Vec<_> = fields.unnamed.iter().map(|f| &f.ty).collect();
let n = field_tys.len();
let idents: Vec<_> = (0..n).map(|i| quote::format_ident!("__field{}", i)).collect();
quote! {
impl #impl_generics ::web_workers::web::message::MessageSend for #name #ty_generics #where_clause {
type Send = (<(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::Send,);
fn send<E: ::std::iter::Extend<::wasm_bindgen::JsValue>>(self, transfer: &mut E) -> ::web_workers::web::message::RawMessage<Self::Send> {
let #name(#(#idents,)*) = self;
let inner = (#(#idents,)*);
let msg = <(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::send(inner, transfer);
::web_workers::web::message::RawMessage { serialize: msg.serialize, send: msg.send.map(|s| (s,)) }
}
fn receive(serialized: Option<::wasm_bindgen::JsValue>, sent: Option<Self::Send>) -> Self {
let (inner_send,) = sent.expect("expected Send for tuple struct");
let inner = <(#(#field_tys,)*) as ::web_workers::web::message::MessageSend>::receive(serialized, Some(inner_send));
let (#(#idents,)*) = inner;
Self(#(#idents,)*)
}
}
}
}
Fields::Unit => quote! {
impl #impl_generics ::web_workers::web::message::MessageSend for #name #ty_generics #where_clause {
type Send = ();
fn send<E: ::std::iter::Extend<::wasm_bindgen::JsValue>>(self, _: &mut E) -> ::web_workers::web::message::RawMessage<Self::Send> {
::web_workers::web::message::RawMessage { serialize: None, send: None }
}
fn receive(_serialized: Option<::wasm_bindgen::JsValue>, _sent: Option<Self::Send>) -> Self { Self }
}
},
},
Data::Enum(_) => {
return syn::Error::new_spanned(name, "MessageSend derive for enums not yet supported - implement manually via tuple delegation").to_compile_error().into();
}
Data::Union(_) => {
return syn::Error::new_spanned(name, "MessageSend derive does not support unions").to_compile_error().into();
}
};
expanded.into()
}