1use darling::{FromDeriveInput, FromField, FromTypeParam, ast, util::Flag};
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::{DeriveInput, parse_macro_input};
5
6#[derive(FromTypeParam, Debug)]
7#[darling(attributes(table))]
8struct GenericOpts {
9 ident: syn::Ident,
10 bounds: Vec<syn::TypeParamBound>,
11
12 proxy: Flag,
16}
17
18#[derive(FromField, Debug)]
19#[darling(attributes(table))]
20struct FieldOpts {
21 ident: Option<syn::Ident>,
22
23 sub_table: Flag,
27}
28
29#[derive(FromDeriveInput, Debug)]
30#[darling(attributes(table), supports(struct_named))]
31struct TableStructOpts {
32 ident: syn::Ident,
33 data: ast::Data<darling::util::Ignored, FieldOpts>,
34 generics: darling::ast::Generics<darling::ast::GenericParam<GenericOpts>>,
35
36 #[darling(rename = "crate", default)]
37 crate_name: Option<syn::Path>,
38}
39
40#[proc_macro_derive(TableStruct, attributes(table))]
41pub fn derive_table_struct(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
42 let a = match TableStructOpts::from_derive_input(&parse_macro_input!(input as DeriveInput)) {
43 Ok(a) => a,
44 Err(e) => {
45 return proc_macro::TokenStream::from(e.write_errors());
46 }
47 };
48
49 let r = match do_all(&a) {
50 Ok(r) => r,
51 Err(e) => {
52 return proc_macro::TokenStream::from(e.write_errors());
53 }
54 };
55
56 r.into()
57}
58
59fn do_all(a: &TableStructOpts) -> darling::Result<TokenStream> {
60 #[cfg(feature = "sqlx")]
61 let sqlx_table_loader = do_sqlx_table_loader(a)?;
62 #[cfg(not(feature = "sqlx"))]
63 let sqlx_table_loader = quote!();
64
65 let rest = do_rest(a)?;
66
67 Ok(quote! {
68 #sqlx_table_loader
69 #rest
70 })
71}
72
73#[cfg(feature = "sqlx")]
74fn do_sqlx_table_loader(t: &TableStructOpts) -> darling::Result<TokenStream> {
75 use proc_macro2::Span;
76
77 let crate_ = t.crate_name.clone().unwrap_or_else(|| {
78 let mut path = syn::Path::from(syn::Ident::new("rust_rel8", Span::call_site()));
79 path.leading_colon = Some(syn::Token));
80 path
81 });
82 let ident = &t.ident;
83 let proxied_type_params = t
84 .generics
85 .type_params()
86 .filter(|p| p.proxy.is_present())
87 .map(|p| p.ident.clone())
88 .collect::<Vec<_>>();
89 let proxied_type_param_bounds = t
90 .generics
91 .type_params()
92 .filter(|p| p.proxy.is_present())
93 .flat_map(|p| {
94 p.bounds.iter().map(|b| {
95 let ident = &p.ident;
96 quote! { #ident: #b}
97 })
98 })
99 .collect::<Vec<_>>();
100 let tokens = quote! {
101 impl<#(#proxied_type_params,)*> #crate_::TableLoaderSqlx for #ident<'static, #crate_::table_modes::ExprMode, #(#proxied_type_params,)*>
102 where
103 #(#proxied_type_param_bounds,)*
104 {
105 fn load<'a>(
106 &self,
107 values: &mut impl Iterator<Item = ::sqlx::any::AnyValueRef<'a>>,
108 ) -> Self::Result {
109 #crate_::TableUsingMapper::wrap_ref(self).load(values)
110 }
111
112 fn skip<'a>(&self, values: &mut impl Iterator<Item = ::sqlx::any::AnyValueRef<'a>>) {
113 #crate_::TableUsingMapper::wrap_ref(self).skip(values)
114 }
115 }
116 };
117
118 Ok(tokens)
119}
120
121fn do_rest(t: &TableStructOpts) -> darling::Result<TokenStream> {
122 use proc_macro2::Span;
123
124 let crate_ = t.crate_name.clone().unwrap_or_else(|| {
125 let mut path = syn::Path::from(syn::Ident::new("rust_rel8", Span::call_site()));
126 path.leading_colon = Some(syn::Token));
127 path
128 });
129 let ident = &t.ident;
130 let proxied_type_params = t
131 .generics
132 .type_params()
133 .filter(|p| p.proxy.is_present())
134 .map(|p| p.ident.clone())
135 .collect::<Vec<_>>();
136 let proxied_type_param_bounds = t
137 .generics
138 .type_params()
139 .filter(|p| p.proxy.is_present())
140 .flat_map(|p| {
141 p.bounds.iter().map(|b| {
142 let ident = &p.ident;
143 quote! { #ident: #b}
144 })
145 })
146 .collect::<Vec<_>>();
147
148 let fields = t.data.as_ref().take_struct().unwrap();
149
150 let fields = fields
151 .iter()
152 .map(|f| {
153 let ident = f.ident.as_ref().unwrap();
154 let is_sub_table = f.sub_table.is_present();
155
156 (ident, is_sub_table)
157 })
158 .collect::<Vec<_>>();
159
160 let map_modes_final_fields = fields.iter().map(|(ident, _)| quote! { #ident });
161 let map_modes_final = quote! {
162 #ident {
163 #(#map_modes_final_fields,)*
164 }
165 };
166
167 let map_modes_fields = fields.iter().map(|(ident, is_sub_table)| {
168 if *is_sub_table {
169 quote! { let #ident = self.#ident.map_modes(mapper); }
170 } else {
171 quote! { let #ident = mapper.map_mode(self.#ident); }
172 }
173 });
174
175 let map_modes_ref_fields = fields.iter().map(|(ident, is_sub_table)| {
176 if *is_sub_table {
177 quote! { let #ident = self.#ident.map_modes_ref(mapper); }
178 } else {
179 quote! { let #ident = mapper.map_mode_ref(&self.#ident); }
180 }
181 });
182
183 let map_modes_mut_fields = fields.iter().map(|(ident, is_sub_table)| {
184 if *is_sub_table {
185 quote! { let #ident = self.#ident.map_modes_mut(mapper); }
186 } else {
187 quote! { let #ident = mapper.map_mode_mut(&mut self.#ident); }
188 }
189 });
190
191 let shorten_lifetime_fields_shorten = fields
192 .iter()
193 .map(|(ident, _is_sub_table)| {
194 quote! { #ident: self.#ident.shorten_lifetime() }
195 })
196 .collect::<Vec<_>>();
197
198 let shorten_lifetime_fields_noop = fields
199 .iter()
200 .map(|(ident, _is_sub_table)| {
201 quote! { #ident: self.#ident }
202 })
203 .collect::<Vec<_>>();
204
205 let tokens = quote! {
206 impl<T: #crate_::TableMode, #(#proxied_type_params,)*> #crate_::ForLifetimeTable for #ident<'static, T, #(#proxied_type_params,)*>
207 where
208 for<'a> #ident<'a, T, #(#proxied_type_params,)*>: #crate_::Table<'a>,
209 #(#proxied_type_param_bounds,)*
210 {
211 type Of<'lt> = #ident<'lt, T, #(#proxied_type_params,)*>
212 where
213 T: 'lt,
214 #(#proxied_type_params: 'lt,)*
215 ;
216 }
217
218 impl<#(#proxied_type_params,)*> #crate_::ShortenLifetime for #ident<'static, #crate_::NameMode, #(#proxied_type_params,)*>
219 where
220 #(#proxied_type_param_bounds,)*
221 {
222 type Shortened<'small> = #ident<'small, #crate_::NameMode, #(#proxied_type_params,)*>
223 where
224 Self: 'small
225 ;
226
227 fn shorten_lifetime<'small, 'large: 'small>(self) -> Self::Shortened<'small>
228 where
229 Self: 'large,
230 {
231 #ident {
232 #(#shorten_lifetime_fields_noop,)*
233 }
234 }
235 }
236
237 impl<#(#proxied_type_params,)*> #crate_::ShortenLifetime for #ident<'static, #crate_::ValueMode, #(#proxied_type_params,)*>
238 where
239 #(#proxied_type_param_bounds,)*
240 {
241 type Shortened<'small> = #ident<'small, #crate_::ValueMode, #(#proxied_type_params,)*>
242 where
243 Self: 'small
244 ;
245
246 fn shorten_lifetime<'small, 'large: 'small>(self) -> Self::Shortened<'small>
247 where
248 Self: 'large,
249 {
250 #ident {
251 #(#shorten_lifetime_fields_noop,)*
252 }
253 }
254 }
255
256 impl<#(#proxied_type_params,)*> #crate_::ShortenLifetime for #ident<'static, #crate_::ValueNullifiedMode, #(#proxied_type_params,)*>
257 where
258 #(#proxied_type_param_bounds,)*
259 {
260 type Shortened<'small> = #ident<'small, #crate_::ValueNullifiedMode, #(#proxied_type_params,)*>
261 where
262 Self: 'small
263 ;
264
265 fn shorten_lifetime<'small, 'large: 'small>(self) -> Self::Shortened<'small>
266 where
267 Self: 'large,
268 {
269 #ident {
270 #(#shorten_lifetime_fields_noop,)*
271 }
272 }
273 }
274
275 impl<#(#proxied_type_params,)*> #crate_::ShortenLifetime for #ident<'static, #crate_::EmptyMode, #(#proxied_type_params,)*>
276 where
277 #(#proxied_type_param_bounds,)*
278 {
279 type Shortened<'small> = #ident<'small, #crate_::EmptyMode, #(#proxied_type_params,)*>
280 where
281 Self: 'small
282 ;
283
284 fn shorten_lifetime<'small, 'large: 'small>(self) -> Self::Shortened<'small>
285 where
286 Self: 'large,
287 {
288 #ident {
289 #(#shorten_lifetime_fields_noop,)*
290 }
291 }
292 }
293
294 impl<#(#proxied_type_params,)*> #crate_::ShortenLifetime for #ident<'static, #crate_::ExprMode, #(#proxied_type_params,)*>
295 where
296 #(#proxied_type_param_bounds,)*
297 {
298 type Shortened<'small> = #ident<'small, #crate_::ExprMode, #(#proxied_type_params,)*>
299 where
300 Self: 'small
301 ;
302
303 fn shorten_lifetime<'small, 'large: 'small>(self) -> Self::Shortened<'small>
304 where
305 Self: 'large,
306 {
307 #ident {
308 #(#shorten_lifetime_fields_shorten,)*
309 }
310 }
311 }
312
313 impl<#(#proxied_type_params,)*> #crate_::ShortenLifetime for #ident<'static, #crate_::ExprNullifiedMode, #(#proxied_type_params,)*>
314 where
315 #(#proxied_type_param_bounds,)*
316 {
317 type Shortened<'small> = #ident<'small, #crate_::ExprNullifiedMode, #(#proxied_type_params,)*>
318 where
319 Self: 'small
320 ;
321
322 fn shorten_lifetime<'small, 'large: 'small>(self) -> Self::Shortened<'small>
323 where
324 Self: 'large,
325 {
326 #ident {
327 #(#shorten_lifetime_fields_shorten,)*
328 }
329 }
330 }
331
332 impl<'scope, T: #crate_::TableMode, #(#proxied_type_params,)*> #crate_::TableHKT for #ident<'scope, T, #(#proxied_type_params,)*>
333 where
334 #(#proxied_type_param_bounds,)*
335 {
336 type Of<Mode: #crate_::TableMode> = #ident<'scope, Mode, #(#proxied_type_params,)*>;
337
338 type Mode = T;
339 }
340
341 impl<'scope, Mode: #crate_::TableMode, #(#proxied_type_params,)*> #crate_::MapTable<'scope> for #ident<'scope, Mode, #(#proxied_type_params,)*>
342 where
343 #(#proxied_type_param_bounds,)*
344 {
345 fn map_modes<Mapper, DestMode>(self, mapper: &mut Mapper) -> Self::Of<DestMode>
346 where
347 Mapper: #crate_::ModeMapper<'scope, Self::Mode, DestMode>,
348 DestMode: #crate_::TableMode,
349 {
350 #(#map_modes_fields)*
351
352 #map_modes_final
353 }
354
355 fn map_modes_ref<Mapper, DestMode>(&self, mapper: &mut Mapper) -> Self::Of<DestMode>
356 where
357 Mapper: #crate_::ModeMapperRef<'scope, Self::Mode, DestMode>,
358 DestMode: #crate_::TableMode,
359 {
360 #(#map_modes_ref_fields)*
361
362 #map_modes_final
363 }
364
365 fn map_modes_mut<Mapper, DestMode>(&mut self, mapper: &mut Mapper) -> Self::Of<DestMode>
366 where
367 Mapper: #crate_::ModeMapperMut<'scope, Self::Mode, DestMode>,
368 DestMode: #crate_::TableMode,
369 {
370 #(#map_modes_mut_fields)*
371
372 #map_modes_final
373 }
374 }
375
376 impl<'scope, #(#proxied_type_params,)*> #crate_::Table<'scope> for #ident<'scope, #crate_::table_modes::ExprMode, #(#proxied_type_params,)*>
377 where
378 <Self as #crate_::TableHKT>::Of<#crate_::table_modes::ExprNullifiedMode>: #crate_::Table<'scope>,
379 #(#proxied_type_param_bounds,)*
380 {
381 type Nullify = <Self as #crate_::TableHKT>::Of<#crate_::table_modes::ExprNullifiedMode>;
382
383 type Result = <Self as #crate_::TableHKT>::Of<#crate_::table_modes::ValueMode>;
384
385 fn visit(&self, f: &mut impl FnMut(&#crate_::ErasedExpr)) {
386 #crate_::TableUsingMapper::wrap_ref(self).visit(f)
387 }
388
389 fn visit_mut(&mut self, f: &mut impl FnMut(&mut #crate_::ErasedExpr)) {
390 #crate_::TableUsingMapper::wrap_mut(self).visit_mut(f)
391 }
392
393 fn nullify(self) -> Self::Nullify {
394 #crate_::TableUsingMapper::wrap(self).nullify()
395 }
396 }
397
398 impl<'scope, #(#proxied_type_params,)*> #crate_::Table<'scope> for #ident<'scope, #crate_::table_modes::ExprNullifiedMode, #(#proxied_type_params,)*>
399 where
400 #(#proxied_type_param_bounds,)*
401 {
402 type Nullify = Self;
403
404 type Result = <Self as #crate_::TableHKT>::Of<#crate_::table_modes::ValueNullifiedMode>;
405
406 fn visit(&self, f: &mut impl FnMut(&#crate_::ErasedExpr)) {
407 #crate_::TableUsingMapperNullified::wrap_ref(self).visit(f)
408 }
409
410 fn visit_mut(&mut self, f: &mut impl FnMut(&mut #crate_::ErasedExpr)) {
411 #crate_::TableUsingMapperNullified::wrap_mut(self).visit_mut(f)
412 }
413
414 fn nullify(self) -> Self::Nullify {
415 #crate_::TableUsingMapperNullified::wrap(self).nullify()
416 }
417 }
418 };
419
420 Ok(tokens)
421}