tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cg.rs (13188B)


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