structz_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, parse_quote, punctuated::Punctuated};
4
5mod parse;
6
7use parse::*;
8
9#[proc_macro]
10pub fn stru(input: TokenStream) -> TokenStream {
11    let ReExportStructz {
12        path,
13        other: AnonymousStruct(input),
14    } = parse_macro_input!(input as ReExportStructz<AnonymousStruct>);
15    let fields: Vec<_> = input
16        .into_iter()
17        .map(|(ident, expr)| match expr {
18            Some(expr) => quote! { (<#path::ident!(#ident)>::default(), #expr) },
19            None => quote! { (<#path::ident!(#ident)>::default(), #ident) },
20        })
21        .collect();
22    quote! {
23        #path::__tuplez::tuple!(#(#fields),*)
24    }
25    .into()
26}
27
28#[proc_macro]
29pub fn stru_t(input: TokenStream) -> TokenStream {
30    let ReExportStructz {
31        path,
32        other: AnonymousStructType(input),
33    } = parse_macro_input!(input as ReExportStructz<AnonymousStructType>);
34    let fields: Vec<_> = input
35        .into_iter()
36        .map(|(ident, ty)| quote! { (#path::ident!(#ident), #ty) })
37        .collect();
38    quote! {
39        #path::__tuplez::tuple_t!(#(#fields),*)
40    }
41    .into()
42}
43
44#[proc_macro_attribute]
45pub fn named_args(_: TokenStream, item: TokenStream) -> TokenStream {
46    let mut input = parse_macro_input!(item as syn::ItemFn);
47    let mut args = vec![];
48    let mut has_self = None;
49    for arg in input.sig.inputs {
50        match arg {
51            syn::FnArg::Receiver(arg) => has_self = Some(arg),
52            syn::FnArg::Typed(arg) => {
53                if let syn::Pat::Ident(pat) = *arg.pat {
54                    args.push((pat, arg.ty))
55                } else {
56                    return quote! {
57                       compile_error!("arguments must be an identifier or receiver");
58                    }
59                    .into();
60                }
61            }
62        }
63    }
64    args.sort_by(|x, y| x.0.ident.cmp(&y.0.ident));
65    let (idents, tys): (Vec<syn::PatIdent>, Vec<Box<syn::Type>>) = args.into_iter().unzip();
66    let struct_type: syn::Type = parse_quote! {
67        ::structz::stru_t! { #(#idents: #tys),* }
68    };
69    let mut inputs = Punctuated::new();
70    if let Some(arg) = has_self {
71        inputs.push(syn::FnArg::Receiver(arg));
72    }
73    inputs.push(syn::FnArg::Typed(syn::PatType {
74        attrs: vec![],
75        pat: parse_quote! { structz_s },
76        colon_token: Default::default(),
77        ty: Box::new(struct_type),
78    }));
79    input.sig.inputs = inputs;
80    let mut unpack: Vec<(syn::Pat, syn::Type)> = vec![];
81    for ident in idents {
82        let ident = ident.ident;
83        unpack.push((
84            parse_quote! { #ident },
85            parse_quote! { ::structz::ident!(#ident) },
86        ))
87    }
88    let (pat, ident_tys): (Vec<syn::Pat>, Vec<syn::Type>) = unpack.into_iter().unzip();
89    let pat: syn::Pat = parse_quote! { ::structz::__tuplez::tuple_pat!( #( (_, #pat) ),* )};
90    let ident_tys: syn::Type =
91        parse_quote! { ::structz::__tuplez::tuple_t!( #( (#ident_tys, #tys) ),* )};
92    let unpack: syn::Stmt = parse_quote! { let #pat: #ident_tys = structz_s; };
93    input.block.stmts.insert(0, unpack);
94    quote!(#input).into()
95}