]> git.proxmox.com Git - rustc.git/blob - src/vendor/serde_derive/src/bound.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / vendor / serde_derive / src / bound.rs
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
9 use std::collections::HashSet;
10
11 use syn::{self, visit};
12
13 use internals::ast::{Body, Container};
14 use internals::attr;
15
16 macro_rules! path {
17 ($($path:tt)+) => {
18 syn::parse_path(quote!($($path)+).as_str()).unwrap()
19 };
20 }
21
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
24 // allowed here".
25 pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
26 syn::Generics {
27 ty_params: generics
28 .ty_params
29 .iter()
30 .map(
31 |ty_param| {
32 syn::TyParam {
33 default: None,
34 ..ty_param.clone()
35 }
36 },
37 )
38 .collect(),
39 ..generics.clone()
40 }
41 }
42
43 pub fn with_where_predicates(
44 generics: &syn::Generics,
45 predicates: &[syn::WherePredicate],
46 ) -> syn::Generics {
47 let mut generics = generics.clone();
48 generics
49 .where_clause
50 .predicates
51 .extend_from_slice(predicates);
52 generics
53 }
54
55 pub fn with_where_predicates_from_fields<F>(
56 cont: &Container,
57 generics: &syn::Generics,
58 from_field: F,
59 ) -> syn::Generics
60 where
61 F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
62 {
63 let predicates = cont.body
64 .all_fields()
65 .flat_map(|field| from_field(&field.attrs))
66 .flat_map(|predicates| predicates.to_vec());
67
68 let mut generics = generics.clone();
69 generics.where_clause.predicates.extend(predicates);
70 generics
71 }
72
73 // Puts the given bound on any generic type parameters that are used in fields
74 // for which filter returns true.
75 //
76 // For example, the following struct needs the bound `A: Serialize, B: Serialize`.
77 //
78 // struct S<'b, A, B: 'b, C> {
79 // a: A,
80 // b: Option<&'b B>
81 // #[serde(skip_serializing)]
82 // c: C,
83 // }
84 pub fn with_bound<F>(
85 cont: &Container,
86 generics: &syn::Generics,
87 filter: F,
88 bound: &syn::Path,
89 ) -> syn::Generics
90 where
91 F: Fn(&attr::Field, Option<&attr::Variant>) -> bool,
92 {
93 struct FindTyParams {
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
99 // them.
100 relevant_ty_params: HashSet<syn::Ident>,
101 }
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.
108 return;
109 }
110 }
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);
115 }
116 }
117 visit::walk_path(self, path);
118 }
119
120 // Type parameter should not be considered used by a macro path.
121 //
122 // struct TypeMacro<T> {
123 // mac: T!(),
124 // marker: PhantomData<T>,
125 // }
126 fn visit_mac(&mut self, _mac: &syn::Mac) {}
127 }
128
129 let all_ty_params: HashSet<_> = generics
130 .ty_params
131 .iter()
132 .map(|ty_param| ty_param.ident.clone())
133 .collect();
134
135 let mut visitor = FindTyParams {
136 all_ty_params: all_ty_params,
137 relevant_ty_params: HashSet::new(),
138 };
139 match cont.body {
140 Body::Enum(ref variants) => {
141 for variant in variants.iter() {
142 let relevant_fields = variant
143 .fields
144 .iter()
145 .filter(|field| filter(&field.attrs, Some(&variant.attrs)));
146 for field in relevant_fields {
147 visit::walk_ty(&mut visitor, field.ty);
148 }
149 }
150 }
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);
154 }
155 }
156 }
157
158 let new_predicates = generics
159 .ty_params
160 .iter()
161 .map(|ty_param| ty_param.ident.clone())
162 .filter(|id| visitor.relevant_ty_params.contains(id))
163 .map(
164 |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
171 bounds: vec![
172 syn::TyParamBound::Trait(
173 syn::PolyTraitRef {
174 bound_lifetimes: Vec::new(),
175 trait_ref: bound.clone(),
176 },
177 syn::TraitBoundModifier::None,
178 ),
179 ],
180 },
181 )
182 },
183 );
184
185 let mut generics = generics.clone();
186 generics.where_clause.predicates.extend(new_predicates);
187 generics
188 }
189
190 pub fn with_self_bound(
191 cont: &Container,
192 generics: &syn::Generics,
193 bound: &syn::Path,
194 ) -> syn::Generics {
195 let mut generics = generics.clone();
196 generics
197 .where_clause
198 .predicates
199 .push(
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
206 bounds: vec![
207 syn::TyParamBound::Trait(
208 syn::PolyTraitRef {
209 bound_lifetimes: Vec::new(),
210 trait_ref: bound.clone(),
211 },
212 syn::TraitBoundModifier::None,
213 ),
214 ],
215 },
216 ),
217 );
218 generics
219 }
220
221 pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
222 let mut generics = generics.clone();
223
224 for lifetime_def in &mut generics.lifetimes {
225 lifetime_def.bounds.push(syn::Lifetime::new(lifetime));
226 }
227
228 for ty_param in &mut generics.ty_params {
229 ty_param
230 .bounds
231 .push(syn::TyParamBound::Region(syn::Lifetime::new(lifetime)));
232 }
233
234 generics
235 .lifetimes
236 .push(
237 syn::LifetimeDef {
238 attrs: Vec::new(),
239 lifetime: syn::Lifetime::new(lifetime),
240 bounds: Vec::new(),
241 },
242 );
243
244 generics
245 }
246
247 fn type_of_item(cont: &Container) -> syn::Ty {
248 syn::Ty::Path(
249 None,
250 syn::Path {
251 global: false,
252 segments: vec![
253 syn::PathSegment {
254 ident: cont.ident.clone(),
255 parameters: syn::PathParameters::AngleBracketed(
256 syn::AngleBracketedParameterData {
257 lifetimes: cont.generics
258 .lifetimes
259 .iter()
260 .map(|def| def.lifetime.clone())
261 .collect(),
262 types: cont.generics
263 .ty_params
264 .iter()
265 .map(|param| syn::Ty::Path(None, param.ident.clone().into()))
266 .collect(),
267 bindings: Vec::new(),
268 },
269 ),
270 },
271 ],
272 },
273 )
274 }