]>
Commit | Line | Data |
---|---|---|
3b2f2976 XL |
1 | // Copyright 2017 Serde Developers |
2 | // | |
3 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
4 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
5 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
6 | // option. This file may not be copied, modified, or distributed | |
7 | // except according to those terms. | |
8 | ||
83c7162d XL |
9 | use proc_macro2::{Group, Span, TokenStream, TokenTree}; |
10 | use std::collections::BTreeSet; | |
11 | use std::str::FromStr; | |
3b2f2976 | 12 | use syn; |
83c7162d XL |
13 | use syn::punctuated::Punctuated; |
14 | use syn::synom::{ParseError, Synom}; | |
0531ce1d XL |
15 | use syn::Ident; |
16 | use syn::Meta::{List, NameValue, Word}; | |
17 | use syn::NestedMeta::{Literal, Meta}; | |
83c7162d | 18 | use Ctxt; |
3b2f2976 XL |
19 | |
20 | // This module handles parsing of `#[serde(...)]` attributes. The entrypoints | |
21 | // are `attr::Container::from_ast`, `attr::Variant::from_ast`, and | |
22 | // `attr::Field::from_ast`. Each returns an instance of the corresponding | |
23 | // struct. Note that none of them return a Result. Unrecognized, malformed, or | |
24 | // duplicated attributes result in a span_err but otherwise are ignored. The | |
25 | // user will see errors simultaneously for all bad attributes in the crate | |
26 | // rather than just the first. | |
27 | ||
28 | pub use case::RenameRule; | |
29 | ||
0531ce1d | 30 | #[derive(Copy, Clone)] |
3b2f2976 XL |
31 | struct Attr<'c, T> { |
32 | cx: &'c Ctxt, | |
33 | name: &'static str, | |
34 | value: Option<T>, | |
35 | } | |
36 | ||
37 | impl<'c, T> Attr<'c, T> { | |
38 | fn none(cx: &'c Ctxt, name: &'static str) -> Self { | |
39 | Attr { | |
40 | cx: cx, | |
41 | name: name, | |
42 | value: None, | |
43 | } | |
44 | } | |
45 | ||
46 | fn set(&mut self, value: T) { | |
47 | if self.value.is_some() { | |
48 | self.cx | |
49 | .error(format!("duplicate serde attribute `{}`", self.name)); | |
50 | } else { | |
51 | self.value = Some(value); | |
52 | } | |
53 | } | |
54 | ||
55 | fn set_opt(&mut self, value: Option<T>) { | |
56 | if let Some(value) = value { | |
57 | self.set(value); | |
58 | } | |
59 | } | |
60 | ||
61 | fn set_if_none(&mut self, value: T) { | |
62 | if self.value.is_none() { | |
63 | self.value = Some(value); | |
64 | } | |
65 | } | |
66 | ||
67 | fn get(self) -> Option<T> { | |
68 | self.value | |
69 | } | |
70 | } | |
71 | ||
72 | struct BoolAttr<'c>(Attr<'c, ()>); | |
73 | ||
74 | impl<'c> BoolAttr<'c> { | |
75 | fn none(cx: &'c Ctxt, name: &'static str) -> Self { | |
76 | BoolAttr(Attr::none(cx, name)) | |
77 | } | |
78 | ||
79 | fn set_true(&mut self) { | |
80 | self.0.set(()); | |
81 | } | |
82 | ||
83 | fn get(&self) -> bool { | |
84 | self.0.value.is_some() | |
85 | } | |
86 | } | |
87 | ||
3b2f2976 XL |
88 | pub struct Name { |
89 | serialize: String, | |
90 | deserialize: String, | |
91 | } | |
92 | ||
93 | impl Name { | |
94 | /// Return the container name for the container when serializing. | |
95 | pub fn serialize_name(&self) -> String { | |
96 | self.serialize.clone() | |
97 | } | |
98 | ||
99 | /// Return the container name for the container when deserializing. | |
100 | pub fn deserialize_name(&self) -> String { | |
101 | self.deserialize.clone() | |
102 | } | |
103 | } | |
104 | ||
105 | /// Represents container (e.g. struct) attribute information | |
3b2f2976 XL |
106 | pub struct Container { |
107 | name: Name, | |
108 | deny_unknown_fields: bool, | |
109 | default: Default, | |
110 | rename_all: RenameRule, | |
111 | ser_bound: Option<Vec<syn::WherePredicate>>, | |
112 | de_bound: Option<Vec<syn::WherePredicate>>, | |
113 | tag: EnumTag, | |
0531ce1d XL |
114 | type_from: Option<syn::Type>, |
115 | type_into: Option<syn::Type>, | |
3b2f2976 XL |
116 | remote: Option<syn::Path>, |
117 | identifier: Identifier, | |
0531ce1d | 118 | has_flatten: bool, |
3b2f2976 XL |
119 | } |
120 | ||
121 | /// Styles of representing an enum. | |
3b2f2976 XL |
122 | pub enum EnumTag { |
123 | /// The default. | |
124 | /// | |
125 | /// ```json | |
126 | /// {"variant1": {"key1": "value1", "key2": "value2"}} | |
127 | /// ``` | |
128 | External, | |
129 | ||
130 | /// `#[serde(tag = "type")]` | |
131 | /// | |
132 | /// ```json | |
133 | /// {"type": "variant1", "key1": "value1", "key2": "value2"} | |
134 | /// ``` | |
135 | Internal { tag: String }, | |
136 | ||
137 | /// `#[serde(tag = "t", content = "c")]` | |
138 | /// | |
139 | /// ```json | |
140 | /// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}} | |
141 | /// ``` | |
142 | Adjacent { tag: String, content: String }, | |
143 | ||
144 | /// `#[serde(untagged)]` | |
145 | /// | |
146 | /// ```json | |
147 | /// {"key1": "value1", "key2": "value2"} | |
148 | /// ``` | |
149 | None, | |
150 | } | |
151 | ||
152 | /// Whether this enum represents the fields of a struct or the variants of an | |
153 | /// enum. | |
0531ce1d | 154 | #[derive(Copy, Clone)] |
3b2f2976 XL |
155 | pub enum Identifier { |
156 | /// It does not. | |
157 | No, | |
158 | ||
159 | /// This enum represents the fields of a struct. All of the variants must be | |
160 | /// unit variants, except possibly one which is annotated with | |
161 | /// `#[serde(other)]` and is a newtype variant. | |
162 | Field, | |
163 | ||
164 | /// This enum represents the variants of an enum. All of the variants must | |
165 | /// be unit variants. | |
166 | Variant, | |
167 | } | |
168 | ||
ff7c6d11 XL |
169 | impl Identifier { |
170 | pub fn is_some(self) -> bool { | |
171 | match self { | |
172 | Identifier::No => false, | |
173 | Identifier::Field | Identifier::Variant => true, | |
174 | } | |
175 | } | |
176 | } | |
177 | ||
3b2f2976 XL |
178 | impl Container { |
179 | /// Extract out the `#[serde(...)]` attributes from an item. | |
180 | pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self { | |
181 | let mut ser_name = Attr::none(cx, "rename"); | |
182 | let mut de_name = Attr::none(cx, "rename"); | |
183 | let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields"); | |
184 | let mut default = Attr::none(cx, "default"); | |
185 | let mut rename_all = Attr::none(cx, "rename_all"); | |
186 | let mut ser_bound = Attr::none(cx, "bound"); | |
187 | let mut de_bound = Attr::none(cx, "bound"); | |
188 | let mut untagged = BoolAttr::none(cx, "untagged"); | |
189 | let mut internal_tag = Attr::none(cx, "tag"); | |
190 | let mut content = Attr::none(cx, "content"); | |
0531ce1d XL |
191 | let mut type_from = Attr::none(cx, "from"); |
192 | let mut type_into = Attr::none(cx, "into"); | |
3b2f2976 XL |
193 | let mut remote = Attr::none(cx, "remote"); |
194 | let mut field_identifier = BoolAttr::none(cx, "field_identifier"); | |
195 | let mut variant_identifier = BoolAttr::none(cx, "variant_identifier"); | |
196 | ||
197 | for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) { | |
198 | for meta_item in meta_items { | |
199 | match meta_item { | |
200 | // Parse `#[serde(rename = "foo")]` | |
0531ce1d XL |
201 | Meta(NameValue(ref m)) if m.ident == "rename" => { |
202 | if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { | |
203 | ser_name.set(s.value()); | |
204 | de_name.set(s.value()); | |
3b2f2976 XL |
205 | } |
206 | } | |
207 | ||
208 | // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` | |
0531ce1d XL |
209 | Meta(List(ref m)) if m.ident == "rename" => { |
210 | if let Ok((ser, de)) = get_renames(cx, &m.nested) { | |
211 | ser_name.set_opt(ser.map(syn::LitStr::value)); | |
212 | de_name.set_opt(de.map(syn::LitStr::value)); | |
3b2f2976 XL |
213 | } |
214 | } | |
215 | ||
216 | // Parse `#[serde(rename_all = "foo")]` | |
0531ce1d XL |
217 | Meta(NameValue(ref m)) if m.ident == "rename_all" => { |
218 | if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { | |
219 | match RenameRule::from_str(&s.value()) { | |
3b2f2976 | 220 | Ok(rename_rule) => rename_all.set(rename_rule), |
ff7c6d11 XL |
221 | Err(()) => cx.error(format!( |
222 | "unknown rename rule for #[serde(rename_all \ | |
223 | = {:?})]", | |
0531ce1d | 224 | s.value() |
ff7c6d11 | 225 | )), |
3b2f2976 XL |
226 | } |
227 | } | |
228 | } | |
229 | ||
230 | // Parse `#[serde(deny_unknown_fields)]` | |
0531ce1d | 231 | Meta(Word(word)) if word == "deny_unknown_fields" => { |
3b2f2976 XL |
232 | deny_unknown_fields.set_true(); |
233 | } | |
234 | ||
235 | // Parse `#[serde(default)]` | |
0531ce1d | 236 | Meta(Word(word)) if word == "default" => match item.data { |
83c7162d XL |
237 | syn::Data::Struct(syn::DataStruct { |
238 | fields: syn::Fields::Named(_), | |
239 | .. | |
240 | }) => { | |
ff7c6d11 | 241 | default.set(Default::Default); |
3b2f2976 | 242 | } |
ff7c6d11 XL |
243 | _ => cx.error( |
244 | "#[serde(default)] can only be used on structs \ | |
245 | with named fields", | |
246 | ), | |
247 | }, | |
3b2f2976 XL |
248 | |
249 | // Parse `#[serde(default = "...")]` | |
0531ce1d XL |
250 | Meta(NameValue(ref m)) if m.ident == "default" => { |
251 | if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { | |
252 | match item.data { | |
83c7162d XL |
253 | syn::Data::Struct(syn::DataStruct { |
254 | fields: syn::Fields::Named(_), | |
255 | .. | |
256 | }) => { | |
3b2f2976 XL |
257 | default.set(Default::Path(path)); |
258 | } | |
ff7c6d11 XL |
259 | _ => cx.error( |
260 | "#[serde(default = \"...\")] can only be used \ | |
261 | on structs with named fields", | |
262 | ), | |
3b2f2976 XL |
263 | } |
264 | } | |
265 | } | |
266 | ||
267 | // Parse `#[serde(bound = "D: Serialize")]` | |
0531ce1d | 268 | Meta(NameValue(ref m)) if m.ident == "bound" => { |
3b2f2976 | 269 | if let Ok(where_predicates) = |
0531ce1d | 270 | parse_lit_into_where(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) |
ff7c6d11 | 271 | { |
3b2f2976 XL |
272 | ser_bound.set(where_predicates.clone()); |
273 | de_bound.set(where_predicates); | |
274 | } | |
275 | } | |
276 | ||
277 | // Parse `#[serde(bound(serialize = "D: Serialize", deserialize = "D: Deserialize"))]` | |
0531ce1d XL |
278 | Meta(List(ref m)) if m.ident == "bound" => { |
279 | if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { | |
3b2f2976 XL |
280 | ser_bound.set_opt(ser); |
281 | de_bound.set_opt(de); | |
282 | } | |
283 | } | |
284 | ||
285 | // Parse `#[serde(untagged)]` | |
0531ce1d XL |
286 | Meta(Word(word)) if word == "untagged" => match item.data { |
287 | syn::Data::Enum(_) => { | |
ff7c6d11 | 288 | untagged.set_true(); |
3b2f2976 | 289 | } |
0531ce1d | 290 | syn::Data::Struct(_) | syn::Data::Union(_) => { |
ff7c6d11 XL |
291 | cx.error("#[serde(untagged)] can only be used on enums") |
292 | } | |
293 | }, | |
3b2f2976 XL |
294 | |
295 | // Parse `#[serde(tag = "type")]` | |
0531ce1d XL |
296 | Meta(NameValue(ref m)) if m.ident == "tag" => { |
297 | if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { | |
298 | match item.data { | |
299 | syn::Data::Enum(_) => { | |
300 | internal_tag.set(s.value()); | |
3b2f2976 | 301 | } |
0531ce1d | 302 | syn::Data::Struct(_) | syn::Data::Union(_) => { |
3b2f2976 XL |
303 | cx.error("#[serde(tag = \"...\")] can only be used on enums") |
304 | } | |
305 | } | |
306 | } | |
307 | } | |
308 | ||
309 | // Parse `#[serde(content = "c")]` | |
0531ce1d XL |
310 | Meta(NameValue(ref m)) if m.ident == "content" => { |
311 | if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { | |
312 | match item.data { | |
313 | syn::Data::Enum(_) => { | |
314 | content.set(s.value()); | |
3b2f2976 | 315 | } |
0531ce1d | 316 | syn::Data::Struct(_) | syn::Data::Union(_) => cx.error( |
ff7c6d11 XL |
317 | "#[serde(content = \"...\")] can only be used on \ |
318 | enums", | |
319 | ), | |
3b2f2976 XL |
320 | } |
321 | } | |
322 | } | |
323 | ||
324 | // Parse `#[serde(from = "Type")] | |
0531ce1d XL |
325 | Meta(NameValue(ref m)) if m.ident == "from" => { |
326 | if let Ok(from_ty) = parse_lit_into_ty(cx, m.ident.as_ref(), &m.lit) { | |
327 | type_from.set_opt(Some(from_ty)); | |
3b2f2976 XL |
328 | } |
329 | } | |
330 | ||
331 | // Parse `#[serde(into = "Type")] | |
0531ce1d XL |
332 | Meta(NameValue(ref m)) if m.ident == "into" => { |
333 | if let Ok(into_ty) = parse_lit_into_ty(cx, m.ident.as_ref(), &m.lit) { | |
334 | type_into.set_opt(Some(into_ty)); | |
3b2f2976 XL |
335 | } |
336 | } | |
337 | ||
338 | // Parse `#[serde(remote = "...")]` | |
0531ce1d XL |
339 | Meta(NameValue(ref m)) if m.ident == "remote" => { |
340 | if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { | |
83c7162d XL |
341 | if is_primitive_path(&path, "Self") { |
342 | remote.set(item.ident.into()); | |
343 | } else { | |
344 | remote.set(path); | |
345 | } | |
3b2f2976 XL |
346 | } |
347 | } | |
348 | ||
349 | // Parse `#[serde(field_identifier)]` | |
0531ce1d | 350 | Meta(Word(word)) if word == "field_identifier" => { |
3b2f2976 XL |
351 | field_identifier.set_true(); |
352 | } | |
353 | ||
354 | // Parse `#[serde(variant_identifier)]` | |
0531ce1d | 355 | Meta(Word(word)) if word == "variant_identifier" => { |
3b2f2976 XL |
356 | variant_identifier.set_true(); |
357 | } | |
358 | ||
0531ce1d | 359 | Meta(ref meta_item) => { |
ff7c6d11 XL |
360 | cx.error(format!( |
361 | "unknown serde container attribute `{}`", | |
362 | meta_item.name() | |
363 | )); | |
3b2f2976 XL |
364 | } |
365 | ||
366 | Literal(_) => { | |
367 | cx.error("unexpected literal in serde container attribute"); | |
368 | } | |
369 | } | |
370 | } | |
371 | } | |
372 | ||
373 | Container { | |
374 | name: Name { | |
375 | serialize: ser_name.get().unwrap_or_else(|| item.ident.to_string()), | |
376 | deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()), | |
377 | }, | |
378 | deny_unknown_fields: deny_unknown_fields.get(), | |
379 | default: default.get().unwrap_or(Default::None), | |
380 | rename_all: rename_all.get().unwrap_or(RenameRule::None), | |
381 | ser_bound: ser_bound.get(), | |
382 | de_bound: de_bound.get(), | |
0531ce1d XL |
383 | tag: decide_tag(cx, item, &untagged, internal_tag, content), |
384 | type_from: type_from.get(), | |
385 | type_into: type_into.get(), | |
3b2f2976 | 386 | remote: remote.get(), |
0531ce1d XL |
387 | identifier: decide_identifier(cx, item, &field_identifier, &variant_identifier), |
388 | has_flatten: false, | |
3b2f2976 XL |
389 | } |
390 | } | |
391 | ||
392 | pub fn name(&self) -> &Name { | |
393 | &self.name | |
394 | } | |
395 | ||
396 | pub fn rename_all(&self) -> &RenameRule { | |
397 | &self.rename_all | |
398 | } | |
399 | ||
400 | pub fn deny_unknown_fields(&self) -> bool { | |
401 | self.deny_unknown_fields | |
402 | } | |
403 | ||
404 | pub fn default(&self) -> &Default { | |
405 | &self.default | |
406 | } | |
407 | ||
408 | pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { | |
409 | self.ser_bound.as_ref().map(|vec| &vec[..]) | |
410 | } | |
411 | ||
412 | pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { | |
413 | self.de_bound.as_ref().map(|vec| &vec[..]) | |
414 | } | |
415 | ||
416 | pub fn tag(&self) -> &EnumTag { | |
417 | &self.tag | |
418 | } | |
419 | ||
0531ce1d XL |
420 | pub fn type_from(&self) -> Option<&syn::Type> { |
421 | self.type_from.as_ref() | |
3b2f2976 XL |
422 | } |
423 | ||
0531ce1d XL |
424 | pub fn type_into(&self) -> Option<&syn::Type> { |
425 | self.type_into.as_ref() | |
3b2f2976 XL |
426 | } |
427 | ||
428 | pub fn remote(&self) -> Option<&syn::Path> { | |
429 | self.remote.as_ref() | |
430 | } | |
431 | ||
432 | pub fn identifier(&self) -> Identifier { | |
433 | self.identifier | |
434 | } | |
0531ce1d XL |
435 | |
436 | pub fn has_flatten(&self) -> bool { | |
437 | self.has_flatten | |
438 | } | |
439 | ||
440 | pub fn mark_has_flatten(&mut self) { | |
441 | self.has_flatten = true; | |
442 | } | |
3b2f2976 XL |
443 | } |
444 | ||
445 | fn decide_tag( | |
446 | cx: &Ctxt, | |
447 | item: &syn::DeriveInput, | |
0531ce1d | 448 | untagged: &BoolAttr, |
3b2f2976 XL |
449 | internal_tag: Attr<String>, |
450 | content: Attr<String>, | |
451 | ) -> EnumTag { | |
452 | match (untagged.get(), internal_tag.get(), content.get()) { | |
453 | (false, None, None) => EnumTag::External, | |
454 | (true, None, None) => EnumTag::None, | |
455 | (false, Some(tag), None) => { | |
456 | // Check that there are no tuple variants. | |
0531ce1d XL |
457 | if let syn::Data::Enum(ref data) = item.data { |
458 | for variant in &data.variants { | |
459 | match variant.fields { | |
460 | syn::Fields::Named(_) | syn::Fields::Unit => {} | |
461 | syn::Fields::Unnamed(ref fields) => { | |
462 | if fields.unnamed.len() != 1 { | |
3b2f2976 XL |
463 | cx.error( |
464 | "#[serde(tag = \"...\")] cannot be used with tuple \ | |
ff7c6d11 | 465 | variants", |
3b2f2976 XL |
466 | ); |
467 | break; | |
468 | } | |
469 | } | |
470 | } | |
471 | } | |
472 | } | |
473 | EnumTag::Internal { tag: tag } | |
474 | } | |
475 | (true, Some(_), None) => { | |
476 | cx.error("enum cannot be both untagged and internally tagged"); | |
477 | EnumTag::External // doesn't matter, will error | |
478 | } | |
479 | (false, None, Some(_)) => { | |
ff7c6d11 | 480 | cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together"); |
3b2f2976 XL |
481 | EnumTag::External |
482 | } | |
483 | (true, None, Some(_)) => { | |
484 | cx.error("untagged enum cannot have #[serde(content = \"...\")]"); | |
485 | EnumTag::External | |
486 | } | |
ff7c6d11 XL |
487 | (false, Some(tag), Some(content)) => EnumTag::Adjacent { |
488 | tag: tag, | |
489 | content: content, | |
490 | }, | |
3b2f2976 | 491 | (true, Some(_), Some(_)) => { |
ff7c6d11 | 492 | cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]"); |
3b2f2976 XL |
493 | EnumTag::External |
494 | } | |
495 | } | |
496 | } | |
497 | ||
498 | fn decide_identifier( | |
499 | cx: &Ctxt, | |
500 | item: &syn::DeriveInput, | |
0531ce1d XL |
501 | field_identifier: &BoolAttr, |
502 | variant_identifier: &BoolAttr, | |
3b2f2976 | 503 | ) -> Identifier { |
0531ce1d | 504 | match (&item.data, field_identifier.get(), variant_identifier.get()) { |
3b2f2976 XL |
505 | (_, false, false) => Identifier::No, |
506 | (_, true, true) => { | |
ff7c6d11 | 507 | cx.error("`field_identifier` and `variant_identifier` cannot both be set"); |
3b2f2976 XL |
508 | Identifier::No |
509 | } | |
0531ce1d XL |
510 | (&syn::Data::Enum(_), true, false) => Identifier::Field, |
511 | (&syn::Data::Enum(_), false, true) => Identifier::Variant, | |
83c7162d | 512 | (&syn::Data::Struct(_), true, false) | (&syn::Data::Union(_), true, false) => { |
3b2f2976 XL |
513 | cx.error("`field_identifier` can only be used on an enum"); |
514 | Identifier::No | |
515 | } | |
83c7162d | 516 | (&syn::Data::Struct(_), false, true) | (&syn::Data::Union(_), false, true) => { |
3b2f2976 XL |
517 | cx.error("`variant_identifier` can only be used on an enum"); |
518 | Identifier::No | |
519 | } | |
3b2f2976 XL |
520 | } |
521 | } | |
522 | ||
523 | /// Represents variant attribute information | |
3b2f2976 XL |
524 | pub struct Variant { |
525 | name: Name, | |
526 | ser_renamed: bool, | |
527 | de_renamed: bool, | |
528 | rename_all: RenameRule, | |
529 | skip_deserializing: bool, | |
530 | skip_serializing: bool, | |
531 | other: bool, | |
0531ce1d XL |
532 | serialize_with: Option<syn::ExprPath>, |
533 | deserialize_with: Option<syn::ExprPath>, | |
534 | borrow: Option<syn::Meta>, | |
3b2f2976 XL |
535 | } |
536 | ||
537 | impl Variant { | |
538 | pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self { | |
539 | let mut ser_name = Attr::none(cx, "rename"); | |
540 | let mut de_name = Attr::none(cx, "rename"); | |
541 | let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing"); | |
542 | let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); | |
543 | let mut rename_all = Attr::none(cx, "rename_all"); | |
544 | let mut other = BoolAttr::none(cx, "other"); | |
ea8adc8c XL |
545 | let mut serialize_with = Attr::none(cx, "serialize_with"); |
546 | let mut deserialize_with = Attr::none(cx, "deserialize_with"); | |
abe05a73 | 547 | let mut borrow = Attr::none(cx, "borrow"); |
3b2f2976 XL |
548 | |
549 | for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) { | |
550 | for meta_item in meta_items { | |
551 | match meta_item { | |
552 | // Parse `#[serde(rename = "foo")]` | |
0531ce1d XL |
553 | Meta(NameValue(ref m)) if m.ident == "rename" => { |
554 | if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { | |
555 | ser_name.set(s.value()); | |
556 | de_name.set(s.value()); | |
3b2f2976 XL |
557 | } |
558 | } | |
559 | ||
560 | // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` | |
0531ce1d XL |
561 | Meta(List(ref m)) if m.ident == "rename" => { |
562 | if let Ok((ser, de)) = get_renames(cx, &m.nested) { | |
563 | ser_name.set_opt(ser.map(syn::LitStr::value)); | |
564 | de_name.set_opt(de.map(syn::LitStr::value)); | |
3b2f2976 XL |
565 | } |
566 | } | |
567 | ||
568 | // Parse `#[serde(rename_all = "foo")]` | |
0531ce1d XL |
569 | Meta(NameValue(ref m)) if m.ident == "rename_all" => { |
570 | if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { | |
571 | match RenameRule::from_str(&s.value()) { | |
3b2f2976 | 572 | Ok(rename_rule) => rename_all.set(rename_rule), |
ff7c6d11 XL |
573 | Err(()) => cx.error(format!( |
574 | "unknown rename rule for #[serde(rename_all \ | |
575 | = {:?})]", | |
0531ce1d | 576 | s.value() |
ff7c6d11 | 577 | )), |
3b2f2976 XL |
578 | } |
579 | } | |
580 | } | |
581 | ||
582 | // Parse `#[serde(skip_deserializing)]` | |
0531ce1d | 583 | Meta(Word(word)) if word == "skip_deserializing" => { |
3b2f2976 XL |
584 | skip_deserializing.set_true(); |
585 | } | |
586 | ||
587 | // Parse `#[serde(skip_serializing)]` | |
0531ce1d | 588 | Meta(Word(word)) if word == "skip_serializing" => { |
3b2f2976 XL |
589 | skip_serializing.set_true(); |
590 | } | |
591 | ||
592 | // Parse `#[serde(other)]` | |
0531ce1d | 593 | Meta(Word(word)) if word == "other" => { |
3b2f2976 XL |
594 | other.set_true(); |
595 | } | |
596 | ||
ea8adc8c | 597 | // Parse `#[serde(with = "...")]` |
0531ce1d XL |
598 | Meta(NameValue(ref m)) if m.ident == "with" => { |
599 | if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { | |
ea8adc8c | 600 | let mut ser_path = path.clone(); |
83c7162d XL |
601 | ser_path |
602 | .path | |
603 | .segments | |
604 | .push(Ident::new("serialize", Span::call_site()).into()); | |
ea8adc8c XL |
605 | serialize_with.set(ser_path); |
606 | let mut de_path = path; | |
83c7162d XL |
607 | de_path |
608 | .path | |
609 | .segments | |
610 | .push(Ident::new("deserialize", Span::call_site()).into()); | |
ea8adc8c XL |
611 | deserialize_with.set(de_path); |
612 | } | |
613 | } | |
614 | ||
615 | // Parse `#[serde(serialize_with = "...")]` | |
0531ce1d XL |
616 | Meta(NameValue(ref m)) if m.ident == "serialize_with" => { |
617 | if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { | |
ea8adc8c XL |
618 | serialize_with.set(path); |
619 | } | |
620 | } | |
621 | ||
622 | // Parse `#[serde(deserialize_with = "...")]` | |
0531ce1d XL |
623 | Meta(NameValue(ref m)) if m.ident == "deserialize_with" => { |
624 | if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { | |
ea8adc8c XL |
625 | deserialize_with.set(path); |
626 | } | |
627 | } | |
628 | ||
abe05a73 | 629 | // Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]` |
0531ce1d XL |
630 | Meta(ref m) if m.name() == "borrow" => match variant.fields { |
631 | syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => { | |
632 | borrow.set(m.clone()); | |
abe05a73 | 633 | } |
ff7c6d11 XL |
634 | _ => { |
635 | cx.error("#[serde(borrow)] may only be used on newtype variants"); | |
636 | } | |
637 | }, | |
abe05a73 | 638 | |
0531ce1d | 639 | Meta(ref meta_item) => { |
ff7c6d11 XL |
640 | cx.error(format!( |
641 | "unknown serde variant attribute `{}`", | |
642 | meta_item.name() | |
643 | )); | |
3b2f2976 XL |
644 | } |
645 | ||
646 | Literal(_) => { | |
647 | cx.error("unexpected literal in serde variant attribute"); | |
648 | } | |
649 | } | |
650 | } | |
651 | } | |
652 | ||
653 | let ser_name = ser_name.get(); | |
654 | let ser_renamed = ser_name.is_some(); | |
655 | let de_name = de_name.get(); | |
656 | let de_renamed = de_name.is_some(); | |
657 | Variant { | |
658 | name: Name { | |
659 | serialize: ser_name.unwrap_or_else(|| variant.ident.to_string()), | |
660 | deserialize: de_name.unwrap_or_else(|| variant.ident.to_string()), | |
661 | }, | |
662 | ser_renamed: ser_renamed, | |
663 | de_renamed: de_renamed, | |
664 | rename_all: rename_all.get().unwrap_or(RenameRule::None), | |
665 | skip_deserializing: skip_deserializing.get(), | |
666 | skip_serializing: skip_serializing.get(), | |
667 | other: other.get(), | |
ea8adc8c XL |
668 | serialize_with: serialize_with.get(), |
669 | deserialize_with: deserialize_with.get(), | |
abe05a73 | 670 | borrow: borrow.get(), |
3b2f2976 XL |
671 | } |
672 | } | |
673 | ||
674 | pub fn name(&self) -> &Name { | |
675 | &self.name | |
676 | } | |
677 | ||
678 | pub fn rename_by_rule(&mut self, rule: &RenameRule) { | |
679 | if !self.ser_renamed { | |
680 | self.name.serialize = rule.apply_to_variant(&self.name.serialize); | |
681 | } | |
682 | if !self.de_renamed { | |
683 | self.name.deserialize = rule.apply_to_variant(&self.name.deserialize); | |
684 | } | |
685 | } | |
686 | ||
687 | pub fn rename_all(&self) -> &RenameRule { | |
688 | &self.rename_all | |
689 | } | |
690 | ||
691 | pub fn skip_deserializing(&self) -> bool { | |
692 | self.skip_deserializing | |
693 | } | |
694 | ||
695 | pub fn skip_serializing(&self) -> bool { | |
696 | self.skip_serializing | |
697 | } | |
698 | ||
699 | pub fn other(&self) -> bool { | |
700 | self.other | |
701 | } | |
ea8adc8c | 702 | |
0531ce1d | 703 | pub fn serialize_with(&self) -> Option<&syn::ExprPath> { |
ea8adc8c XL |
704 | self.serialize_with.as_ref() |
705 | } | |
706 | ||
0531ce1d | 707 | pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { |
ea8adc8c XL |
708 | self.deserialize_with.as_ref() |
709 | } | |
3b2f2976 XL |
710 | } |
711 | ||
712 | /// Represents field attribute information | |
3b2f2976 XL |
713 | pub struct Field { |
714 | name: Name, | |
715 | ser_renamed: bool, | |
716 | de_renamed: bool, | |
717 | skip_serializing: bool, | |
718 | skip_deserializing: bool, | |
0531ce1d | 719 | skip_serializing_if: Option<syn::ExprPath>, |
3b2f2976 | 720 | default: Default, |
0531ce1d XL |
721 | serialize_with: Option<syn::ExprPath>, |
722 | deserialize_with: Option<syn::ExprPath>, | |
3b2f2976 XL |
723 | ser_bound: Option<Vec<syn::WherePredicate>>, |
724 | de_bound: Option<Vec<syn::WherePredicate>>, | |
725 | borrowed_lifetimes: BTreeSet<syn::Lifetime>, | |
0531ce1d XL |
726 | getter: Option<syn::ExprPath>, |
727 | flatten: bool, | |
3b2f2976 XL |
728 | } |
729 | ||
730 | /// Represents the default to use for a field when deserializing. | |
3b2f2976 XL |
731 | pub enum Default { |
732 | /// Field must always be specified because it does not have a default. | |
733 | None, | |
734 | /// The default is given by `std::default::Default::default()`. | |
735 | Default, | |
736 | /// The default is given by this function. | |
0531ce1d | 737 | Path(syn::ExprPath), |
3b2f2976 XL |
738 | } |
739 | ||
740 | impl Field { | |
741 | /// Extract out the `#[serde(...)]` attributes from a struct field. | |
ff7c6d11 XL |
742 | pub fn from_ast( |
743 | cx: &Ctxt, | |
744 | index: usize, | |
745 | field: &syn::Field, | |
746 | attrs: Option<&Variant>, | |
747 | container_default: &Default, | |
748 | ) -> Self { | |
3b2f2976 XL |
749 | let mut ser_name = Attr::none(cx, "rename"); |
750 | let mut de_name = Attr::none(cx, "rename"); | |
751 | let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); | |
752 | let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing"); | |
753 | let mut skip_serializing_if = Attr::none(cx, "skip_serializing_if"); | |
754 | let mut default = Attr::none(cx, "default"); | |
755 | let mut serialize_with = Attr::none(cx, "serialize_with"); | |
756 | let mut deserialize_with = Attr::none(cx, "deserialize_with"); | |
757 | let mut ser_bound = Attr::none(cx, "bound"); | |
758 | let mut de_bound = Attr::none(cx, "bound"); | |
759 | let mut borrowed_lifetimes = Attr::none(cx, "borrow"); | |
760 | let mut getter = Attr::none(cx, "getter"); | |
0531ce1d | 761 | let mut flatten = BoolAttr::none(cx, "flatten"); |
3b2f2976 XL |
762 | |
763 | let ident = match field.ident { | |
764 | Some(ref ident) => ident.to_string(), | |
765 | None => index.to_string(), | |
766 | }; | |
767 | ||
abe05a73 XL |
768 | let variant_borrow = attrs |
769 | .map(|variant| &variant.borrow) | |
770 | .unwrap_or(&None) | |
771 | .as_ref() | |
0531ce1d | 772 | .map(|borrow| vec![Meta(borrow.clone())]); |
abe05a73 | 773 | |
ff7c6d11 XL |
774 | for meta_items in field |
775 | .attrs | |
776 | .iter() | |
777 | .filter_map(get_serde_meta_items) | |
778 | .chain(variant_borrow) | |
779 | { | |
3b2f2976 XL |
780 | for meta_item in meta_items { |
781 | match meta_item { | |
782 | // Parse `#[serde(rename = "foo")]` | |
0531ce1d XL |
783 | Meta(NameValue(ref m)) if m.ident == "rename" => { |
784 | if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { | |
785 | ser_name.set(s.value()); | |
786 | de_name.set(s.value()); | |
3b2f2976 XL |
787 | } |
788 | } | |
789 | ||
790 | // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` | |
0531ce1d XL |
791 | Meta(List(ref m)) if m.ident == "rename" => { |
792 | if let Ok((ser, de)) = get_renames(cx, &m.nested) { | |
793 | ser_name.set_opt(ser.map(syn::LitStr::value)); | |
794 | de_name.set_opt(de.map(syn::LitStr::value)); | |
3b2f2976 XL |
795 | } |
796 | } | |
797 | ||
798 | // Parse `#[serde(default)]` | |
0531ce1d | 799 | Meta(Word(word)) if word == "default" => { |
3b2f2976 XL |
800 | default.set(Default::Default); |
801 | } | |
802 | ||
803 | // Parse `#[serde(default = "...")]` | |
0531ce1d XL |
804 | Meta(NameValue(ref m)) if m.ident == "default" => { |
805 | if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { | |
3b2f2976 XL |
806 | default.set(Default::Path(path)); |
807 | } | |
808 | } | |
809 | ||
810 | // Parse `#[serde(skip_serializing)]` | |
0531ce1d | 811 | Meta(Word(word)) if word == "skip_serializing" => { |
3b2f2976 XL |
812 | skip_serializing.set_true(); |
813 | } | |
814 | ||
815 | // Parse `#[serde(skip_deserializing)]` | |
0531ce1d | 816 | Meta(Word(word)) if word == "skip_deserializing" => { |
3b2f2976 XL |
817 | skip_deserializing.set_true(); |
818 | } | |
819 | ||
820 | // Parse `#[serde(skip)]` | |
0531ce1d | 821 | Meta(Word(word)) if word == "skip" => { |
3b2f2976 XL |
822 | skip_serializing.set_true(); |
823 | skip_deserializing.set_true(); | |
ff7c6d11 | 824 | } |
3b2f2976 XL |
825 | |
826 | // Parse `#[serde(skip_serializing_if = "...")]` | |
0531ce1d XL |
827 | Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => { |
828 | if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { | |
3b2f2976 XL |
829 | skip_serializing_if.set(path); |
830 | } | |
831 | } | |
832 | ||
833 | // Parse `#[serde(serialize_with = "...")]` | |
0531ce1d XL |
834 | Meta(NameValue(ref m)) if m.ident == "serialize_with" => { |
835 | if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { | |
3b2f2976 XL |
836 | serialize_with.set(path); |
837 | } | |
838 | } | |
839 | ||
840 | // Parse `#[serde(deserialize_with = "...")]` | |
0531ce1d XL |
841 | Meta(NameValue(ref m)) if m.ident == "deserialize_with" => { |
842 | if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { | |
3b2f2976 XL |
843 | deserialize_with.set(path); |
844 | } | |
845 | } | |
846 | ||
847 | // Parse `#[serde(with = "...")]` | |
0531ce1d XL |
848 | Meta(NameValue(ref m)) if m.ident == "with" => { |
849 | if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { | |
3b2f2976 | 850 | let mut ser_path = path.clone(); |
83c7162d XL |
851 | ser_path |
852 | .path | |
853 | .segments | |
854 | .push(Ident::new("serialize", Span::call_site()).into()); | |
3b2f2976 XL |
855 | serialize_with.set(ser_path); |
856 | let mut de_path = path; | |
83c7162d XL |
857 | de_path |
858 | .path | |
859 | .segments | |
860 | .push(Ident::new("deserialize", Span::call_site()).into()); | |
3b2f2976 XL |
861 | deserialize_with.set(de_path); |
862 | } | |
863 | } | |
864 | ||
865 | // Parse `#[serde(bound = "D: Serialize")]` | |
0531ce1d | 866 | Meta(NameValue(ref m)) if m.ident == "bound" => { |
3b2f2976 | 867 | if let Ok(where_predicates) = |
0531ce1d | 868 | parse_lit_into_where(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) |
ff7c6d11 | 869 | { |
3b2f2976 XL |
870 | ser_bound.set(where_predicates.clone()); |
871 | de_bound.set(where_predicates); | |
872 | } | |
873 | } | |
874 | ||
875 | // Parse `#[serde(bound(serialize = "D: Serialize", deserialize = "D: Deserialize"))]` | |
0531ce1d XL |
876 | Meta(List(ref m)) if m.ident == "bound" => { |
877 | if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { | |
3b2f2976 XL |
878 | ser_bound.set_opt(ser); |
879 | de_bound.set_opt(de); | |
880 | } | |
881 | } | |
882 | ||
883 | // Parse `#[serde(borrow)]` | |
0531ce1d | 884 | Meta(Word(word)) if word == "borrow" => { |
3b2f2976 XL |
885 | if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { |
886 | borrowed_lifetimes.set(borrowable); | |
887 | } | |
888 | } | |
889 | ||
890 | // Parse `#[serde(borrow = "'a + 'b")]` | |
0531ce1d | 891 | Meta(NameValue(ref m)) if m.ident == "borrow" => { |
83c7162d XL |
892 | if let Ok(lifetimes) = |
893 | parse_lit_into_lifetimes(cx, m.ident.as_ref(), &m.lit) | |
894 | { | |
3b2f2976 XL |
895 | if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { |
896 | for lifetime in &lifetimes { | |
897 | if !borrowable.contains(lifetime) { | |
ff7c6d11 XL |
898 | cx.error(format!( |
899 | "field `{}` does not have lifetime {}", | |
0531ce1d | 900 | ident, lifetime |
ff7c6d11 | 901 | )); |
3b2f2976 XL |
902 | } |
903 | } | |
904 | borrowed_lifetimes.set(lifetimes); | |
905 | } | |
906 | } | |
907 | } | |
908 | ||
909 | // Parse `#[serde(getter = "...")]` | |
0531ce1d XL |
910 | Meta(NameValue(ref m)) if m.ident == "getter" => { |
911 | if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { | |
3b2f2976 XL |
912 | getter.set(path); |
913 | } | |
914 | } | |
915 | ||
0531ce1d XL |
916 | // Parse `#[serde(flatten)]` |
917 | Meta(Word(word)) if word == "flatten" => { | |
918 | flatten.set_true(); | |
919 | } | |
920 | ||
921 | Meta(ref meta_item) => { | |
ff7c6d11 XL |
922 | cx.error(format!( |
923 | "unknown serde field attribute `{}`", | |
924 | meta_item.name() | |
925 | )); | |
3b2f2976 XL |
926 | } |
927 | ||
928 | Literal(_) => { | |
929 | cx.error("unexpected literal in serde field attribute"); | |
930 | } | |
931 | } | |
932 | } | |
933 | } | |
934 | ||
ff7c6d11 XL |
935 | // Is skip_deserializing, initialize the field to Default::default() unless a different |
936 | // default is specified by `#[serde(default = "...")]` on ourselves or our container (e.g. | |
937 | // the struct we are in). | |
0531ce1d XL |
938 | if let Default::None = *container_default { |
939 | if skip_deserializing.0.value.is_some() { | |
940 | default.set_if_none(Default::Default); | |
941 | } | |
3b2f2976 XL |
942 | } |
943 | ||
944 | let mut borrowed_lifetimes = borrowed_lifetimes.get().unwrap_or_default(); | |
945 | if !borrowed_lifetimes.is_empty() { | |
946 | // Cow<str> and Cow<[u8]> never borrow by default: | |
947 | // | |
948 | // impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> | |
949 | // | |
950 | // A #[serde(borrow)] attribute enables borrowing that corresponds | |
951 | // roughly to these impls: | |
952 | // | |
953 | // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, str> | |
954 | // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> | |
0531ce1d XL |
955 | if is_cow(&field.ty, is_str) { |
956 | let mut path = syn::Path { | |
957 | leading_colon: None, | |
958 | segments: Punctuated::new(), | |
959 | }; | |
83c7162d XL |
960 | path.segments |
961 | .push(Ident::new("_serde", Span::call_site()).into()); | |
962 | path.segments | |
963 | .push(Ident::new("private", Span::call_site()).into()); | |
964 | path.segments | |
965 | .push(Ident::new("de", Span::call_site()).into()); | |
966 | path.segments | |
967 | .push(Ident::new("borrow_cow_str", Span::call_site()).into()); | |
0531ce1d XL |
968 | let expr = syn::ExprPath { |
969 | attrs: Vec::new(), | |
970 | qself: None, | |
971 | path: path, | |
972 | }; | |
973 | deserialize_with.set_if_none(expr); | |
974 | } else if is_cow(&field.ty, is_slice_u8) { | |
975 | let mut path = syn::Path { | |
976 | leading_colon: None, | |
977 | segments: Punctuated::new(), | |
978 | }; | |
83c7162d XL |
979 | path.segments |
980 | .push(Ident::new("_serde", Span::call_site()).into()); | |
981 | path.segments | |
982 | .push(Ident::new("private", Span::call_site()).into()); | |
983 | path.segments | |
984 | .push(Ident::new("de", Span::call_site()).into()); | |
985 | path.segments | |
986 | .push(Ident::new("borrow_cow_bytes", Span::call_site()).into()); | |
0531ce1d XL |
987 | let expr = syn::ExprPath { |
988 | attrs: Vec::new(), | |
989 | qself: None, | |
990 | path: path, | |
991 | }; | |
992 | deserialize_with.set_if_none(expr); | |
3b2f2976 | 993 | } |
0531ce1d | 994 | } else if is_rptr(&field.ty, is_str) || is_rptr(&field.ty, is_slice_u8) { |
3b2f2976 XL |
995 | // Types &str and &[u8] are always implicitly borrowed. No need for |
996 | // a #[serde(borrow)]. | |
0531ce1d | 997 | collect_lifetimes(&field.ty, &mut borrowed_lifetimes); |
3b2f2976 XL |
998 | } |
999 | ||
1000 | let ser_name = ser_name.get(); | |
1001 | let ser_renamed = ser_name.is_some(); | |
1002 | let de_name = de_name.get(); | |
1003 | let de_renamed = de_name.is_some(); | |
1004 | Field { | |
1005 | name: Name { | |
1006 | serialize: ser_name.unwrap_or_else(|| ident.clone()), | |
1007 | deserialize: de_name.unwrap_or(ident), | |
1008 | }, | |
1009 | ser_renamed: ser_renamed, | |
1010 | de_renamed: de_renamed, | |
1011 | skip_serializing: skip_serializing.get(), | |
1012 | skip_deserializing: skip_deserializing.get(), | |
1013 | skip_serializing_if: skip_serializing_if.get(), | |
1014 | default: default.get().unwrap_or(Default::None), | |
1015 | serialize_with: serialize_with.get(), | |
1016 | deserialize_with: deserialize_with.get(), | |
1017 | ser_bound: ser_bound.get(), | |
1018 | de_bound: de_bound.get(), | |
1019 | borrowed_lifetimes: borrowed_lifetimes, | |
1020 | getter: getter.get(), | |
0531ce1d | 1021 | flatten: flatten.get(), |
3b2f2976 XL |
1022 | } |
1023 | } | |
1024 | ||
1025 | pub fn name(&self) -> &Name { | |
1026 | &self.name | |
1027 | } | |
1028 | ||
1029 | pub fn rename_by_rule(&mut self, rule: &RenameRule) { | |
1030 | if !self.ser_renamed { | |
1031 | self.name.serialize = rule.apply_to_field(&self.name.serialize); | |
1032 | } | |
1033 | if !self.de_renamed { | |
1034 | self.name.deserialize = rule.apply_to_field(&self.name.deserialize); | |
1035 | } | |
1036 | } | |
1037 | ||
1038 | pub fn skip_serializing(&self) -> bool { | |
1039 | self.skip_serializing | |
1040 | } | |
1041 | ||
1042 | pub fn skip_deserializing(&self) -> bool { | |
1043 | self.skip_deserializing | |
1044 | } | |
1045 | ||
0531ce1d | 1046 | pub fn skip_serializing_if(&self) -> Option<&syn::ExprPath> { |
3b2f2976 XL |
1047 | self.skip_serializing_if.as_ref() |
1048 | } | |
1049 | ||
1050 | pub fn default(&self) -> &Default { | |
1051 | &self.default | |
1052 | } | |
1053 | ||
0531ce1d | 1054 | pub fn serialize_with(&self) -> Option<&syn::ExprPath> { |
3b2f2976 XL |
1055 | self.serialize_with.as_ref() |
1056 | } | |
1057 | ||
0531ce1d | 1058 | pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { |
3b2f2976 XL |
1059 | self.deserialize_with.as_ref() |
1060 | } | |
1061 | ||
1062 | pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { | |
1063 | self.ser_bound.as_ref().map(|vec| &vec[..]) | |
1064 | } | |
1065 | ||
1066 | pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { | |
1067 | self.de_bound.as_ref().map(|vec| &vec[..]) | |
1068 | } | |
1069 | ||
1070 | pub fn borrowed_lifetimes(&self) -> &BTreeSet<syn::Lifetime> { | |
1071 | &self.borrowed_lifetimes | |
1072 | } | |
1073 | ||
0531ce1d | 1074 | pub fn getter(&self) -> Option<&syn::ExprPath> { |
3b2f2976 XL |
1075 | self.getter.as_ref() |
1076 | } | |
0531ce1d XL |
1077 | |
1078 | pub fn flatten(&self) -> bool { | |
1079 | self.flatten | |
1080 | } | |
3b2f2976 XL |
1081 | } |
1082 | ||
1083 | type SerAndDe<T> = (Option<T>, Option<T>); | |
1084 | ||
0531ce1d | 1085 | fn get_ser_and_de<'a, T, F>( |
3b2f2976 XL |
1086 | cx: &Ctxt, |
1087 | attr_name: &'static str, | |
0531ce1d | 1088 | metas: &'a Punctuated<syn::NestedMeta, Token![,]>, |
3b2f2976 XL |
1089 | f: F, |
1090 | ) -> Result<SerAndDe<T>, ()> | |
1091 | where | |
0531ce1d XL |
1092 | T: 'a, |
1093 | F: Fn(&Ctxt, &str, &str, &'a syn::Lit) -> Result<T, ()>, | |
3b2f2976 | 1094 | { |
0531ce1d XL |
1095 | let mut ser_meta = Attr::none(cx, attr_name); |
1096 | let mut de_meta = Attr::none(cx, attr_name); | |
1097 | ||
1098 | for meta in metas { | |
1099 | match *meta { | |
1100 | Meta(NameValue(ref meta)) if meta.ident == "serialize" => { | |
1101 | if let Ok(v) = f(cx, attr_name, meta.ident.as_ref(), &meta.lit) { | |
1102 | ser_meta.set(v); | |
3b2f2976 XL |
1103 | } |
1104 | } | |
1105 | ||
0531ce1d XL |
1106 | Meta(NameValue(ref meta)) if meta.ident == "deserialize" => { |
1107 | if let Ok(v) = f(cx, attr_name, meta.ident.as_ref(), &meta.lit) { | |
1108 | de_meta.set(v); | |
3b2f2976 XL |
1109 | } |
1110 | } | |
1111 | ||
1112 | _ => { | |
ff7c6d11 XL |
1113 | cx.error(format!( |
1114 | "malformed {0} attribute, expected `{0}(serialize = ..., \ | |
1115 | deserialize = ...)`", | |
1116 | attr_name | |
1117 | )); | |
3b2f2976 XL |
1118 | return Err(()); |
1119 | } | |
1120 | } | |
1121 | } | |
1122 | ||
0531ce1d | 1123 | Ok((ser_meta.get(), de_meta.get())) |
3b2f2976 XL |
1124 | } |
1125 | ||
83c7162d XL |
1126 | fn get_renames<'a>( |
1127 | cx: &Ctxt, | |
1128 | items: &'a Punctuated<syn::NestedMeta, Token![,]>, | |
1129 | ) -> Result<SerAndDe<&'a syn::LitStr>, ()> { | |
0531ce1d | 1130 | get_ser_and_de(cx, "rename", items, get_lit_str) |
3b2f2976 XL |
1131 | } |
1132 | ||
1133 | fn get_where_predicates( | |
1134 | cx: &Ctxt, | |
0531ce1d | 1135 | items: &Punctuated<syn::NestedMeta, Token![,]>, |
3b2f2976 XL |
1136 | ) -> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> { |
1137 | get_ser_and_de(cx, "bound", items, parse_lit_into_where) | |
1138 | } | |
1139 | ||
0531ce1d XL |
1140 | pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMeta>> { |
1141 | if attr.path.segments.len() == 1 && attr.path.segments[0].ident == "serde" { | |
1142 | match attr.interpret_meta() { | |
1143 | Some(List(ref meta)) => Some(meta.nested.iter().cloned().collect()), | |
1144 | _ => { | |
1145 | // TODO: produce an error | |
1146 | None | |
1147 | } | |
1148 | } | |
1149 | } else { | |
1150 | None | |
3b2f2976 XL |
1151 | } |
1152 | } | |
1153 | ||
0531ce1d | 1154 | fn get_lit_str<'a>( |
3b2f2976 XL |
1155 | cx: &Ctxt, |
1156 | attr_name: &str, | |
1157 | meta_item_name: &str, | |
0531ce1d XL |
1158 | lit: &'a syn::Lit, |
1159 | ) -> Result<&'a syn::LitStr, ()> { | |
1160 | if let syn::Lit::Str(ref lit) = *lit { | |
1161 | Ok(lit) | |
3b2f2976 | 1162 | } else { |
ff7c6d11 XL |
1163 | cx.error(format!( |
1164 | "expected serde {} attribute to be a string: `{} = \"...\"`", | |
1165 | attr_name, meta_item_name | |
1166 | )); | |
3b2f2976 XL |
1167 | Err(()) |
1168 | } | |
1169 | } | |
1170 | ||
1171 | fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Path, ()> { | |
0531ce1d | 1172 | let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); |
83c7162d XL |
1173 | parse_lit_str(string) |
1174 | .map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value()))) | |
0531ce1d XL |
1175 | } |
1176 | ||
83c7162d XL |
1177 | fn parse_lit_into_expr_path( |
1178 | cx: &Ctxt, | |
1179 | attr_name: &str, | |
1180 | lit: &syn::Lit, | |
1181 | ) -> Result<syn::ExprPath, ()> { | |
0531ce1d | 1182 | let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); |
83c7162d XL |
1183 | parse_lit_str(string) |
1184 | .map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value()))) | |
3b2f2976 XL |
1185 | } |
1186 | ||
1187 | fn parse_lit_into_where( | |
1188 | cx: &Ctxt, | |
1189 | attr_name: &str, | |
1190 | meta_item_name: &str, | |
1191 | lit: &syn::Lit, | |
1192 | ) -> Result<Vec<syn::WherePredicate>, ()> { | |
0531ce1d XL |
1193 | let string = try!(get_lit_str(cx, attr_name, meta_item_name, lit)); |
1194 | if string.value().is_empty() { | |
3b2f2976 XL |
1195 | return Ok(Vec::new()); |
1196 | } | |
1197 | ||
83c7162d | 1198 | let where_string = syn::LitStr::new(&format!("where {}", string.value()), string.span()); |
3b2f2976 | 1199 | |
0531ce1d XL |
1200 | parse_lit_str::<syn::WhereClause>(&where_string) |
1201 | .map(|wh| wh.predicates.into_iter().collect()) | |
3b2f2976 XL |
1202 | .map_err(|err| cx.error(err)) |
1203 | } | |
1204 | ||
0531ce1d XL |
1205 | fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Type, ()> { |
1206 | let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); | |
3b2f2976 | 1207 | |
0531ce1d | 1208 | parse_lit_str(string).map_err(|_| { |
ff7c6d11 XL |
1209 | cx.error(format!( |
1210 | "failed to parse type: {} = {:?}", | |
83c7162d XL |
1211 | attr_name, |
1212 | string.value() | |
ff7c6d11 XL |
1213 | )) |
1214 | }) | |
3b2f2976 XL |
1215 | } |
1216 | ||
1217 | // Parses a string literal like "'a + 'b + 'c" containing a nonempty list of | |
1218 | // lifetimes separated by `+`. | |
1219 | fn parse_lit_into_lifetimes( | |
1220 | cx: &Ctxt, | |
1221 | attr_name: &str, | |
1222 | lit: &syn::Lit, | |
1223 | ) -> Result<BTreeSet<syn::Lifetime>, ()> { | |
0531ce1d XL |
1224 | let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); |
1225 | if string.value().is_empty() { | |
3b2f2976 XL |
1226 | cx.error("at least one lifetime must be borrowed"); |
1227 | return Err(()); | |
1228 | } | |
1229 | ||
0531ce1d | 1230 | struct BorrowedLifetimes(Punctuated<syn::Lifetime, Token![+]>); |
3b2f2976 | 1231 | |
0531ce1d XL |
1232 | impl Synom for BorrowedLifetimes { |
1233 | named!(parse -> Self, map!( | |
1234 | call!(Punctuated::parse_separated_nonempty), | |
1235 | BorrowedLifetimes | |
1236 | )); | |
1237 | } | |
1238 | ||
1239 | if let Ok(BorrowedLifetimes(lifetimes)) = parse_lit_str(string) { | |
1240 | let mut set = BTreeSet::new(); | |
1241 | for lifetime in lifetimes { | |
1242 | if !set.insert(lifetime) { | |
1243 | cx.error(format!("duplicate borrowed lifetime `{}`", lifetime)); | |
3b2f2976 | 1244 | } |
3b2f2976 | 1245 | } |
0531ce1d | 1246 | return Ok(set); |
3b2f2976 | 1247 | } |
0531ce1d | 1248 | |
83c7162d XL |
1249 | cx.error(format!( |
1250 | "failed to parse borrowed lifetimes: {:?}", | |
1251 | string.value() | |
1252 | )); | |
0531ce1d | 1253 | Err(()) |
3b2f2976 XL |
1254 | } |
1255 | ||
1256 | // Whether the type looks like it might be `std::borrow::Cow<T>` where elem="T". | |
1257 | // This can have false negatives and false positives. | |
1258 | // | |
1259 | // False negative: | |
1260 | // | |
1261 | // use std::borrow::Cow as Pig; | |
1262 | // | |
1263 | // #[derive(Deserialize)] | |
1264 | // struct S<'a> { | |
1265 | // #[serde(borrow)] | |
1266 | // pig: Pig<'a, str>, | |
1267 | // } | |
1268 | // | |
1269 | // False positive: | |
1270 | // | |
1271 | // type str = [i16]; | |
1272 | // | |
1273 | // #[derive(Deserialize)] | |
1274 | // struct S<'a> { | |
1275 | // #[serde(borrow)] | |
1276 | // cow: Cow<'a, str>, | |
1277 | // } | |
0531ce1d | 1278 | fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { |
3b2f2976 | 1279 | let path = match *ty { |
0531ce1d | 1280 | syn::Type::Path(ref ty) => &ty.path, |
3b2f2976 XL |
1281 | _ => { |
1282 | return false; | |
1283 | } | |
1284 | }; | |
1285 | let seg = match path.segments.last() { | |
0531ce1d | 1286 | Some(seg) => seg.into_value(), |
3b2f2976 XL |
1287 | None => { |
1288 | return false; | |
1289 | } | |
1290 | }; | |
0531ce1d XL |
1291 | let args = match seg.arguments { |
1292 | syn::PathArguments::AngleBracketed(ref bracketed) => &bracketed.args, | |
3b2f2976 XL |
1293 | _ => { |
1294 | return false; | |
1295 | } | |
1296 | }; | |
83c7162d XL |
1297 | seg.ident == "Cow" && args.len() == 2 && match (&args[0], &args[1]) { |
1298 | (&syn::GenericArgument::Lifetime(_), &syn::GenericArgument::Type(ref arg)) => elem(arg), | |
1299 | _ => false, | |
1300 | } | |
3b2f2976 XL |
1301 | } |
1302 | ||
1303 | // Whether the type looks like it might be `&T` where elem="T". This can have | |
1304 | // false negatives and false positives. | |
1305 | // | |
1306 | // False negative: | |
1307 | // | |
1308 | // type Yarn = str; | |
1309 | // | |
1310 | // #[derive(Deserialize)] | |
1311 | // struct S<'a> { | |
1312 | // r: &'a Yarn, | |
1313 | // } | |
1314 | // | |
1315 | // False positive: | |
1316 | // | |
1317 | // type str = [i16]; | |
1318 | // | |
1319 | // #[derive(Deserialize)] | |
1320 | // struct S<'a> { | |
1321 | // r: &'a str, | |
1322 | // } | |
0531ce1d | 1323 | fn is_rptr(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { |
3b2f2976 | 1324 | match *ty { |
83c7162d | 1325 | syn::Type::Reference(ref ty) => ty.mutability.is_none() && elem(&ty.elem), |
0531ce1d XL |
1326 | _ => false, |
1327 | } | |
1328 | } | |
1329 | ||
1330 | fn is_str(ty: &syn::Type) -> bool { | |
83c7162d | 1331 | is_primitive_type(ty, "str") |
0531ce1d XL |
1332 | } |
1333 | ||
1334 | fn is_slice_u8(ty: &syn::Type) -> bool { | |
1335 | match *ty { | |
83c7162d | 1336 | syn::Type::Slice(ref ty) => is_primitive_type(&ty.elem, "u8"), |
0531ce1d XL |
1337 | _ => false, |
1338 | } | |
1339 | } | |
1340 | ||
83c7162d | 1341 | fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool { |
0531ce1d | 1342 | match *ty { |
83c7162d | 1343 | syn::Type::Path(ref ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive), |
3b2f2976 XL |
1344 | _ => false, |
1345 | } | |
1346 | } | |
1347 | ||
83c7162d XL |
1348 | fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { |
1349 | path.leading_colon.is_none() && path.segments.len() == 1 && path.segments[0].ident == primitive | |
1350 | && path.segments[0].arguments.is_empty() | |
1351 | } | |
1352 | ||
3b2f2976 XL |
1353 | // All lifetimes that this type could borrow from a Deserializer. |
1354 | // | |
1355 | // For example a type `S<'a, 'b>` could borrow `'a` and `'b`. On the other hand | |
1356 | // a type `for<'a> fn(&'a str)` could not borrow `'a` from the Deserializer. | |
1357 | // | |
1358 | // This is used when there is an explicit or implicit `#[serde(borrow)]` | |
1359 | // attribute on the field so there must be at least one borrowable lifetime. | |
1360 | fn borrowable_lifetimes( | |
1361 | cx: &Ctxt, | |
1362 | name: &str, | |
0531ce1d | 1363 | ty: &syn::Type, |
3b2f2976 XL |
1364 | ) -> Result<BTreeSet<syn::Lifetime>, ()> { |
1365 | let mut lifetimes = BTreeSet::new(); | |
1366 | collect_lifetimes(ty, &mut lifetimes); | |
1367 | if lifetimes.is_empty() { | |
0531ce1d XL |
1368 | cx.error(format!("field `{}` has no lifetimes to borrow", name)); |
1369 | Err(()) | |
3b2f2976 XL |
1370 | } else { |
1371 | Ok(lifetimes) | |
1372 | } | |
1373 | } | |
1374 | ||
0531ce1d | 1375 | fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) { |
3b2f2976 | 1376 | match *ty { |
0531ce1d XL |
1377 | syn::Type::Slice(ref ty) => { |
1378 | collect_lifetimes(&ty.elem, out); | |
3b2f2976 | 1379 | } |
0531ce1d XL |
1380 | syn::Type::Array(ref ty) => { |
1381 | collect_lifetimes(&ty.elem, out); | |
3b2f2976 | 1382 | } |
0531ce1d XL |
1383 | syn::Type::Ptr(ref ty) => { |
1384 | collect_lifetimes(&ty.elem, out); | |
3b2f2976 | 1385 | } |
0531ce1d XL |
1386 | syn::Type::Reference(ref ty) => { |
1387 | out.extend(ty.lifetime.iter().cloned()); | |
1388 | collect_lifetimes(&ty.elem, out); | |
1389 | } | |
1390 | syn::Type::Tuple(ref ty) => for elem in &ty.elems { | |
ff7c6d11 XL |
1391 | collect_lifetimes(elem, out); |
1392 | }, | |
0531ce1d XL |
1393 | syn::Type::Path(ref ty) => { |
1394 | if let Some(ref qself) = ty.qself { | |
3b2f2976 XL |
1395 | collect_lifetimes(&qself.ty, out); |
1396 | } | |
0531ce1d XL |
1397 | for seg in &ty.path.segments { |
1398 | if let syn::PathArguments::AngleBracketed(ref bracketed) = seg.arguments { | |
1399 | for arg in &bracketed.args { | |
1400 | match *arg { | |
1401 | syn::GenericArgument::Lifetime(ref lifetime) => { | |
1402 | out.insert(lifetime.clone()); | |
1403 | } | |
1404 | syn::GenericArgument::Type(ref ty) => { | |
1405 | collect_lifetimes(ty, out); | |
1406 | } | |
1407 | syn::GenericArgument::Binding(ref binding) => { | |
1408 | collect_lifetimes(&binding.ty, out); | |
1409 | } | |
1410 | syn::GenericArgument::Const(_) => {} | |
1411 | } | |
3b2f2976 XL |
1412 | } |
1413 | } | |
1414 | } | |
1415 | } | |
0531ce1d XL |
1416 | syn::Type::Paren(ref ty) => { |
1417 | collect_lifetimes(&ty.elem, out); | |
1418 | } | |
1419 | syn::Type::Group(ref ty) => { | |
1420 | collect_lifetimes(&ty.elem, out); | |
1421 | } | |
1422 | syn::Type::BareFn(_) | |
1423 | | syn::Type::Never(_) | |
1424 | | syn::Type::TraitObject(_) | |
1425 | | syn::Type::ImplTrait(_) | |
1426 | | syn::Type::Infer(_) | |
1427 | | syn::Type::Macro(_) | |
1428 | | syn::Type::Verbatim(_) => {} | |
1429 | } | |
1430 | } | |
1431 | ||
1432 | fn parse_lit_str<T>(s: &syn::LitStr) -> Result<T, ParseError> | |
1433 | where | |
1434 | T: Synom, | |
1435 | { | |
1436 | let tokens = try!(spanned_tokens(s)); | |
1437 | syn::parse2(tokens) | |
1438 | } | |
1439 | ||
1440 | fn spanned_tokens(s: &syn::LitStr) -> Result<TokenStream, ParseError> { | |
1441 | let stream = try!(syn::parse_str(&s.value())); | |
83c7162d | 1442 | Ok(respan_token_stream(stream, s.span())) |
0531ce1d XL |
1443 | } |
1444 | ||
1445 | fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream { | |
83c7162d XL |
1446 | stream |
1447 | .into_iter() | |
1448 | .map(|token| respan_token_tree(token, span)) | |
1449 | .collect() | |
0531ce1d XL |
1450 | } |
1451 | ||
83c7162d XL |
1452 | fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree { |
1453 | if let TokenTree::Group(ref mut g) = token { | |
1454 | *g = Group::new(g.delimiter(), respan_token_stream(g.stream().clone(), span)); | |
3b2f2976 | 1455 | } |
83c7162d XL |
1456 | token.set_span(span); |
1457 | token | |
3b2f2976 | 1458 | } |