From 42c8dc983f86371e9e89818a2e8d9ad8b24a9900 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 22 Jan 2018 23:37:15 +0100 Subject: [PATCH] Derive ToCss for TransformOperation Now that SequenceWriter does not monomorphise excessively, we can actually type check a derived ToCss without too much type recursion. --- components/style/values/generics/transform.rs | 146 ++++-------------- components/style_derive/to_css.rs | 40 ++++- 2 files changed, 61 insertions(+), 125 deletions(-) diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs index c74cbc8d459..7c2bb57546e 100644 --- a/components/style/values/generics/transform.rs +++ b/components/style/values/generics/transform.rs @@ -30,7 +30,8 @@ pub struct Matrix { #[allow(missing_docs)] #[cfg_attr(rustfmt, rustfmt_skip)] -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[css(comma, function = "matrix3d")] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] pub struct Matrix3D { pub m11: T, pub m12: T, pub m13: T, pub m14: T, pub m21: T, pub m22: T, pub m23: T, pub m24: T, @@ -191,7 +192,7 @@ impl TimingKeyword { } } -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] /// A single operation in the list of a `transform` value pub enum TransformOperation { /// Represents a 2D 2x3 matrix. @@ -200,31 +201,37 @@ pub enum TransformOperation), /// Represents a 3D 4x4 matrix. - #[allow(missing_docs)] Matrix3D(Matrix3D), /// Represents a 3D 4x4 matrix with percentage and length values. /// For `moz-transform`. - #[allow(missing_docs)] PrefixedMatrix3D(Matrix3D), /// A 2D skew. /// /// If the second angle is not provided it is assumed zero. /// /// Syntax can be skew(angle) or skew(angle, angle) + #[css(comma, function)] Skew(Angle, Option), /// skewX(angle) + #[css(function = "skewX")] SkewX(Angle), /// skewY(angle) + #[css(function = "skewY")] SkewY(Angle), /// translate(x, y) or translate(x) + #[css(comma, function)] Translate(LengthOrPercentage, Option), /// translateX(x) + #[css(function = "translateX")] TranslateX(LengthOrPercentage), /// translateY(y) + #[css(function = "translateY")] TranslateY(LengthOrPercentage), /// translateZ(z) + #[css(function = "translateZ")] TranslateZ(Length), /// translate3d(x, y, z) + #[css(comma, function = "translate3d")] Translate3D(LengthOrPercentage, LengthOrPercentage, Length), /// A 2D scaling factor. /// @@ -234,28 +241,38 @@ pub enum TransformOperation), /// scaleX(factor) + #[css(function = "scaleX")] ScaleX(Number), /// scaleY(factor) + #[css(function = "scaleY")] ScaleY(Number), /// scaleZ(factor) + #[css(function = "scaleZ")] ScaleZ(Number), /// scale3D(factorX, factorY, factorZ) + #[css(comma, function = "scale3d")] Scale3D(Number, Number, Number), /// Describes a 2D Rotation. /// /// In a 3D scene `rotate(angle)` is equivalent to `rotateZ(angle)`. + #[css(function)] Rotate(Angle), /// Rotation in 3D space around the x-axis. + #[css(function = "rotateX")] RotateX(Angle), /// Rotation in 3D space around the y-axis. + #[css(function = "rotateY")] RotateY(Angle), /// Rotation in 3D space around the z-axis. + #[css(function = "rotateZ")] RotateZ(Angle), /// Rotation in 3D space. /// /// Generalization of rotateX, rotateY and rotateZ. + #[css(comma, function = "rotate3d")] Rotate3D(Number, Number, Number, Angle), /// Specifies a perspective projection matrix. /// @@ -263,11 +280,14 @@ pub enum TransformOperation, >, #[compute(ignore_bound)] + #[css(ignore_bound)] to_list: Transform< TransformOperation< Angle, @@ -296,8 +317,10 @@ pub enum TransformOperation, >, #[compute(ignore_bound)] + #[css(ignore_bound)] to_list: Transform< TransformOperation< Angle, @@ -541,120 +565,6 @@ where } } -#[cfg_attr(rustfmt, rustfmt_skip)] -impl - ToCss for - TransformOperation { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - match *self { - TransformOperation::Matrix(ref m) => m.to_css(dest), - TransformOperation::PrefixedMatrix(ref m) => m.to_css(dest), - TransformOperation::Matrix3D(Matrix3D { - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44, - }) => { - serialize_function!(dest, matrix3d( - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44, - )) - } - TransformOperation::PrefixedMatrix3D(Matrix3D { - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - ref m41, ref m42, ref m43, m44, - }) => { - serialize_function!(dest, matrix3d( - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44, - )) - } - TransformOperation::Skew(ax, None) => { - serialize_function!(dest, skew(ax)) - } - TransformOperation::Skew(ax, Some(ay)) => { - serialize_function!(dest, skew(ax, ay)) - } - TransformOperation::SkewX(angle) => { - serialize_function!(dest, skewX(angle)) - } - TransformOperation::SkewY(angle) => { - serialize_function!(dest, skewY(angle)) - } - TransformOperation::Translate(ref tx, None) => { - serialize_function!(dest, translate(tx)) - } - TransformOperation::Translate(ref tx, Some(ref ty)) => { - serialize_function!(dest, translate(tx, ty)) - } - TransformOperation::TranslateX(ref tx) => { - serialize_function!(dest, translateX(tx)) - } - TransformOperation::TranslateY(ref ty) => { - serialize_function!(dest, translateY(ty)) - } - TransformOperation::TranslateZ(ref tz) => { - serialize_function!(dest, translateZ(tz)) - } - TransformOperation::Translate3D(ref tx, ref ty, ref tz) => { - serialize_function!(dest, translate3d(tx, ty, tz)) - } - TransformOperation::Scale(factor, None) => { - serialize_function!(dest, scale(factor)) - } - TransformOperation::Scale(sx, Some(sy)) => { - serialize_function!(dest, scale(sx, sy)) - } - TransformOperation::ScaleX(sx) => { - serialize_function!(dest, scaleX(sx)) - } - TransformOperation::ScaleY(sy) => { - serialize_function!(dest, scaleY(sy)) - } - TransformOperation::ScaleZ(sz) => { - serialize_function!(dest, scaleZ(sz)) - } - TransformOperation::Scale3D(sx, sy, sz) => { - serialize_function!(dest, scale3d(sx, sy, sz)) - } - TransformOperation::Rotate(theta) => { - serialize_function!(dest, rotate(theta)) - } - TransformOperation::RotateX(theta) => { - serialize_function!(dest, rotateX(theta)) - } - TransformOperation::RotateY(theta) => { - serialize_function!(dest, rotateY(theta)) - } - TransformOperation::RotateZ(theta) => { - serialize_function!(dest, rotateZ(theta)) - } - TransformOperation::Rotate3D(x, y, z, theta) => { - serialize_function!(dest, rotate3d(x, y, z, theta)) - } - TransformOperation::Perspective(ref length) => { - serialize_function!(dest, perspective(length)) - } - TransformOperation::InterpolateMatrix { ref from_list, ref to_list, progress } => { - serialize_function!(dest, interpolatematrix(from_list, to_list, progress)) - } - TransformOperation::AccumulateMatrix { ref from_list, ref to_list, count } => { - serialize_function!(dest, accumulatematrix(from_list, to_list, count)) - } - } - } -} - impl ToCss for Transform { fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index db56ca3b644..de48f4612e4 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -3,8 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cg; +use darling::{Error, FromMetaItem}; use quote::Tokens; -use syn::DeriveInput; +use syn::{self, DeriveInput, Ident}; use synstructure; pub fn derive(input: DeriveInput) -> Tokens { @@ -16,13 +17,13 @@ pub fn derive(input: DeriveInput) -> Tokens { let input_attrs = cg::parse_input_attrs::(&input); let style = synstructure::BindStyle::Ref.into(); let match_body = synstructure::each_variant(&input, &style, |bindings, variant| { - let mut identifier = cg::to_css_identifier(variant.ident.as_ref()); + let identifier = cg::to_css_identifier(variant.ident.as_ref()); let variant_attrs = cg::parse_variant_attrs::(variant); let separator = if variant_attrs.comma { ", " } else { " " }; if variant_attrs.dimension { assert_eq!(bindings.len(), 1); - assert!(!variant_attrs.function, "That makes no sense"); + assert!(variant_attrs.function.is_none(), "That makes no sense"); } let mut expr = if !bindings.is_empty() { @@ -39,7 +40,10 @@ pub fn derive(input: DeriveInput) -> Tokens { }; } else { for binding in bindings { - where_clause.add_trait_bound(&binding.field.ty); + let attrs = cg::parse_field_attrs::(&binding.field); + if !attrs.ignore_bound { + where_clause.add_trait_bound(&binding.field.ty); + } expr = quote! { #expr writer.item(#binding)?; @@ -63,7 +67,8 @@ pub fn derive(input: DeriveInput) -> Tokens { #expr?; ::std::fmt::Write::write_str(dest, #identifier) } - } else if variant_attrs.function { + } else if let Some(function) = variant_attrs.function { + let mut identifier = function.name.map_or(identifier, |name| name.to_string()); identifier.push_str("("); expr = quote! { ::std::fmt::Write::write_str(dest, #identifier)?; @@ -112,15 +117,36 @@ pub fn derive(input: DeriveInput) -> Tokens { #[derive(Default, FromDeriveInput)] struct CssInputAttrs { derive_debug: bool, - function: bool, + function: Option, comma: bool, } #[darling(attributes(css), default)] #[derive(Default, FromVariant)] struct CssVariantAttrs { - function: bool, + function: Option, iterable: bool, comma: bool, dimension: bool, } + +#[darling(attributes(css), default)] +#[derive(Default, FromField)] +struct CssFieldAttrs { + ignore_bound: bool, +} + +struct Function { + name: Option, +} + +impl FromMetaItem for Function { + fn from_word() -> Result { + Ok(Self { name: None }) + } + + fn from_string(name: &str) -> Result { + let name = syn::parse_ident(name).map_err(Error::custom)?; + Ok(Self { name: Some(name) }) + } +}