non_structural_derive_macro/
lib.rs1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens};
3use syn::parse::Parse;
4use syn::punctuated::Punctuated;
5use syn::{parse_quote, Ident, Token};
6use synstructure::{decl_attribute, AddBounds, Structure};
7
8struct AttrConfig {
9 pub elems: Punctuated<Ident, Token![,]>,
10}
11
12impl Parse for AttrConfig {
13 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
14 let elems = input.parse_terminated(Ident::parse, Token![,])?;
15 Ok(AttrConfig { elems })
16 }
17}
18
19fn non_structural_derive_impl(attr: TokenStream, mut s: Structure) -> TokenStream {
20 let cfg: AttrConfig = match syn::parse2(attr) {
21 Ok(x) => x,
22 Err(e) => return e.into_compile_error(),
23 };
24
25 let mut bodies = vec![];
26 for name in cfg.elems {
27 let (name, is_unsafe) = match &*name.to_string() {
28 "Send" | "Sync" => (quote!(::core::marker::#name), true),
29 "Unpin" => (quote!(::core::marker::#name), false),
30 "UnwindSafe" => (quote!(::core::panic::#name), false),
31 "RefUnwindSafe" => (quote!(::core::panic::#name), false),
32 "DynSync" | "DynSend" => (quote!(::rustc_data_structures::marker::#name), true),
33 _ => {
34 return syn::Error::new_spanned(name, "not a known auto-trait")
35 .into_compile_error()
36 .into()
37 }
38 };
39 s.add_bounds(AddBounds::Generics);
40 let impl_source = if is_unsafe {
41 quote!(gen unsafe impl #name for @Self {})
42 } else {
43 quote!(gen impl #name for @Self {})
44 };
45 let impl_ = s.gen_impl(impl_source);
46
47 let mut generics = s.ast().generics.clone();
48 for par in generics.type_params_mut() {
49 par.bounds.push(parse_quote! { #name });
50 }
51 let where_ = generics.where_clause.take();
52
53 let fields = s
54 .variants()
55 .iter()
56 .flat_map(|v| v.bindings())
57 .map(|b| &b.ast().ty);
58
59 bodies.push(quote! {
60 const _: () = {
61 #impl_
62
63 fn _check_bound<T: #name>() {}
64 fn _validate_fields #generics () #where_ {
65 #(
66 _check_bound::<#fields>();
67 )*
68 }
69 };
70 });
71 }
72 Some(s.ast().into_token_stream())
73 .into_iter()
74 .chain(bodies.into_iter())
75 .collect()
76}
77
78decl_attribute!([non_structural_derive] => non_structural_derive_impl);