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}