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}