diff --git a/servo/components/style_derive/animate.rs b/servo/components/style_derive/animate.rs --- a/servo/components/style_derive/animate.rs +++ b/servo/components/style_derive/animate.rs @@ -1,129 +1,129 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cg; use darling::util::IdentList; use quote::Tokens; use syn::{DeriveInput, Path}; use synstructure::{Structure, VariantInfo}; pub fn derive(mut input: DeriveInput) -> Tokens { let animation_input_attrs = cg::parse_input_attrs::(&input); let no_bound = animation_input_attrs.no_bound.unwrap_or_default(); let mut where_clause = input.generics.where_clause.take(); for param in input.generics.type_params() { if !no_bound.contains(¶m.ident) { cg::add_predicate( &mut where_clause, parse_quote!(#param: ::values::animated::Animate), ); } } input.generics.where_clause = where_clause; let s = Structure::new(&input); let mut append_error_clause = s.variants().len() > 1; let mut match_body = s.variants().iter().fold(quote!(), |body, variant| { let arm = match derive_variant_arm(variant) { Ok(arm) => arm, Err(()) => { append_error_clause = true; return body; - } + }, }; quote! { #body #arm } }); if append_error_clause { let input_attrs = cg::parse_input_attrs::(&input); if let Some(fallback) = input_attrs.fallback { match_body.append_all(quote! { (this, other) => #fallback(this, other, procedure) }); } else { match_body.append_all(quote! { _ => Err(()) }); } } let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); quote! { impl #impl_generics ::values::animated::Animate for #name #ty_generics #where_clause { #[allow(unused_variables, unused_imports)] #[inline] fn animate( &self, other: &Self, procedure: ::values::animated::Procedure, ) -> Result { match (self, other) { #match_body } } } } } fn derive_variant_arm(variant: &VariantInfo) -> Result { let variant_attrs = cg::parse_variant_attrs_from_ast::(&variant.ast()); if variant_attrs.error { return Err(()); } let (this_pattern, this_info) = cg::ref_pattern(&variant, "this"); let (other_pattern, other_info) = cg::ref_pattern(&variant, "other"); let (result_value, result_info) = cg::value(&variant, "result"); let mut computations = quote!(); let iter = result_info.iter().zip(this_info.iter().zip(&other_info)); computations.append_all(iter.map(|(result, (this, other))| { let field_attrs = cg::parse_field_attrs::(&result.ast()); if field_attrs.constant { quote! { if #this != #other { return Err(()); } let #result = ::std::clone::Clone::clone(#this); } } else { quote! { let #result = ::values::animated::Animate::animate(#this, #other, procedure)?; } } })); Ok(quote! { (&#this_pattern, &#other_pattern) => { #computations Ok(#result_value) } }) } #[darling(attributes(animate), default)] #[derive(Default, FromDeriveInput)] struct AnimateInputAttrs { fallback: Option, } #[darling(attributes(animation), default)] #[derive(Default, FromDeriveInput)] pub struct AnimationInputAttrs { pub no_bound: Option, } #[darling(attributes(animation), default)] #[derive(Default, FromVariant)] pub struct AnimationVariantAttrs { pub error: bool, // Only here because of structs, where the struct definition acts as a // variant itself. pub no_bound: Option, } #[darling(attributes(animation), default)] #[derive(Default, FromField)] pub struct AnimationFieldAttrs { pub constant: bool, } diff --git a/servo/components/style_derive/cg.rs b/servo/components/style_derive/cg.rs --- a/servo/components/style_derive/cg.rs +++ b/servo/components/style_derive/cg.rs @@ -1,271 +1,283 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use darling::{FromDeriveInput, FromField, FromVariant}; use quote::Tokens; use syn::{self, AngleBracketedGenericArguments, Binding, DeriveInput, Field}; use syn::{GenericArgument, GenericParam, Ident, Path}; use syn::{PathArguments, PathSegment, QSelf, Type, TypeArray}; use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple}; use syn::{Variant, WherePredicate}; use synstructure::{self, BindingInfo, BindStyle, VariantAst, VariantInfo}; -pub fn add_predicate( - where_clause: &mut Option, - pred: WherePredicate, -) { - where_clause.get_or_insert(parse_quote!(where)).predicates.push(pred); +pub fn add_predicate(where_clause: &mut Option, pred: WherePredicate) { + where_clause + .get_or_insert(parse_quote!(where)) + .predicates + .push(pred); } -pub fn fmap_match( - input: &DeriveInput, - bind_style: BindStyle, - mut f: F, -) -> Tokens +pub fn fmap_match(input: &DeriveInput, bind_style: BindStyle, mut f: F) -> Tokens where F: FnMut(BindingInfo) -> Tokens, { let mut s = synstructure::Structure::new(input); - s.variants_mut().iter_mut().for_each(|v| { v.bind_with(|_| bind_style); }); + s.variants_mut().iter_mut().for_each(|v| { + v.bind_with(|_| bind_style); + }); s.each_variant(|variant| { let (mapped, mapped_fields) = value(variant, "mapped"); let fields_pairs = variant.bindings().into_iter().zip(mapped_fields); let mut computations = quote!(); computations.append_all(fields_pairs.map(|(field, mapped_field)| { let expr = f(field.clone()); quote! { let #mapped_field = #expr; } })); computations.append_all(mapped); Some(computations) }) } -pub fn fmap_trait_output( - input: &DeriveInput, - trait_path: &Path, - trait_output: Ident, -) -> Path { +pub fn fmap_trait_output(input: &DeriveInput, trait_path: &Path, trait_output: Ident) -> Path { let segment = PathSegment { ident: input.ident.clone(), arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { - args: input.generics.params.iter().map(|arg| { - match arg { - &GenericParam::Lifetime(ref data) => GenericArgument::Lifetime(data.lifetime.clone()), + args: input + .generics + .params + .iter() + .map(|arg| match arg { + &GenericParam::Lifetime(ref data) => { + GenericArgument::Lifetime(data.lifetime.clone()) + }, &GenericParam::Type(ref data) => { let ident = data.ident; GenericArgument::Type( parse_quote!(<#ident as ::#trait_path>::#trait_output), ) }, - ref arg => panic!("arguments {:?} cannot be mapped yet", arg) - } - }).collect(), + ref arg => panic!("arguments {:?} cannot be mapped yet", arg), + }).collect(), colon2_token: Default::default(), gt_token: Default::default(), lt_token: Default::default(), - - }) + }), }; segment.into() } pub fn map_type_params(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type where F: FnMut(&Ident) -> Type, { match *ty { - Type::Slice(ref inner) => { - Type::from(TypeSlice { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() }) - }, - Type::Array(ref inner) => { //ref ty, ref expr) => { - Type::from(TypeArray { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() }) + Type::Slice(ref inner) => Type::from(TypeSlice { + elem: Box::new(map_type_params(&inner.elem, params, f)), + ..inner.clone() + }), + Type::Array(ref inner) => { + //ref ty, ref expr) => { + Type::from(TypeArray { + elem: Box::new(map_type_params(&inner.elem, params, f)), + ..inner.clone() + }) }, ref ty @ Type::Never(_) => ty.clone(), - Type::Tuple(ref inner) => { - Type::from( - TypeTuple { - elems: inner.elems.iter().map(|ty| map_type_params(&ty, params, f)).collect(), - ..inner.clone() - } - ) - }, - Type::Path(TypePath { qself: None, ref path }) => { + Type::Tuple(ref inner) => Type::from(TypeTuple { + elems: inner + .elems + .iter() + .map(|ty| map_type_params(&ty, params, f)) + .collect(), + ..inner.clone() + }), + Type::Path(TypePath { + qself: None, + ref path, + }) => { if let Some(ident) = path_to_ident(path) { if params.iter().any(|param| param.ident == ident) { return f(ident); } } - Type::from(TypePath { qself: None, path: map_type_params_in_path(path, params, f) }) - } - Type::Path(TypePath { ref qself, ref path }) => { Type::from(TypePath { - qself: qself.as_ref().map(|qself| { - QSelf { - ty: Box::new(map_type_params(&qself.ty, params, f)), - position: qself.position, - ..qself.clone() - } - }), + qself: None, path: map_type_params_in_path(path, params, f), }) }, - Type::Paren(ref inner) => { - Type::from(TypeParen { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() }) - }, + Type::Path(TypePath { + ref qself, + ref path, + }) => Type::from(TypePath { + qself: qself.as_ref().map(|qself| QSelf { + ty: Box::new(map_type_params(&qself.ty, params, f)), + position: qself.position, + ..qself.clone() + }), + path: map_type_params_in_path(path, params, f), + }), + Type::Paren(ref inner) => Type::from(TypeParen { + elem: Box::new(map_type_params(&inner.elem, params, f)), + ..inner.clone() + }), ref ty => panic!("type {:?} cannot be mapped yet", ty), } } fn map_type_params_in_path(path: &Path, params: &[&TypeParam], f: &mut F) -> Path where F: FnMut(&Ident) -> Type, { Path { leading_colon: path.leading_colon, - segments: path.segments.iter().map(|segment| { - PathSegment { + segments: path + .segments + .iter() + .map(|segment| PathSegment { ident: segment.ident.clone(), arguments: match segment.arguments { PathArguments::AngleBracketed(ref data) => { PathArguments::AngleBracketed(AngleBracketedGenericArguments { - args: data.args.iter().map(|arg| { - match arg { + args: data + .args + .iter() + .map(|arg| match arg { ty @ &GenericArgument::Lifetime(_) => ty.clone(), &GenericArgument::Type(ref data) => { GenericArgument::Type(map_type_params(data, params, f)) }, - &GenericArgument::Binding(ref data) => GenericArgument::Binding(Binding { - ty: map_type_params(&data.ty, params, f), - ..data.clone() - }), - ref arg => panic!("arguments {:?} cannot be mapped yet", arg) - } - }).collect(), + &GenericArgument::Binding(ref data) => { + GenericArgument::Binding(Binding { + ty: map_type_params(&data.ty, params, f), + ..data.clone() + }) + }, + ref arg => panic!("arguments {:?} cannot be mapped yet", arg), + }).collect(), ..data.clone() }) }, ref arg @ PathArguments::None => arg.clone(), - ref parameters => { - panic!("parameters {:?} cannot be mapped yet", parameters) - } + ref parameters => panic!("parameters {:?} cannot be mapped yet", parameters), }, - } - }).collect(), + }).collect(), } } fn path_to_ident(path: &Path) -> Option<&Ident> { match *path { - Path { leading_colon: None, ref segments } if segments.len() == 1 => { + Path { + leading_colon: None, + ref segments, + } + if segments.len() == 1 => + { if segments[0].arguments.is_empty() { Some(&segments[0].ident) } else { None } }, _ => None, } } pub fn parse_field_attrs(field: &Field) -> A where A: FromField, { match A::from_field(field) { Ok(attrs) => attrs, Err(e) => panic!("failed to parse field attributes: {}", e), } } pub fn parse_input_attrs(input: &DeriveInput) -> A where A: FromDeriveInput, { match A::from_derive_input(input) { Ok(attrs) => attrs, Err(e) => panic!("failed to parse input attributes: {}", e), } } pub fn parse_variant_attrs_from_ast(variant: &VariantAst) -> A where A: FromVariant, { let v = Variant { ident: *variant.ident, attrs: variant.attrs.to_vec(), fields: variant.fields.clone(), discriminant: variant.discriminant.clone(), }; parse_variant_attrs(&v) } pub fn parse_variant_attrs(variant: &Variant) -> A where - A: FromVariant + A: FromVariant, { match A::from_variant(variant) { Ok(attrs) => attrs, Err(e) => panic!("failed to parse variant attributes: {}", e), } } - -pub fn ref_pattern<'a>( - variant: &'a VariantInfo, - prefix: &str, -) -> (Tokens, Vec>) { +pub fn ref_pattern<'a>(variant: &'a VariantInfo, prefix: &str) -> (Tokens, Vec>) { let mut v = variant.clone(); v.bind_with(|_| BindStyle::Ref); - v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) }); + v.bindings_mut() + .iter_mut() + .for_each(|b| b.binding = Ident::from(format!("{}_{}", b.binding, prefix))); (v.pat(), v.bindings().iter().cloned().collect()) } -pub fn value<'a>( - variant: &'a VariantInfo, - prefix: &str, -) -> (Tokens, Vec>) { +pub fn value<'a>(variant: &'a VariantInfo, prefix: &str) -> (Tokens, Vec>) { let mut v = variant.clone(); - v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) }); + v.bindings_mut() + .iter_mut() + .for_each(|b| b.binding = Ident::from(format!("{}_{}", b.binding, prefix))); v.bind_with(|_| BindStyle::Move); (v.pat(), v.bindings().iter().cloned().collect()) } /// Transforms "FooBar" to "foo-bar". /// /// If the first Camel segment is "Moz", "Webkit", or "Servo", the result string /// is prepended with "-". pub fn to_css_identifier(mut camel_case: &str) -> String { camel_case = camel_case.trim_right_matches('_'); let mut first = true; let mut result = String::with_capacity(camel_case.len()); while let Some(segment) = split_camel_segment(&mut camel_case) { if first { match segment { "Moz" | "Webkit" | "Servo" => first = false, _ => {}, } } if !first { result.push_str("-"); } first = false; result.push_str(&segment.to_lowercase()); } result } /// Given "FooBar", returns "Foo" and sets `camel_case` to "Bar". fn split_camel_segment<'input>(camel_case: &mut &'input str) -> Option<&'input str> { let index = match camel_case.chars().next() { None => return None, Some(ch) => ch.len_utf8(), }; let end_position = camel_case[index..] .find(char::is_uppercase) .map_or(camel_case.len(), |pos| index + pos); let result = &camel_case[..end_position]; *camel_case = &camel_case[end_position..]; Some(result) } diff --git a/servo/components/style_derive/lib.rs b/servo/components/style_derive/lib.rs --- a/servo/components/style_derive/lib.rs +++ b/servo/components/style_derive/lib.rs @@ -1,71 +1,74 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #![recursion_limit = "128"] -#[macro_use] extern crate darling; +#[macro_use] +extern crate darling; extern crate proc_macro; -#[macro_use] extern crate quote; -#[macro_use] extern crate syn; +#[macro_use] +extern crate quote; +#[macro_use] +extern crate syn; extern crate synstructure; use proc_macro::TokenStream; mod animate; mod cg; mod compute_squared_distance; mod parse; mod specified_value_info; mod to_animated_value; mod to_animated_zero; mod to_computed_value; mod to_css; #[proc_macro_derive(Animate, attributes(animate, animation))] pub fn derive_animate(stream: TokenStream) -> TokenStream { let input = syn::parse(stream).unwrap(); animate::derive(input).into() } #[proc_macro_derive(ComputeSquaredDistance, attributes(animation, distance))] pub fn derive_compute_squared_distance(stream: TokenStream) -> TokenStream { let input = syn::parse(stream).unwrap(); compute_squared_distance::derive(input).into() } #[proc_macro_derive(ToAnimatedValue)] pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream { let input = syn::parse(stream).unwrap(); to_animated_value::derive(input).into() } #[proc_macro_derive(Parse, attributes(css, parse))] pub fn derive_parse(stream: TokenStream) -> TokenStream { let input = syn::parse(stream).unwrap(); parse::derive(input).into() } #[proc_macro_derive(ToAnimatedZero, attributes(animation, zero))] pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream { let input = syn::parse(stream).unwrap(); to_animated_zero::derive(input).into() } #[proc_macro_derive(ToComputedValue, attributes(compute))] pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream { let input = syn::parse(stream).unwrap(); to_computed_value::derive(input).into() } #[proc_macro_derive(ToCss, attributes(css))] pub fn derive_to_css(stream: TokenStream) -> TokenStream { let input = syn::parse(stream).unwrap(); to_css::derive(input).into() } #[proc_macro_derive(SpecifiedValueInfo, attributes(css, parse, value_info))] pub fn derive_specified_value_info(stream: TokenStream) -> TokenStream { let input = syn::parse(stream).unwrap(); specified_value_info::derive(input).into() } diff --git a/servo/components/style_derive/parse.rs b/servo/components/style_derive/parse.rs --- a/servo/components/style_derive/parse.rs +++ b/servo/components/style_derive/parse.rs @@ -1,140 +1,139 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cg; use quote::Tokens; use syn::{DeriveInput, Path}; use synstructure; use to_css::CssVariantAttrs; #[darling(attributes(parse), default)] #[derive(Default, FromVariant)] pub struct ParseVariantAttrs { pub aliases: Option, pub condition: Option, } pub fn derive(input: DeriveInput) -> Tokens { let name = &input.ident; let s = synstructure::Structure::new(&input); let mut saw_condition = false; let match_body = s.variants().iter().fold(quote!(), |match_body, variant| { let bindings = variant.bindings(); assert!( bindings.is_empty(), "Parse is only supported for single-variant enums for now" ); - let css_variant_attrs = - cg::parse_variant_attrs_from_ast::(&variant.ast()); - let parse_attrs = - cg::parse_variant_attrs_from_ast::(&variant.ast()); + let css_variant_attrs = cg::parse_variant_attrs_from_ast::(&variant.ast()); + let parse_attrs = cg::parse_variant_attrs_from_ast::(&variant.ast()); if css_variant_attrs.skip { return match_body; } let identifier = cg::to_css_identifier( - &css_variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()), + &css_variant_attrs + .keyword + .unwrap_or(variant.ast().ident.as_ref().into()), ); let ident = &variant.ast().ident; saw_condition |= parse_attrs.condition.is_some(); let condition = match parse_attrs.condition { Some(ref p) => quote! { if #p(context) }, - None => quote! { }, + None => quote!{}, }; let mut body = quote! { #match_body #identifier #condition => Ok(#name::#ident), }; let aliases = match parse_attrs.aliases { Some(aliases) => aliases, None => return body, }; for alias in aliases.split(",") { body = quote! { #body #alias #condition => Ok(#name::#ident), }; } body }); let context_ident = if saw_condition { quote! { context } } else { quote! { _ } }; let parse_body = if saw_condition { quote! { let location = input.current_source_location(); let ident = input.expect_ident()?; match_ignore_ascii_case! { &ident, #match_body _ => Err(location.new_unexpected_token_error( ::cssparser::Token::Ident(ident.clone()) )) } } } else { quote! { Self::parse(input) } }; - let parse_trait_impl = quote! { impl ::parser::Parse for #name { #[inline] fn parse<'i, 't>( #context_ident: &::parser::ParserContext, input: &mut ::cssparser::Parser<'i, 't>, ) -> Result> { #parse_body } } }; if saw_condition { return parse_trait_impl; } // TODO(emilio): It'd be nice to get rid of these, but that makes the // conversion harder... let methods_impl = quote! { impl #name { /// Parse this keyword. #[inline] pub fn parse<'i, 't>( input: &mut ::cssparser::Parser<'i, 't>, ) -> Result> { let location = input.current_source_location(); let ident = input.expect_ident()?; Self::from_ident(ident.as_ref()).map_err(|()| { location.new_unexpected_token_error( ::cssparser::Token::Ident(ident.clone()) ) }) } /// Parse this keyword from a string slice. #[inline] pub fn from_ident(ident: &str) -> Result { match_ignore_ascii_case! { ident, #match_body _ => Err(()), } } } }; quote! { #parse_trait_impl #methods_impl } } diff --git a/servo/components/style_derive/specified_value_info.rs b/servo/components/style_derive/specified_value_info.rs --- a/servo/components/style_derive/specified_value_info.rs +++ b/servo/components/style_derive/specified_value_info.rs @@ -1,182 +1,188 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cg; use parse::ParseVariantAttrs; use quote::Tokens; use syn::{Data, DeriveInput, Fields, Ident, Type}; use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs}; pub fn derive(mut input: DeriveInput) -> Tokens { let css_attrs = cg::parse_input_attrs::(&input); let mut types = vec![]; let mut values = vec![]; let input_ident = input.ident; let input_name = || cg::to_css_identifier(input_ident.as_ref()); if let Some(function) = css_attrs.function { values.push(function.explicit().unwrap_or_else(input_name)); - // If the whole value is wrapped in a function, value types of - // its fields should not be propagated. + // If the whole value is wrapped in a function, value types of + // its fields should not be propagated. } else { let mut where_clause = input.generics.where_clause.take(); for param in input.generics.type_params() { cg::add_predicate( &mut where_clause, parse_quote!(#param: ::style_traits::SpecifiedValueInfo), ); } input.generics.where_clause = where_clause; match input.data { Data::Enum(ref e) => { for v in e.variants.iter() { let css_attrs = cg::parse_variant_attrs::(&v); let info_attrs = cg::parse_variant_attrs::(&v); let parse_attrs = cg::parse_variant_attrs::(&v); if css_attrs.skip { continue; } if let Some(aliases) = parse_attrs.aliases { for alias in aliases.split(",") { values.push(alias.to_string()); } } if let Some(other_values) = info_attrs.other_values { for value in other_values.split(",") { values.push(value.to_string()); } } let ident = &v.ident; let variant_name = || cg::to_css_identifier(ident.as_ref()); if info_attrs.starts_with_keyword { values.push(variant_name()); continue; } if let Some(keyword) = css_attrs.keyword { values.push(keyword); continue; } if let Some(function) = css_attrs.function { values.push(function.explicit().unwrap_or_else(variant_name)); } else { if !derive_struct_fields(&v.fields, &mut types, &mut values) { values.push(variant_name()); } } } - } + }, Data::Struct(ref s) => { if !derive_struct_fields(&s.fields, &mut types, &mut values) { values.push(input_name()); } - } + }, Data::Union(_) => unreachable!("union is not supported"), } } let info_attrs = cg::parse_input_attrs::(&input); if let Some(other_values) = info_attrs.other_values { for value in other_values.split(",") { values.push(value.to_string()); } } let mut types_value = quote!(0); - types_value.append_all(types.iter().map(|ty| quote! { - | <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES + types_value.append_all(types.iter().map(|ty| { + quote! { + | <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES + } })); let mut nested_collects = quote!(); - nested_collects.append_all(types.iter().map(|ty| quote! { - <#ty as ::style_traits::SpecifiedValueInfo>::collect_completion_keywords(_f); + nested_collects.append_all(types.iter().map(|ty| { + quote! { + <#ty as ::style_traits::SpecifiedValueInfo>::collect_completion_keywords(_f); + } })); if let Some(ty) = info_attrs.ty { types_value.append_all(quote! { | ::style_traits::CssType::#ty }); } let append_values = if values.is_empty() { quote!() } else { let mut value_list = quote!(); value_list.append_separated(values.iter(), quote! { , }); quote! { _f(&[#value_list]); } }; let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); quote! { impl #impl_generics ::style_traits::SpecifiedValueInfo for #name #ty_generics #where_clause { const SUPPORTED_TYPES: u8 = #types_value; fn collect_completion_keywords(_f: &mut FnMut(&[&'static str])) { #nested_collects #append_values } } } } /// Derive from the given fields. Return false if the fields is a Unit, /// true otherwise. fn derive_struct_fields<'a>( fields: &'a Fields, types: &mut Vec<&'a Type>, values: &mut Vec, ) -> bool { let fields = match *fields { Fields::Unit => return false, Fields::Named(ref fields) => fields.named.iter(), Fields::Unnamed(ref fields) => fields.unnamed.iter(), }; types.extend(fields.filter_map(|field| { let info_attrs = cg::parse_field_attrs::(field); if let Some(other_values) = info_attrs.other_values { for value in other_values.split(",") { values.push(value.to_string()); } } let css_attrs = cg::parse_field_attrs::(field); if css_attrs.represents_keyword { - let ident = field.ident.as_ref() + let ident = field + .ident + .as_ref() .expect("only named field should use represents_keyword"); values.push(cg::to_css_identifier(ident.as_ref())); return None; } if let Some(if_empty) = css_attrs.if_empty { values.push(if_empty); } if !css_attrs.skip { Some(&field.ty) } else { None } })); true } #[darling(attributes(value_info), default)] #[derive(Default, FromDeriveInput)] struct ValueInfoInputAttrs { ty: Option, other_values: Option, } #[darling(attributes(value_info), default)] #[derive(Default, FromVariant)] struct ValueInfoVariantAttrs { starts_with_keyword: bool, other_values: Option, } #[darling(attributes(value_info), default)] #[derive(Default, FromField)] struct ValueInfoFieldAttrs { other_values: Option, } diff --git a/servo/components/style_derive/to_animated_value.rs b/servo/components/style_derive/to_animated_value.rs --- a/servo/components/style_derive/to_animated_value.rs +++ b/servo/components/style_derive/to_animated_value.rs @@ -1,55 +1,59 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cg; use quote; use syn::DeriveInput; use synstructure::BindStyle; pub fn derive(mut input: DeriveInput) -> quote::Tokens { let mut where_clause = input.generics.where_clause.take(); for param in input.generics.type_params() { cg::add_predicate( &mut where_clause, parse_quote!(#param: ::values::animated::ToAnimatedValue), ); } - let to_body = cg::fmap_match(&input, BindStyle::Move, |binding| { - quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding)) - }); - let from_body = cg::fmap_match(&input, BindStyle::Move, |binding| { - quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding)) - }); + let to_body = cg::fmap_match( + &input, + BindStyle::Move, + |binding| quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding)), + ); + let from_body = cg::fmap_match( + &input, + BindStyle::Move, + |binding| quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding)), + ); input.generics.where_clause = where_clause; let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let animated_value_type = cg::fmap_trait_output( &input, &parse_quote!(values::animated::ToAnimatedValue), "AnimatedValue".into(), ); quote! { impl #impl_generics ::values::animated::ToAnimatedValue for #name #ty_generics #where_clause { type AnimatedValue = #animated_value_type; #[allow(unused_variables)] #[inline] fn to_animated_value(self) -> Self::AnimatedValue { match self { #to_body } } #[inline] fn from_animated_value(animated: Self::AnimatedValue) -> Self { match animated { #from_body } } } } } diff --git a/servo/components/style_derive/to_computed_value.rs b/servo/components/style_derive/to_computed_value.rs --- a/servo/components/style_derive/to_computed_value.rs +++ b/servo/components/style_derive/to_computed_value.rs @@ -1,109 +1,111 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cg; use quote::Tokens; use syn::DeriveInput; use synstructure::BindStyle; pub fn derive(mut input: DeriveInput) -> Tokens { let mut where_clause = input.generics.where_clause.take(); let (to_body, from_body) = { let params = input.generics.type_params().collect::>(); for param in ¶ms { cg::add_predicate( &mut where_clause, parse_quote!(#param: ::values::computed::ToComputedValue), ); } let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { let attrs = cg::parse_field_attrs::(&binding.ast()); if attrs.field_bound { let ty = &binding.ast().ty; - let output_type = cg::map_type_params(ty, ¶ms, &mut |ident| { - parse_quote!(<#ident as ::values::computed::ToComputedValue>::ComputedValue) - }); + let output_type = cg::map_type_params( + ty, + ¶ms, + &mut |ident| parse_quote!(<#ident as ::values::computed::ToComputedValue>::ComputedValue), + ); cg::add_predicate( &mut where_clause, parse_quote!( #ty: ::values::computed::ToComputedValue ), ); } quote! { ::values::computed::ToComputedValue::to_computed_value(#binding, context) } }); let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { quote! { ::values::computed::ToComputedValue::from_computed_value(#binding) } }); (to_body, from_body) }; input.generics.where_clause = where_clause; let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); if input.generics.type_params().next().is_none() { return quote! { impl #impl_generics ::values::computed::ToComputedValue for #name #ty_generics #where_clause { type ComputedValue = Self; #[inline] fn to_computed_value( &self, _context: &::values::computed::Context, ) -> Self::ComputedValue { ::std::clone::Clone::clone(self) } #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { ::std::clone::Clone::clone(computed) } } - } + }; } let computed_value_type = cg::fmap_trait_output( &input, &parse_quote!(values::computed::ToComputedValue), "ComputedValue".into(), ); quote! { impl #impl_generics ::values::computed::ToComputedValue for #name #ty_generics #where_clause { type ComputedValue = #computed_value_type; #[allow(unused_variables)] #[inline] fn to_computed_value(&self, context: &::values::computed::Context) -> Self::ComputedValue { match *self { #to_body } } #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { match *computed { #from_body } } } } } #[darling(attributes(compute), default)] #[derive(Default, FromField)] struct ComputedValueAttrs { field_bound: bool, } diff --git a/servo/components/style_derive/to_css.rs b/servo/components/style_derive/to_css.rs --- a/servo/components/style_derive/to_css.rs +++ b/servo/components/style_derive/to_css.rs @@ -1,251 +1,254 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cg; use darling::util::Override; use quote::{ToTokens, Tokens}; use syn::{self, Data, Path, WhereClause}; use synstructure::{BindingInfo, Structure, VariantInfo}; pub fn derive(mut input: syn::DeriveInput) -> Tokens { let mut where_clause = input.generics.where_clause.take(); for param in input.generics.type_params() { cg::add_predicate( &mut where_clause, parse_quote!(#param: ::style_traits::ToCss), ); } let input_attrs = cg::parse_input_attrs::(&input); if let Data::Enum(_) = input.data { - assert!(input_attrs.function.is_none(), "#[css(function)] is not allowed on enums"); + assert!( + input_attrs.function.is_none(), + "#[css(function)] is not allowed on enums" + ); assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums"); } let match_body = { let s = Structure::new(&input); - s.each_variant(|variant| { - derive_variant_arm(variant, &mut where_clause) - }) + s.each_variant(|variant| derive_variant_arm(variant, &mut where_clause)) }; input.generics.where_clause = where_clause; let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let mut impls = quote! { impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause { #[allow(unused_variables)] #[inline] fn to_css( &self, dest: &mut ::style_traits::CssWriter, ) -> ::std::fmt::Result where W: ::std::fmt::Write, { match *self { #match_body } } } }; if input_attrs.derive_debug { impls.append_all(quote! { impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { ::style_traits::ToCss::to_css( self, &mut ::style_traits::CssWriter::new(f), ) } } }); } impls } -fn derive_variant_arm( - variant: &VariantInfo, - generics: &mut Option, -) -> Tokens { +fn derive_variant_arm(variant: &VariantInfo, generics: &mut Option) -> Tokens { let bindings = variant.bindings(); let identifier = cg::to_css_identifier(variant.ast().ident.as_ref()); let ast = variant.ast(); let variant_attrs = cg::parse_variant_attrs_from_ast::(&ast); let separator = if variant_attrs.comma { ", " } else { " " }; if variant_attrs.skip { return quote!(Ok(())); } if variant_attrs.dimension { assert_eq!(bindings.len(), 1); assert!( variant_attrs.function.is_none() && variant_attrs.keyword.is_none(), "That makes no sense" ); } let mut expr = if let Some(keyword) = variant_attrs.keyword { assert!(bindings.is_empty()); quote! { ::std::fmt::Write::write_str(dest, #keyword) } } else if !bindings.is_empty() { derive_variant_fields_expr(bindings, generics, separator) } else { quote! { ::std::fmt::Write::write_str(dest, #identifier) } }; if variant_attrs.dimension { expr = quote! { #expr?; ::std::fmt::Write::write_str(dest, #identifier) } } else if let Some(function) = variant_attrs.function { let mut identifier = function.explicit().map_or(identifier, |name| name); identifier.push_str("("); expr = quote! { ::std::fmt::Write::write_str(dest, #identifier)?; #expr?; ::std::fmt::Write::write_str(dest, ")") } } expr } fn derive_variant_fields_expr( bindings: &[BindingInfo], where_clause: &mut Option, separator: &str, ) -> Tokens { - let mut iter = bindings.iter().filter_map(|binding| { - let attrs = cg::parse_field_attrs::(&binding.ast()); - if attrs.skip { - return None; - } - Some((binding, attrs)) - }).peekable(); + let mut iter = bindings + .iter() + .filter_map(|binding| { + let attrs = cg::parse_field_attrs::(&binding.ast()); + if attrs.skip { + return None; + } + Some((binding, attrs)) + }).peekable(); let (first, attrs) = match iter.next() { Some(pair) => pair, None => return quote! { Ok(()) }, }; if !attrs.iterable && iter.peek().is_none() { if attrs.field_bound { let ty = &first.ast().ty; cg::add_predicate(where_clause, parse_quote!(#ty: ::style_traits::ToCss)); } let mut expr = quote! { ::style_traits::ToCss::to_css(#first, dest) }; if let Some(condition) = attrs.skip_if { expr = quote! { if !#condition(#first) { #expr } } } return expr; } let mut expr = derive_single_field_expr(first, attrs, where_clause); for (binding, attrs) in iter { derive_single_field_expr(binding, attrs, where_clause).to_tokens(&mut expr) } quote! {{ let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator); #expr Ok(()) }} } fn derive_single_field_expr( field: &BindingInfo, attrs: CssFieldAttrs, where_clause: &mut Option, ) -> Tokens { let mut expr = if attrs.iterable { if let Some(if_empty) = attrs.if_empty { return quote! { { let mut iter = #field.iter().peekable(); if iter.peek().is_none() { writer.raw_item(#if_empty)?; } else { for item in iter { writer.item(&item)?; } } } }; } quote! { for item in #field.iter() { writer.item(&item)?; } } } else if attrs.represents_keyword { - let ident = - field.ast().ident.as_ref().expect("Unnamed field with represents_keyword?"); + let ident = field + .ast() + .ident + .as_ref() + .expect("Unnamed field with represents_keyword?"); let ident = cg::to_css_identifier(ident.as_ref()); quote! { if *#field { writer.raw_item(#ident)?; } } } else { if attrs.field_bound { let ty = &field.ast().ty; cg::add_predicate(where_clause, parse_quote!(#ty: ::style_traits::ToCss)); } quote! { writer.item(#field)?; } }; if let Some(condition) = attrs.skip_if { expr = quote! { if !#condition(#field) { #expr } } } expr } #[darling(attributes(css), default)] #[derive(Default, FromDeriveInput)] pub struct CssInputAttrs { pub derive_debug: bool, // Here because structs variants are also their whole type definition. pub function: Option>, // Here because structs variants are also their whole type definition. pub comma: bool, } #[darling(attributes(css), default)] #[derive(Default, FromVariant)] pub struct CssVariantAttrs { pub function: Option>, // Here because structs variants are also their whole type definition. pub derive_debug: bool, pub comma: bool, pub dimension: bool, pub keyword: Option, pub skip: bool, } #[darling(attributes(css), default)] #[derive(Default, FromField)] pub struct CssFieldAttrs { pub if_empty: Option, pub field_bound: bool, pub iterable: bool, pub skip: bool, pub represents_keyword: bool, pub skip_if: Option, }