diesel_derives/
diesel_for_each_tuple.rs

1use proc_macro2::{Ident, Span, TokenStream};
2use quote::quote;
3
4#[cfg(not(feature = "32-column-tables"))]
5pub const MAX_TUPLE_SIZE: i32 = 16;
6#[cfg(all(not(feature = "64-column-tables"), feature = "32-column-tables"))]
7pub const MAX_TUPLE_SIZE: i32 = 32;
8#[cfg(all(not(feature = "128-column-tables"), feature = "64-column-tables"))]
9pub const MAX_TUPLE_SIZE: i32 = 64;
10#[cfg(feature = "128-column-tables")]
11pub const MAX_TUPLE_SIZE: i32 = 128;
12
13pub(crate) fn expand(input: ForEachTupleInput) -> TokenStream {
14    let call_side = Span::mixed_site();
15
16    let pairs = (0..input.max_size as usize)
17        .map(|i| {
18            let (t, st, tt) = if i == 0 {
19                // special case these, as #[doc(fake_variadic)]
20                // uses the first generic parameter as `T_n` and `T_n` looks
21                // much better than `T0_n`
22                let t = Ident::new("T", call_side);
23                let st = Ident::new("ST", call_side);
24                let tt = Ident::new("TT", call_side);
25                (t, st, tt)
26            } else {
27                let t = Ident::new(&format!("T{i}"), call_side);
28                let st = Ident::new(&format!("ST{i}"), call_side);
29                let tt = Ident::new(&format!("TT{i}"), call_side);
30                (t, st, tt)
31            };
32            let i = syn::Index::from(i);
33            quote!((#i) -> #t, #st, #tt,)
34        })
35        .collect::<Vec<_>>();
36
37    let mut out = Vec::with_capacity(input.max_size as usize);
38
39    for i in 0..input.max_size {
40        let items = &pairs[0..=i as usize];
41        let tuple = i + 1;
42        out.push(quote! {
43            #tuple {
44                #(#items)*
45            }
46        });
47    }
48    let input = input.inner;
49
50    quote! {
51        #input! {
52            #(#out)*
53        }
54    }
55}
56
57pub struct ForEachTupleInput {
58    inner: Ident,
59    max_size: i32,
60}
61
62impl syn::parse::Parse for ForEachTupleInput {
63    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
64        let inner = input.parse()?;
65        let max_size = if input.peek(syn::Token![,]) {
66            let _ = input.parse::<syn::Token![,]>();
67            input.parse::<syn::LitInt>()?.base10_parse()?
68        } else if input.is_empty() {
69            MAX_TUPLE_SIZE
70        } else {
71            unreachable!("Invalid syntax")
72        };
73        Ok(Self { inner, max_size })
74    }
75}