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 = Ident::new(&format!("T{i}"), call_side);
19            let st = Ident::new(&format!("ST{i}"), call_side);
20            let tt = Ident::new(&format!("TT{i}"), call_side);
21            let i = syn::Index::from(i);
22            quote!((#i) -> #t, #st, #tt,)
23        })
24        .collect::<Vec<_>>();
25
26    let mut out = Vec::with_capacity(input.max_size as usize);
27
28    for i in 0..input.max_size {
29        let items = &pairs[0..=i as usize];
30        let tuple = i + 1;
31        out.push(quote! {
32            #tuple {
33                #(#items)*
34            }
35        });
36    }
37    let input = input.inner;
38
39    quote! {
40        #input! {
41            #(#out)*
42        }
43    }
44}
45
46pub struct ForEachTupleInput {
47    inner: Ident,
48    max_size: i32,
49}
50
51impl syn::parse::Parse for ForEachTupleInput {
52    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
53        let inner = input.parse()?;
54        let max_size = if input.peek(syn::Token![,]) {
55            let _ = input.parse::<syn::Token![,]>();
56            input.parse::<syn::LitInt>()?.base10_parse()?
57        } else if input.is_empty() {
58            MAX_TUPLE_SIZE
59        } else {
60            unreachable!("Invalid syntax")
61        };
62        Ok(Self { inner, max_size })
63    }
64}