From 20e00a46d5362b5cb2049b3b51ebce61b7acb32a Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Wed, 24 May 2023 16:58:58 +0200 Subject: [PATCH] Provide non-conflicting impls up to a tuple size of 5 (This also uses a different strategy to generate these impls as that results in more maintainable code) --- diesel/src/pg/query_builder/distinct_on.rs | 53 ++++- diesel/src/type_impls/tuples.rs | 220 -------------------- diesel_derives/src/diesel_for_each_tuple.rs | 29 ++- 3 files changed, 76 insertions(+), 226 deletions(-) diff --git a/diesel/src/pg/query_builder/distinct_on.rs b/diesel/src/pg/query_builder/distinct_on.rs index 91772bd3605d..68703c9df160 100644 --- a/diesel/src/pg/query_builder/distinct_on.rs +++ b/diesel/src/pg/query_builder/distinct_on.rs @@ -7,7 +7,7 @@ use crate::query_builder::{ use crate::query_dsl::methods::DistinctOnDsl; use crate::query_dsl::order_dsl::ValidOrderingForDistinct; use crate::result::QueryResult; -use crate::{Expression, QuerySource}; +use crate::QuerySource; use diesel::query_builder::order_clause::OrderClause; /// Represents `DISTINCT ON (...)` @@ -17,7 +17,56 @@ pub struct DistinctOnClause(pub(crate) T); impl ValidOrderingForDistinct> for NoOrderClause {} impl ValidOrderingForDistinct> for OrderClause<(T,)> {} -impl ValidOrderingForDistinct> for OrderClause where T: Expression {} +impl ValidOrderingForDistinct> for OrderClause where T: crate::Column {} + +macro_rules! valid_ordering { + (@skip: ($ST1: ident, $($ST:ident,)*), $T1:ident, ) => {}; + (@skip: ($ST1: ident, $($ST:ident,)*), $T1:ident, $($T:ident,)+) => { + valid_ordering!(($($ST,)*), ($ST1,), $($T,)*); + }; + (($ST1: ident,), ($($OT:ident,)*), $T1:ident,) => { + impl<$T1, $ST1, $($OT,)*> ValidOrderingForDistinct> for OrderClause<($T1,)> + where $T1: crate::pg::OrderDecorator, + {} + impl<$T1, $ST1, $($OT,)*> ValidOrderingForDistinct> for OrderClause<($ST1, $($OT,)*)> + where $ST1: crate::pg::OrderDecorator, + {} + + impl<$T1, $ST1, $($OT,)*> ValidOrderingForDistinct> for OrderClause<($ST1, $($OT,)*)> + where $ST1: crate::pg::OrderDecorator, + $T1: crate::Column, + {} + }; + (($ST1: ident, $($ST:ident,)*), ($($OT: ident,)*), $T1:ident, $($T:ident,)+) => { + impl<$T1, $($T,)* $ST1, $($ST,)* $($OT,)*> ValidOrderingForDistinct> for OrderClause<($T1, $($T,)*)> + where $T1: crate::pg::OrderDecorator, + $($T: crate::pg::OrderDecorator,)* + {} + impl<$T1, $($T,)* $ST1, $($ST,)* $($OT,)*> ValidOrderingForDistinct> for OrderClause<($ST1, $($ST,)* $($OT,)*)> + where $ST1: crate::pg::OrderDecorator, + $($ST: crate::pg::OrderDecorator,)* + {} + valid_ordering!(($($ST,)*), ($($OT,)* $ST1,), $($T,)*); + }; + ($( + $Tuple:tt { + $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+ + } + )+) => { + $( + impl<$($T,)* $($ST,)*> ValidOrderingForDistinct> for OrderClause<($($ST,)*)> + where $($ST: crate::pg::OrderDecorator,)* + {} + valid_ordering!(@skip: ($($ST,)*), $($T,)*); + )* + } +} + +// we only generate these impl up to a tuple size of 5 as we generate n*n + 4 impls here +// If we would generate these impls up to max_table_column_count tuple elements that +// would be a really large number for 128 tuple elements (~64k trait impls) +// It's fine to increase this number at some point in the future gradually +diesel_derives::__diesel_for_each_tuple!(valid_ordering, 5); /// A decorator trait for [`OrderClause`] /// It helps to have bounds on either Col, Asc and Desc. diff --git a/diesel/src/type_impls/tuples.rs b/diesel/src/type_impls/tuples.rs index 017a0b8e3763..e47cc6273949 100644 --- a/diesel/src/type_impls/tuples.rs +++ b/diesel/src/type_impls/tuples.rs @@ -16,7 +16,6 @@ use crate::result::QueryResult; use crate::row::*; use crate::sql_types::{HasSqlType, IntoNullable, Nullable, OneIsNullable, SqlType}; use crate::util::{TupleAppend, TupleSize}; -use paste::paste; impl TupleSize for T where @@ -363,18 +362,6 @@ macro_rules! tuple_impls { impl<$($ST,)*> SqlTypeOrSelectable for Nullable<($($ST,)*)> where ($($ST,)*): SqlTypeOrSelectable {} - - #[cfg(feature = "postgres")] - impl<__D, $($T,)*> crate::query_dsl::order_dsl::ValidOrderingForDistinct> - for crate::query_builder::order_clause::OrderClause<(__D, $($T,)*)> {} - - #[cfg(feature = "postgres")] - impl<__D, $($T,)*> crate::query_dsl::order_dsl::ValidOrderingForDistinct> - for crate::query_builder::order_clause::OrderClause<(crate::helper_types::Desc<__D>, $($T,)*)> {} - - #[cfg(feature = "postgres")] - impl<__D, $($T,)*> crate::query_dsl::order_dsl::ValidOrderingForDistinct> - for crate::query_builder::order_clause::OrderClause<(crate::helper_types::Asc<__D>, $($T,)*)> {} )+ } } @@ -542,210 +529,3 @@ macro_rules! impl_sql_type { } diesel_derives::__diesel_for_each_tuple!(tuple_impls); - -macro_rules! valid_distinct_order { - ( - distinct_t = [$($distinct_t: ident),*], - order_t = [$($order_t: ident),*], - bounds_on = [$($bounds_on: ident),*], - )=> { - valid_distinct_order!{ - @build - distinct_t = [$($distinct_t),*], - order_t = [$($order_t),*], - bounds = [], - bounds_on = [$($bounds_on),*], - } - }; - ( - @build - distinct_t = [$($distinct_t: tt)*], - order_t = [$($order_t: tt)*], - bounds = [$($bounds: tt)*], - bounds_on = [$T1: ident, $($T: ident),*], - )=> { - paste! { - valid_distinct_order!{ - @build - distinct_t = [$($distinct_t)*], - order_t = [$($order_t)*], - bounds = [$($bounds)* [<_O $T1>]: crate::pg::OrderDecorator, $T1: Column,], - bounds_on = [$($T),*], - } - } - }; - ( - @build - distinct_t = [$($distinct_t: tt)*], - order_t = [$($order_t: tt)*], - bounds = [$($bounds: tt)*], - bounds_on = [$T1: ident], - )=> { - paste! { - #[allow(unused_parens)] - #[cfg(feature = "postgres")] - impl<$($order_t)* , $($distinct_t)*> crate::query_dsl::order_dsl::ValidOrderingForDistinct> - for crate::query_builder::order_clause::OrderClause<($($order_t)*,)> - where $($bounds)* [<_O $T1>]: crate::pg::OrderDecorator, $T1: Column, - {} - } - }; -} - -valid_distinct_order! { - distinct_t = [T1], - order_t = [_OT1], - bounds_on = [T1], -} - -valid_distinct_order! { - distinct_t = [T1], - order_t = [_OT1, _OT2], - bounds_on = [T1], -} - -valid_distinct_order! { - distinct_t = [T1], - order_t = [_OT1, _OT2, _OT3], - bounds_on = [T1], -} - -valid_distinct_order! { - distinct_t = [T1], - order_t = [_OT1, _OT2, _OT3, _OT4], - bounds_on = [T1], -} - -valid_distinct_order! { - distinct_t = [T1], - order_t = [_OT1, _OT2, _OT3, _OT4, _OT5], - bounds_on = [T1], -} - -// - -valid_distinct_order! { - distinct_t = [T1, T2], - order_t = [_OT1], - bounds_on = [T1], -} - -valid_distinct_order! { - distinct_t = [T1, T2], - order_t = [_OT1, _OT2], - bounds_on = [T1, T2], -} - -valid_distinct_order! { - distinct_t = [T1, T2], - order_t = [_OT1, _OT2, _OT3], - bounds_on = [T1, T2], -} - -valid_distinct_order! { - distinct_t = [T1, T2], - order_t = [_OT1, _OT2, _OT3, _OT4], - bounds_on = [T1, T2], -} - -valid_distinct_order! { - distinct_t = [T1, T2], - order_t = [_OT1, _OT2, _OT3, _OT4, _OT5], - bounds_on = [T1, T2], -} - -// - -valid_distinct_order! { - distinct_t = [T1, T2, T3], - order_t = [_OT1], - bounds_on = [T1], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3], - order_t = [_OT1, _OT2], - bounds_on = [T1, T2], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3], - order_t = [_OT1, _OT2, _OT3], - bounds_on = [T1, T2, T3], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3], - order_t = [_OT1, _OT2, _OT3, _OT4], - bounds_on = [T1, T2, T3], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3], - order_t = [_OT1, _OT2, _OT3, _OT4, _OT5], - bounds_on = [T1, T2, T3], -} - -// - -valid_distinct_order! { - distinct_t = [T1, T2, T3, T4], - order_t = [_OT1], - bounds_on = [T1], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3, T4], - order_t = [_OT1, _OT2], - bounds_on = [T1, T2], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3, T4], - order_t = [_OT1, _OT2, _OT3], - bounds_on = [T1, T2, T3], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3, T4], - order_t = [_OT1, _OT2, _OT3, _OT4], - bounds_on = [T1, T2, T3, T4], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3, T4], - order_t = [_OT1, _OT2, _OT3, _OT4, _OT5], - bounds_on = [T1, T2, T3, T4], -} - -// - -valid_distinct_order! { - distinct_t = [T1, T2, T3, T4, T5], - order_t = [_OT1], - bounds_on = [T1], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3, T4, T5], - order_t = [_OT1, _OT2], - bounds_on = [T1, T2], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3, T4, T5], - order_t = [_OT1, _OT2, _OT3], - bounds_on = [T1, T2, T3], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3, T4, T5], - order_t = [_OT1, _OT2, _OT3, _OT4], - bounds_on = [T1, T2, T3, T4], -} - -valid_distinct_order! { - distinct_t = [T1, T2, T3, T4, T5], - order_t = [_OT1, _OT2, _OT3, _OT4, _OT5], - bounds_on = [T1, T2, T3, T4, T5], -} diff --git a/diesel_derives/src/diesel_for_each_tuple.rs b/diesel_derives/src/diesel_for_each_tuple.rs index 948ddfb8f22a..0d3723a011fe 100644 --- a/diesel_derives/src/diesel_for_each_tuple.rs +++ b/diesel_derives/src/diesel_for_each_tuple.rs @@ -10,10 +10,10 @@ pub const MAX_TUPLE_SIZE: i32 = 64; #[cfg(feature = "128-column-tables")] pub const MAX_TUPLE_SIZE: i32 = 128; -pub(crate) fn expand(input: Ident) -> TokenStream { +pub(crate) fn expand(input: ForEachTupleInput) -> TokenStream { let call_side = Span::mixed_site(); - let pairs = (0..MAX_TUPLE_SIZE as usize) + let pairs = (0..input.max_size as usize) .map(|i| { let t = Ident::new(&format!("T{i}"), call_side); let st = Ident::new(&format!("ST{i}"), call_side); @@ -23,9 +23,9 @@ pub(crate) fn expand(input: Ident) -> TokenStream { }) .collect::>(); - let mut out = Vec::with_capacity(MAX_TUPLE_SIZE as usize); + let mut out = Vec::with_capacity(input.max_size as usize); - for i in 0..MAX_TUPLE_SIZE { + for i in 0..input.max_size { let items = &pairs[0..=i as usize]; let tuple = i + 1; out.push(quote! { @@ -34,6 +34,7 @@ pub(crate) fn expand(input: Ident) -> TokenStream { } }); } + let input = input.inner; quote! { #input! { @@ -41,3 +42,23 @@ pub(crate) fn expand(input: Ident) -> TokenStream { } } } + +pub struct ForEachTupleInput { + inner: Ident, + max_size: i32, +} + +impl syn::parse::Parse for ForEachTupleInput { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let inner = input.parse()?; + let max_size = if input.peek(syn::Token![,]) { + let _ = input.parse::(); + input.parse::()?.base10_parse()? + } else if input.is_empty() { + MAX_TUPLE_SIZE + } else { + unreachable!("Invalid syntax") + }; + Ok(Self { inner, max_size }) + } +}