1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4 
5 use darling::{FromDeriveInput, FromField, FromVariant};
6 use proc_macro2::{Span, TokenStream};
7 use quote::TokenStreamExt;
8 use syn::{self, AngleBracketedGenericArguments, Binding, DeriveInput, Field};
9 use syn::{GenericArgument, GenericParam, Ident, Path};
10 use syn::{PathArguments, PathSegment, QSelf, Type, TypeArray, TypeGroup};
11 use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple};
12 use syn::{Variant, WherePredicate};
13 use synstructure::{self, BindStyle, BindingInfo, VariantAst, VariantInfo};
14 
15 /// Given an input type which has some where clauses already, like:
16 ///
17 /// struct InputType<T>
18 /// where
19 ///     T: Zero,
20 /// {
21 ///     ...
22 /// }
23 ///
24 /// Add the necessary `where` clauses so that the output type of a trait
25 /// fulfils them.
26 ///
27 /// For example:
28 ///
29 /// ```ignore
30 ///     <T as ToComputedValue>::ComputedValue: Zero,
31 /// ```
32 ///
33 /// This needs to run before adding other bounds to the type parameters.
propagate_clauses_to_output_type( where_clause: &mut Option<syn::WhereClause>, generics: &syn::Generics, trait_path: &Path, trait_output: &Ident, )34 pub fn propagate_clauses_to_output_type(
35     where_clause: &mut Option<syn::WhereClause>,
36     generics: &syn::Generics,
37     trait_path: &Path,
38     trait_output: &Ident,
39 ) {
40     let where_clause = match *where_clause {
41         Some(ref mut clause) => clause,
42         None => return,
43     };
44     let mut extra_bounds = vec![];
45     for pred in &where_clause.predicates {
46         let ty = match *pred {
47             syn::WherePredicate::Type(ref ty) => ty,
48             ref predicate => panic!("Unhanded complex where predicate: {:?}", predicate),
49         };
50 
51         let path = match ty.bounded_ty {
52             syn::Type::Path(ref p) => &p.path,
53             ref ty => panic!("Unhanded complex where type: {:?}", ty),
54         };
55 
56         assert!(
57             ty.lifetimes.is_none(),
58             "Unhanded complex lifetime bound: {:?}",
59             ty,
60         );
61 
62         let ident = match path_to_ident(path) {
63             Some(i) => i,
64             None => panic!("Unhanded complex where type path: {:?}", path),
65         };
66 
67         if generics.type_params().any(|param| param.ident == *ident) {
68             extra_bounds.push(ty.clone());
69         }
70     }
71 
72     for bound in extra_bounds {
73         let ty = bound.bounded_ty;
74         let bounds = bound.bounds;
75         where_clause
76             .predicates
77             .push(parse_quote!(<#ty as #trait_path>::#trait_output: #bounds))
78     }
79 }
80 
add_predicate(where_clause: &mut Option<syn::WhereClause>, pred: WherePredicate)81 pub fn add_predicate(where_clause: &mut Option<syn::WhereClause>, pred: WherePredicate) {
82     where_clause
83         .get_or_insert(parse_quote!(where))
84         .predicates
85         .push(pred);
86 }
87 
fmap_match<F>(input: &DeriveInput, bind_style: BindStyle, f: F) -> TokenStream where F: FnMut(&BindingInfo) -> TokenStream,88 pub fn fmap_match<F>(input: &DeriveInput, bind_style: BindStyle, f: F) -> TokenStream
89 where
90     F: FnMut(&BindingInfo) -> TokenStream,
91 {
92     fmap2_match(input, bind_style, f, |_| None)
93 }
94 
fmap2_match<F, G>( input: &DeriveInput, bind_style: BindStyle, mut f: F, mut g: G, ) -> TokenStream where F: FnMut(&BindingInfo) -> TokenStream, G: FnMut(&BindingInfo) -> Option<TokenStream>,95 pub fn fmap2_match<F, G>(
96     input: &DeriveInput,
97     bind_style: BindStyle,
98     mut f: F,
99     mut g: G,
100 ) -> TokenStream
101 where
102     F: FnMut(&BindingInfo) -> TokenStream,
103     G: FnMut(&BindingInfo) -> Option<TokenStream>,
104 {
105     let mut s = synstructure::Structure::new(input);
106     s.variants_mut().iter_mut().for_each(|v| {
107         v.bind_with(|_| bind_style);
108     });
109     s.each_variant(|variant| {
110         let (mapped, mapped_fields) = value(variant, "mapped");
111         let fields_pairs = variant.bindings().iter().zip(mapped_fields.iter());
112         let mut computations = quote!();
113         computations.append_all(fields_pairs.map(|(field, mapped_field)| {
114             let expr = f(field);
115             quote! { let #mapped_field = #expr; }
116         }));
117         computations.append_all(
118             mapped_fields
119                 .iter()
120                 .map(|mapped_field| match g(mapped_field) {
121                     Some(expr) => quote! { let #mapped_field = #expr; },
122                     None => quote!(),
123                 }),
124         );
125         computations.append_all(mapped);
126         Some(computations)
127     })
128 }
129 
fmap_trait_output(input: &DeriveInput, trait_path: &Path, trait_output: &Ident) -> Path130 pub fn fmap_trait_output(input: &DeriveInput, trait_path: &Path, trait_output: &Ident) -> Path {
131     let segment = PathSegment {
132         ident: input.ident.clone(),
133         arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
134             args: input
135                 .generics
136                 .params
137                 .iter()
138                 .map(|arg| match arg {
139                     &GenericParam::Lifetime(ref data) => {
140                         GenericArgument::Lifetime(data.lifetime.clone())
141                     },
142                     &GenericParam::Type(ref data) => {
143                         let ident = &data.ident;
144                         GenericArgument::Type(parse_quote!(<#ident as #trait_path>::#trait_output))
145                     },
146                     ref arg => panic!("arguments {:?} cannot be mapped yet", arg),
147                 })
148                 .collect(),
149             colon2_token: Default::default(),
150             gt_token: Default::default(),
151             lt_token: Default::default(),
152         }),
153     };
154     segment.into()
155 }
156 
map_type_params<F>(ty: &Type, params: &[&TypeParam], self_type: &Path, f: &mut F) -> Type where F: FnMut(&Ident) -> Type,157 pub fn map_type_params<F>(ty: &Type, params: &[&TypeParam], self_type: &Path, f: &mut F) -> Type
158 where
159     F: FnMut(&Ident) -> Type,
160 {
161     match *ty {
162         Type::Slice(ref inner) => Type::from(TypeSlice {
163             elem: Box::new(map_type_params(&inner.elem, params, self_type, f)),
164             ..inner.clone()
165         }),
166         Type::Array(ref inner) => {
167             //ref ty, ref expr) => {
168             Type::from(TypeArray {
169                 elem: Box::new(map_type_params(&inner.elem, params, self_type, f)),
170                 ..inner.clone()
171             })
172         },
173         ref ty @ Type::Never(_) => ty.clone(),
174         Type::Tuple(ref inner) => Type::from(TypeTuple {
175             elems: inner
176                 .elems
177                 .iter()
178                 .map(|ty| map_type_params(&ty, params, self_type, f))
179                 .collect(),
180             ..inner.clone()
181         }),
182         Type::Path(TypePath {
183             qself: None,
184             ref path,
185         }) => {
186             if let Some(ident) = path_to_ident(path) {
187                 if params.iter().any(|ref param| &param.ident == ident) {
188                     return f(ident);
189                 }
190                 if ident == "Self" {
191                     return Type::from(TypePath {
192                         qself: None,
193                         path: self_type.clone(),
194                     });
195                 }
196             }
197             Type::from(TypePath {
198                 qself: None,
199                 path: map_type_params_in_path(path, params, self_type, f),
200             })
201         },
202         Type::Path(TypePath {
203             ref qself,
204             ref path,
205         }) => Type::from(TypePath {
206             qself: qself.as_ref().map(|qself| QSelf {
207                 ty: Box::new(map_type_params(&qself.ty, params, self_type, f)),
208                 position: qself.position,
209                 ..qself.clone()
210             }),
211             path: map_type_params_in_path(path, params, self_type, f),
212         }),
213         Type::Paren(ref inner) => Type::from(TypeParen {
214             elem: Box::new(map_type_params(&inner.elem, params, self_type, f)),
215             ..inner.clone()
216         }),
217         Type::Group(ref inner) => Type::from(TypeGroup {
218             elem: Box::new(map_type_params(&inner.elem, params, self_type, f)),
219             ..inner.clone()
220         }),
221         ref ty => panic!("type {:?} cannot be mapped yet", ty),
222     }
223 }
224 
map_type_params_in_path<F>( path: &Path, params: &[&TypeParam], self_type: &Path, f: &mut F, ) -> Path where F: FnMut(&Ident) -> Type,225 fn map_type_params_in_path<F>(
226     path: &Path,
227     params: &[&TypeParam],
228     self_type: &Path,
229     f: &mut F,
230 ) -> Path
231 where
232     F: FnMut(&Ident) -> Type,
233 {
234     Path {
235         leading_colon: path.leading_colon,
236         segments: path
237             .segments
238             .iter()
239             .map(|segment| PathSegment {
240                 ident: segment.ident.clone(),
241                 arguments: match segment.arguments {
242                     PathArguments::AngleBracketed(ref data) => {
243                         PathArguments::AngleBracketed(AngleBracketedGenericArguments {
244                             args: data
245                                 .args
246                                 .iter()
247                                 .map(|arg| match arg {
248                                     ty @ &GenericArgument::Lifetime(_) => ty.clone(),
249                                     &GenericArgument::Type(ref data) => GenericArgument::Type(
250                                         map_type_params(data, params, self_type, f),
251                                     ),
252                                     &GenericArgument::Binding(ref data) => {
253                                         GenericArgument::Binding(Binding {
254                                             ty: map_type_params(&data.ty, params, self_type, f),
255                                             ..data.clone()
256                                         })
257                                     },
258                                     ref arg => panic!("arguments {:?} cannot be mapped yet", arg),
259                                 })
260                                 .collect(),
261                             ..data.clone()
262                         })
263                     },
264                     ref arg @ PathArguments::None => arg.clone(),
265                     ref parameters => panic!("parameters {:?} cannot be mapped yet", parameters),
266                 },
267             })
268             .collect(),
269     }
270 }
271 
path_to_ident(path: &Path) -> Option<&Ident>272 fn path_to_ident(path: &Path) -> Option<&Ident> {
273     match *path {
274         Path {
275             leading_colon: None,
276             ref segments,
277         } if segments.len() == 1 => {
278             if segments[0].arguments.is_empty() {
279                 Some(&segments[0].ident)
280             } else {
281                 None
282             }
283         },
284         _ => None,
285     }
286 }
287 
parse_field_attrs<A>(field: &Field) -> A where A: FromField,288 pub fn parse_field_attrs<A>(field: &Field) -> A
289 where
290     A: FromField,
291 {
292     match A::from_field(field) {
293         Ok(attrs) => attrs,
294         Err(e) => panic!("failed to parse field attributes: {}", e),
295     }
296 }
297 
parse_input_attrs<A>(input: &DeriveInput) -> A where A: FromDeriveInput,298 pub fn parse_input_attrs<A>(input: &DeriveInput) -> A
299 where
300     A: FromDeriveInput,
301 {
302     match A::from_derive_input(input) {
303         Ok(attrs) => attrs,
304         Err(e) => panic!("failed to parse input attributes: {}", e),
305     }
306 }
307 
parse_variant_attrs_from_ast<A>(variant: &VariantAst) -> A where A: FromVariant,308 pub fn parse_variant_attrs_from_ast<A>(variant: &VariantAst) -> A
309 where
310     A: FromVariant,
311 {
312     let v = Variant {
313         ident: variant.ident.clone(),
314         attrs: variant.attrs.to_vec(),
315         fields: variant.fields.clone(),
316         discriminant: variant.discriminant.clone(),
317     };
318     parse_variant_attrs(&v)
319 }
320 
parse_variant_attrs<A>(variant: &Variant) -> A where A: FromVariant,321 pub fn parse_variant_attrs<A>(variant: &Variant) -> A
322 where
323     A: FromVariant,
324 {
325     match A::from_variant(variant) {
326         Ok(attrs) => attrs,
327         Err(e) => panic!("failed to parse variant attributes: {}", e),
328     }
329 }
330 
ref_pattern<'a>( variant: &'a VariantInfo, prefix: &str, ) -> (TokenStream, Vec<BindingInfo<'a>>)331 pub fn ref_pattern<'a>(
332     variant: &'a VariantInfo,
333     prefix: &str,
334 ) -> (TokenStream, Vec<BindingInfo<'a>>) {
335     let mut v = variant.clone();
336     v.bind_with(|_| BindStyle::Ref);
337     v.bindings_mut().iter_mut().for_each(|b| {
338         b.binding = Ident::new(&format!("{}_{}", b.binding, prefix), Span::call_site())
339     });
340     (v.pat(), v.bindings().to_vec())
341 }
342 
value<'a>(variant: &'a VariantInfo, prefix: &str) -> (TokenStream, Vec<BindingInfo<'a>>)343 pub fn value<'a>(variant: &'a VariantInfo, prefix: &str) -> (TokenStream, Vec<BindingInfo<'a>>) {
344     let mut v = variant.clone();
345     v.bindings_mut().iter_mut().for_each(|b| {
346         b.binding = Ident::new(&format!("{}_{}", b.binding, prefix), Span::call_site())
347     });
348     v.bind_with(|_| BindStyle::Move);
349     (v.pat(), v.bindings().to_vec())
350 }
351 
352 /// Transforms "FooBar" to "foo-bar".
353 ///
354 /// If the first Camel segment is "Moz", "Webkit", or "Servo", the result string
355 /// is prepended with "-".
to_css_identifier(mut camel_case: &str) -> String356 pub fn to_css_identifier(mut camel_case: &str) -> String {
357     camel_case = camel_case.trim_end_matches('_');
358     let mut first = true;
359     let mut result = String::with_capacity(camel_case.len());
360     while let Some(segment) = split_camel_segment(&mut camel_case) {
361         if first {
362             match segment {
363                 "Moz" | "Webkit" | "Servo" => first = false,
364                 _ => {},
365             }
366         }
367         if !first {
368             result.push('-');
369         }
370         first = false;
371         result.push_str(&segment.to_lowercase());
372     }
373     result
374 }
375 
376 /// Given "FooBar", returns "Foo" and sets `camel_case` to "Bar".
split_camel_segment<'input>(camel_case: &mut &'input str) -> Option<&'input str>377 fn split_camel_segment<'input>(camel_case: &mut &'input str) -> Option<&'input str> {
378     let index = match camel_case.chars().next() {
379         None => return None,
380         Some(ch) => ch.len_utf8(),
381     };
382     let end_position = camel_case[index..]
383         .find(char::is_uppercase)
384         .map_or(camel_case.len(), |pos| index + pos);
385     let result = &camel_case[..end_position];
386     *camel_case = &camel_case[end_position..];
387     Some(result)
388 }
389