1use proc_macro2::{Span, TokenStream};
2use syn::spanned::Spanned;
3use syn::{Expr, Field as SynField, Ident, Index, Result, Type};
4
5use crate::attrs::{AttributeSpanWrapper, FieldAttr, SqlIdentifier, parse_attributes};
6
7pub struct Field {
8 pub ty: Type,
9 pub span: Span,
10 pub name: FieldName,
11 column_name: Option<AttributeSpanWrapper<SqlIdentifier>>,
12 pub sql_type: Option<AttributeSpanWrapper<Type>>,
13 pub treat_none_as_default_value: Option<AttributeSpanWrapper<bool>>,
14 pub treat_none_as_null: Option<AttributeSpanWrapper<bool>>,
15 pub serialize_as: Option<AttributeSpanWrapper<Type>>,
16 pub deserialize_as: Option<AttributeSpanWrapper<Type>>,
17 pub select_expression: Option<AttributeSpanWrapper<Expr>>,
18 pub select_expression_type: Option<AttributeSpanWrapper<Type>>,
19 pub embed: Option<AttributeSpanWrapper<bool>>,
20 pub skip_insertion: Option<AttributeSpanWrapper<bool>>,
21 pub skip_update: Option<AttributeSpanWrapper<bool>>,
22}
23
24impl Field {
25 pub fn from_struct_field(field: &SynField, index: usize) -> Result<Self> {
26 let SynField {
27 ident, attrs, ty, ..
28 } = field;
29
30 let mut column_name = None;
31 let mut sql_type = None;
32 let mut serialize_as = None;
33 let mut deserialize_as = None;
34 let mut embed = None;
35 let mut skip_insertion = None;
36 let mut skip_update = None;
37 let mut select_expression = None;
38 let mut select_expression_type = None;
39 let mut treat_none_as_default_value = None;
40 let mut treat_none_as_null = None;
41
42 for attr in parse_attributes(attrs)? {
43 let attribute_span = attr.attribute_span;
44 let ident_span = attr.ident_span;
45 match attr.item {
46 FieldAttr::ColumnName(_, value) => {
47 column_name = Some(AttributeSpanWrapper {
48 item: value,
49 attribute_span,
50 ident_span,
51 })
52 }
53 FieldAttr::SqlType(_, value) => {
54 sql_type = Some(AttributeSpanWrapper {
55 item: Type::Path(value),
56 attribute_span,
57 ident_span,
58 })
59 }
60 FieldAttr::TreatNoneAsDefaultValue(_, value) => {
61 treat_none_as_default_value = Some(AttributeSpanWrapper {
62 item: value.value,
63 attribute_span,
64 ident_span,
65 })
66 }
67 FieldAttr::TreatNoneAsNull(_, value) => {
68 treat_none_as_null = Some(AttributeSpanWrapper {
69 item: value.value,
70 attribute_span,
71 ident_span,
72 })
73 }
74 FieldAttr::SerializeAs(_, value) => {
75 check_serde_as_supported_type(&value, "serialize_as")?;
76 serialize_as = Some(AttributeSpanWrapper {
77 item: value,
78 attribute_span,
79 ident_span,
80 })
81 }
82 FieldAttr::DeserializeAs(_, value) => {
83 check_serde_as_supported_type(&value, "deserialize_as")?;
84 deserialize_as = Some(AttributeSpanWrapper {
85 item: value,
86 attribute_span,
87 ident_span,
88 })
89 }
90 FieldAttr::SelectExpression(_, value) => {
91 select_expression = Some(AttributeSpanWrapper {
92 item: value,
93 attribute_span,
94 ident_span,
95 })
96 }
97 FieldAttr::SelectExpressionType(_, value) => {
98 select_expression_type = Some(AttributeSpanWrapper {
99 item: value,
100 attribute_span,
101 ident_span,
102 })
103 }
104 FieldAttr::Embed(_) => {
105 embed = Some(AttributeSpanWrapper {
106 item: true,
107 attribute_span,
108 ident_span,
109 })
110 }
111 FieldAttr::SkipInsertion(_) => {
112 skip_insertion = Some(AttributeSpanWrapper {
113 item: true,
114 attribute_span,
115 ident_span,
116 })
117 }
118 FieldAttr::SkipUpdate(_) => {
119 skip_update = Some(AttributeSpanWrapper {
120 item: true,
121 attribute_span,
122 ident_span,
123 })
124 }
125 FieldAttr::Rename(_, _) => { }
126 }
127 }
128
129 let name = match ident.clone() {
130 Some(x) => FieldName::Named(x),
131 None => FieldName::Unnamed(index.into()),
132 };
133 let span = match name {
134 FieldName::Named(ref ident) => ident.span(),
135 FieldName::Unnamed(_) => ty.span(),
136 };
137 let span = Span::mixed_site().located_at(span);
138
139 Ok(Self {
140 ty: ty.clone(),
141 span,
142 name,
143 column_name,
144 sql_type,
145 treat_none_as_default_value,
146 treat_none_as_null,
147 serialize_as,
148 deserialize_as,
149 select_expression,
150 select_expression_type,
151 embed,
152 skip_insertion,
153 skip_update,
154 })
155 }
156
157 pub fn column_name(&self) -> Result<SqlIdentifier> {
158 let identifier = self.column_name.as_ref().map(|a| a.item.clone());
159 if let Some(identifier) = identifier {
160 Ok(identifier)
161 } else {
162 match self.name {
163 FieldName::Named(ref x) => Ok(x.into()),
164 FieldName::Unnamed(ref x) => Err(syn::Error::new(
165 x.span(),
166 "all fields of tuple structs must be annotated with `#[diesel(column_name)]`",
167 )),
168 }
169 }
170 }
171
172 pub fn ty_for_deserialize(&self) -> &Type {
173 if let Some(AttributeSpanWrapper { item: value, .. }) = &self.deserialize_as {
174 value
175 } else {
176 &self.ty
177 }
178 }
179
180 pub(crate) fn embed(&self) -> bool {
181 self.embed.as_ref().map(|a| a.item).unwrap_or(false)
182 }
183
184 pub(crate) fn skip_insertion(&self) -> bool {
185 self.skip_insertion
186 .as_ref()
187 .map(|a| a.item)
188 .unwrap_or(false)
189 }
190
191 pub(crate) fn skip_update(&self) -> bool {
192 self.skip_update.as_ref().map(|a| a.item).unwrap_or(false)
193 }
194}
195
196pub enum FieldName {
197 Named(Ident),
198 Unnamed(Index),
199}
200
201impl quote::ToTokens for FieldName {
202 fn to_tokens(&self, tokens: &mut TokenStream) {
203 match *self {
204 FieldName::Named(ref x) => x.to_tokens(tokens),
205 FieldName::Unnamed(ref x) => x.to_tokens(tokens),
206 }
207 }
208}
209
210fn check_serde_as_supported_type(ty: &Type, attr_name: &str) -> Result<()> {
211 match ty {
212 Type::Path(_) => Ok(()),
213 Type::Array(syn::TypeArray { elem, .. }) => check_serde_as_supported_type(elem, attr_name),
214 Type::Paren(syn::TypeParen { elem, .. }) | Type::Group(syn::TypeGroup { elem, .. }) => {
215 check_serde_as_supported_type(elem, attr_name)
216 }
217 Type::Tuple(syn::TypeTuple { elems, .. }) => elems
218 .iter()
219 .try_for_each(|ty| check_serde_as_supported_type(ty, attr_name)),
220 Type::Ptr(_) => Err(syn::Error::new_spanned(
221 ty,
222 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` does not support pointer types",
attr_name))
})format!("`{attr_name}` does not support pointer types"),
223 )),
224 Type::BareFn(_) => Err(syn::Error::new_spanned(
225 ty,
226 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` does not support function pointer types",
attr_name))
})format!("`{attr_name}` does not support function pointer types"),
227 )),
228 Type::Infer(_) => Err(syn::Error::new_spanned(
229 ty,
230 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` does not support inference types",
attr_name))
})format!("`{attr_name}` does not support inference types"),
231 )),
232
233 Type::Reference(_) => Err(syn::Error::new_spanned(
234 ty,
235 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` does not support reference types",
attr_name))
})format!("`{attr_name}` does not support reference types"),
236 )),
237 Type::Slice(_) => Err(syn::Error::new_spanned(
238 ty,
239 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` does not support unsized slice types, use an array instead",
attr_name))
})format!("`{attr_name}` does not support unsized slice types, use an array instead"),
240 )),
241 Type::TraitObject(_) => Err(syn::Error::new_spanned(
242 ty,
243 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` does not support trait objects",
attr_name))
})format!("`{attr_name}` does not support trait objects"),
244 )),
245 Type::Macro(_) => Err(syn::Error::new_spanned(
246 ty,
247 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("macro invocation is not supported in `{0}`",
attr_name))
})format!("macro invocation is not supported in `{attr_name}`"),
248 )),
249 Type::ImplTrait(_) => Err(syn::Error::new_spanned(
250 ty,
251 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` does not support impl trait types",
attr_name))
})format!("`{attr_name}` does not support impl trait types"),
252 )),
253 _ => Err(syn::Error::new_spanned(
254 ty,
255 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` does not support this type",
attr_name))
})format!("`{attr_name}` does not support this type"),
256 )),
257 }
258}