1use crate::attributes::Attributes;
2use proc_macro2::{Span, TokenStream};
3use quote::quote;
4use serde_derive_internals::{
5 Ctxt,
6 attr::{Container, Default as SerdeDefault, Field},
7};
8use syn::{Data, DataStruct, DeriveInput, Error, Fields, Lifetime, Result, parse_macro_input};
9
10mod attributes;
11
12#[cfg(test)]
13mod tests;
14
15#[proc_macro_derive(Row, attributes(clickhouse))]
18pub fn row(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
19 let input = parse_macro_input!(input as DeriveInput);
20 row_impl(input)
21 .unwrap_or_else(Error::into_compile_error)
22 .into()
23}
24
25fn column_names(data: &DataStruct, cx: &Ctxt, container: &Container) -> Result<TokenStream> {
26 Ok(match &data.fields {
27 Fields::Named(fields) => {
28 let rename_rule = container.rename_all_rules().deserialize;
29 let column_names_iter = fields
30 .named
31 .iter()
32 .enumerate()
33 .map(|(index, field)| Field::from_ast(cx, index, field, None, &SerdeDefault::None))
34 .filter(|field| !field.skip_serializing() && !field.skip_deserializing())
35 .map(|field| {
36 rename_rule
37 .apply_to_field(field.name().serialize_name())
38 .to_string()
39 });
40
41 quote! {
42 &[#( #column_names_iter,)*]
43 }
44 }
45 Fields::Unnamed(_) => {
46 quote! { &[] }
47 }
48 Fields::Unit => unreachable!("checked by the caller"),
49 })
50}
51
52fn row_impl(input: DeriveInput) -> Result<TokenStream> {
53 let cx = Ctxt::new();
54
55 let Attributes { crate_path } = input.attrs[..].try_into()?;
56
57 let container = Container::from_ast(&cx, &input);
58 let name = input.ident;
59
60 let result = match &input.data {
61 Data::Struct(data) if data.fields.is_empty() => {
62 let reason = "`Row` cannot be derived for unit or empty structs";
63 Err(Error::new(name.span(), reason))
64 }
65 Data::Struct(data) => column_names(data, &cx, &container),
66 Data::Enum(_) | Data::Union(_) => {
67 let reason = "`Row` can only be derived for structs";
68 Err(Error::new(name.span(), reason))
69 }
70 };
71
72 cx.check()?;
73 let column_names = result?;
74
75 let value = match input.generics.lifetimes().count() {
76 0 => quote! { Self },
78 1 => {
80 let mut cloned = input.generics.clone();
82 let param = cloned.lifetimes_mut().next().unwrap();
83 param.lifetime = Lifetime::new("'__v", Span::call_site());
84 let ty_generics = cloned.split_for_impl().1;
85 quote! { #name #ty_generics }
86 }
87 _ => {
89 let lt = input.generics.lifetimes().nth(1).unwrap();
90 let reason = "`Row` cannot be derived for structs with multiple lifetimes";
91 return Err(Error::new(lt.lifetime.span(), reason));
92 }
93 };
94
95 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
96
97 Ok(quote! {
98 #[automatically_derived]
99 impl #impl_generics #crate_path::Row for #name #ty_generics #where_clause {
100 const NAME: &'static str = stringify!(#name);
101 const COLUMN_NAMES: &'static [&'static str] = #column_names;
102 const COLUMN_COUNT: usize = <Self as #crate_path::Row>::COLUMN_NAMES.len();
103 const KIND: #crate_path::_priv::RowKind = #crate_path::_priv::RowKind::Struct;
104
105 type Value<'__v> = #value;
106 }
107 })
108}