1 // Copyright 2017 Serde Developers
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.
9 use std
::collections
::HashSet
;
11 use syn
::{self, visit}
;
13 use internals
::ast
::{Body, Container}
;
18 syn
::parse_path(quote
!($
($path
)+).as_str()).unwrap()
22 // Remove the default from every type parameter because in the generated impls
23 // they look like associated types: "error: associated type bindings are not
25 pub fn without_defaults(generics
: &syn
::Generics
) -> syn
::Generics
{
43 pub fn with_where_predicates(
44 generics
: &syn
::Generics
,
45 predicates
: &[syn
::WherePredicate
],
47 let mut generics
= generics
.clone();
51 .extend_from_slice(predicates
);
55 pub fn with_where_predicates_from_fields
<F
>(
57 generics
: &syn
::Generics
,
61 F
: Fn(&attr
::Field
) -> Option
<&[syn
::WherePredicate
]>,
63 let predicates
= cont
.body
65 .flat_map(|field
| from_field(&field
.attrs
))
66 .flat_map(|predicates
| predicates
.to_vec());
68 let mut generics
= generics
.clone();
69 generics
.where_clause
.predicates
.extend(predicates
);
73 // Puts the given bound on any generic type parameters that are used in fields
74 // for which filter returns true.
76 // For example, the following struct needs the bound `A: Serialize, B: Serialize`.
78 // struct S<'b, A, B: 'b, C> {
81 // #[serde(skip_serializing)]
86 generics
: &syn
::Generics
,
91 F
: Fn(&attr
::Field
, Option
<&attr
::Variant
>) -> bool
,
94 // Set of all generic type parameters on the current struct (A, B, C in
95 // the example). Initialized up front.
96 all_ty_params
: HashSet
<syn
::Ident
>,
97 // Set of generic type parameters used in fields for which filter
98 // returns true (A and B in the example). Filled in as the visitor sees
100 relevant_ty_params
: HashSet
<syn
::Ident
>,
102 impl visit
::Visitor
for FindTyParams
{
103 fn visit_path(&mut self, path
: &syn
::Path
) {
104 if let Some(seg
) = path
.segments
.last() {
105 if seg
.ident
== "PhantomData" {
106 // Hardcoded exception, because PhantomData<T> implements
107 // Serialize and Deserialize whether or not T implements it.
111 if !path
.global
&& path
.segments
.len() == 1 {
112 let id
= path
.segments
[0].ident
.clone();
113 if self.all_ty_params
.contains(&id
) {
114 self.relevant_ty_params
.insert(id
);
117 visit
::walk_path(self, path
);
120 // Type parameter should not be considered used by a macro path.
122 // struct TypeMacro<T> {
124 // marker: PhantomData<T>,
126 fn visit_mac(&mut self, _mac
: &syn
::Mac
) {}
129 let all_ty_params
: HashSet
<_
> = generics
132 .map(|ty_param
| ty_param
.ident
.clone())
135 let mut visitor
= FindTyParams
{
136 all_ty_params
: all_ty_params
,
137 relevant_ty_params
: HashSet
::new(),
140 Body
::Enum(ref variants
) => {
141 for variant
in variants
.iter() {
142 let relevant_fields
= variant
145 .filter(|field
| filter(&field
.attrs
, Some(&variant
.attrs
)));
146 for field
in relevant_fields
{
147 visit
::walk_ty(&mut visitor
, field
.ty
);
151 Body
::Struct(_
, ref fields
) => {
152 for field
in fields
.iter().filter(|field
| filter(&field
.attrs
, None
)) {
153 visit
::walk_ty(&mut visitor
, field
.ty
);
158 let new_predicates
= generics
161 .map(|ty_param
| ty_param
.ident
.clone())
162 .filter(|id
| visitor
.relevant_ty_params
.contains(id
))
165 syn
::WherePredicate
::BoundPredicate(
166 syn
::WhereBoundPredicate
{
167 bound_lifetimes
: Vec
::new(),
168 // the type parameter that is being bounded e.g. T
169 bounded_ty
: syn
::Ty
::Path(None
, id
.into()),
170 // the bound e.g. Serialize
172 syn
::TyParamBound
::Trait(
174 bound_lifetimes
: Vec
::new(),
175 trait_ref
: bound
.clone(),
177 syn
::TraitBoundModifier
::None
,
185 let mut generics
= generics
.clone();
186 generics
.where_clause
.predicates
.extend(new_predicates
);
190 pub fn with_self_bound(
192 generics
: &syn
::Generics
,
195 let mut generics
= generics
.clone();
200 syn
::WherePredicate
::BoundPredicate(
201 syn
::WhereBoundPredicate
{
202 bound_lifetimes
: Vec
::new(),
203 // the type that is being bounded e.g. MyStruct<'a, T>
204 bounded_ty
: type_of_item(cont
),
205 // the bound e.g. Default
207 syn
::TyParamBound
::Trait(
209 bound_lifetimes
: Vec
::new(),
210 trait_ref
: bound
.clone(),
212 syn
::TraitBoundModifier
::None
,
221 pub fn with_lifetime_bound(generics
: &syn
::Generics
, lifetime
: &str) -> syn
::Generics
{
222 let mut generics
= generics
.clone();
224 for lifetime_def
in &mut generics
.lifetimes
{
225 lifetime_def
.bounds
.push(syn
::Lifetime
::new(lifetime
));
228 for ty_param
in &mut generics
.ty_params
{
231 .push(syn
::TyParamBound
::Region(syn
::Lifetime
::new(lifetime
)));
239 lifetime
: syn
::Lifetime
::new(lifetime
),
247 fn type_of_item(cont
: &Container
) -> syn
::Ty
{
254 ident
: cont
.ident
.clone(),
255 parameters
: syn
::PathParameters
::AngleBracketed(
256 syn
::AngleBracketedParameterData
{
257 lifetimes
: cont
.generics
260 .map(|def
| def
.lifetime
.clone())
265 .map(|param
| syn
::Ty
::Path(None
, param
.ident
.clone().into()))
267 bindings
: Vec
::new(),