diesel_derives/
diesel_for_each_tuple.rs1use 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 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}