tor-browser

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

specified_value_info.rs (7014B)


      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 crate::cg;
      6 use crate::parse::ParseVariantAttrs;
      7 use crate::to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs};
      8 use proc_macro2::TokenStream;
      9 use quote::TokenStreamExt;
     10 use syn::{Data, DeriveInput, Fields, Ident, Type};
     11 
     12 pub fn derive(mut input: DeriveInput) -> TokenStream {
     13    let css_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
     14    let mut types = vec![];
     15    let mut values = vec![];
     16 
     17    let input_ident = &input.ident;
     18    let input_name = || cg::to_css_identifier(&input_ident.to_string());
     19    if let Some(function) = css_attrs.function {
     20        values.push(function.explicit().unwrap_or_else(input_name));
     21    // If the whole value is wrapped in a function, value types of
     22    // its fields should not be propagated.
     23    } else {
     24        let mut where_clause = input.generics.where_clause.take();
     25        for param in input.generics.type_params() {
     26            cg::add_predicate(
     27                &mut where_clause,
     28                parse_quote!(#param: style_traits::SpecifiedValueInfo),
     29            );
     30        }
     31        input.generics.where_clause = where_clause;
     32 
     33        match input.data {
     34            Data::Enum(ref e) => {
     35                for v in e.variants.iter() {
     36                    let css_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&v);
     37                    let info_attrs = cg::parse_variant_attrs::<ValueInfoVariantAttrs>(&v);
     38                    let parse_attrs = cg::parse_variant_attrs::<ParseVariantAttrs>(&v);
     39                    if css_attrs.skip {
     40                        continue;
     41                    }
     42                    if let Some(aliases) = parse_attrs.aliases {
     43                        for alias in aliases.split(',') {
     44                            values.push(alias.to_string());
     45                        }
     46                    }
     47                    if let Some(other_values) = info_attrs.other_values {
     48                        for value in other_values.split(',') {
     49                            values.push(value.to_string());
     50                        }
     51                    }
     52                    let ident = &v.ident;
     53                    let variant_name = || cg::to_css_identifier(&ident.to_string());
     54                    if info_attrs.starts_with_keyword {
     55                        values.push(variant_name());
     56                        continue;
     57                    }
     58                    if let Some(keyword) = css_attrs.keyword {
     59                        values.push(keyword);
     60                        continue;
     61                    }
     62                    if let Some(function) = css_attrs.function {
     63                        values.push(function.explicit().unwrap_or_else(variant_name));
     64                    } else if !derive_struct_fields(&v.fields, &mut types, &mut values) {
     65                        values.push(variant_name());
     66                    }
     67                }
     68            },
     69            Data::Struct(ref s) => {
     70                if let Some(ref bitflags) = css_attrs.bitflags {
     71                    for (_rust_name, css_name) in bitflags.single_flags() {
     72                        values.push(css_name)
     73                    }
     74                    for (_rust_name, css_name) in bitflags.mixed_flags() {
     75                        values.push(css_name)
     76                    }
     77                } else if !derive_struct_fields(&s.fields, &mut types, &mut values) {
     78                    values.push(input_name());
     79                }
     80            },
     81            Data::Union(_) => unreachable!("union is not supported"),
     82        }
     83    }
     84 
     85    let info_attrs = cg::parse_input_attrs::<ValueInfoInputAttrs>(&input);
     86    if let Some(other_values) = info_attrs.other_values {
     87        for value in other_values.split(',') {
     88            values.push(value.to_string());
     89        }
     90    }
     91 
     92    let mut types_value = quote!(0);
     93    types_value.append_all(types.iter().map(|ty| {
     94        quote! {
     95            | <#ty as style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES
     96        }
     97    }));
     98 
     99    let mut nested_collects = quote!();
    100    nested_collects.append_all(types.iter().map(|ty| {
    101        quote! {
    102            <#ty as style_traits::SpecifiedValueInfo>::collect_completion_keywords(_f);
    103        }
    104    }));
    105 
    106    if let Some(ty) = info_attrs.ty {
    107        types_value.append_all(quote! {
    108            | style_traits::CssType::#ty
    109        });
    110    }
    111 
    112    let append_values = if values.is_empty() {
    113        quote!()
    114    } else {
    115        let mut value_list = quote!();
    116        value_list.append_separated(values.iter(), quote! { , });
    117        quote! { _f(&[#value_list]); }
    118    };
    119 
    120    let name = &input.ident;
    121    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    122 
    123    quote! {
    124        impl #impl_generics style_traits::SpecifiedValueInfo for #name #ty_generics
    125        #where_clause
    126        {
    127            const SUPPORTED_TYPES: u8 = #types_value;
    128 
    129            fn collect_completion_keywords(_f: &mut dyn FnMut(&[&'static str])) {
    130                #nested_collects
    131                #append_values
    132            }
    133        }
    134    }
    135 }
    136 
    137 /// Derive from the given fields. Return false if the fields is a Unit,
    138 /// true otherwise.
    139 fn derive_struct_fields<'a>(
    140    fields: &'a Fields,
    141    types: &mut Vec<&'a Type>,
    142    values: &mut Vec<String>,
    143 ) -> bool {
    144    let fields = match *fields {
    145        Fields::Unit => return false,
    146        Fields::Named(ref fields) => fields.named.iter(),
    147        Fields::Unnamed(ref fields) => fields.unnamed.iter(),
    148    };
    149    types.extend(fields.filter_map(|field| {
    150        let info_attrs = cg::parse_field_attrs::<ValueInfoFieldAttrs>(field);
    151        if let Some(other_values) = info_attrs.other_values {
    152            for value in other_values.split(',') {
    153                values.push(value.to_string());
    154            }
    155        }
    156        let css_attrs = cg::parse_field_attrs::<CssFieldAttrs>(field);
    157        if css_attrs.represents_keyword {
    158            let ident = field
    159                .ident
    160                .as_ref()
    161                .expect("only named field should use represents_keyword");
    162            values.push(cg::to_css_identifier(&ident.to_string()).replace("_", "-"));
    163            return None;
    164        }
    165        if let Some(if_empty) = css_attrs.if_empty {
    166            values.push(if_empty);
    167        }
    168        if !css_attrs.skip {
    169            Some(&field.ty)
    170        } else {
    171            None
    172        }
    173    }));
    174    true
    175 }
    176 
    177 #[derive(Default, FromDeriveInput)]
    178 #[darling(attributes(value_info), default)]
    179 struct ValueInfoInputAttrs {
    180    ty: Option<Ident>,
    181    other_values: Option<String>,
    182 }
    183 
    184 #[derive(Default, FromVariant)]
    185 #[darling(attributes(value_info), default)]
    186 struct ValueInfoVariantAttrs {
    187    starts_with_keyword: bool,
    188    other_values: Option<String>,
    189 }
    190 
    191 #[derive(Default, FromField)]
    192 #[darling(attributes(value_info), default)]
    193 struct ValueInfoFieldAttrs {
    194    other_values: Option<String>,
    195 }