Bug 1532134 - Implement a version of #[css(skip_if)] that takes more context. r=xidorn
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sun, 03 Mar 2019 11:31:06 +0000
changeset 520054 b5dec9e96f42cd166b4cdaf70b6765be34454aae
parent 520053 a920a704ff6bf2811f717be3c437239b6257046b
child 520055 7aa72a6aa1b501c6f7a0efc7a4a4ea14d15f0030
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersxidorn
bugs1532134
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1532134 - Implement a version of #[css(skip_if)] that takes more context. r=xidorn I called it contextual_skip_if, though better names welcome. Differential Revision: https://phabricator.services.mozilla.com/D21858
servo/components/style_derive/to_css.rs
servo/components/style_traits/values.rs
--- a/servo/components/style_derive/to_css.rs
+++ b/servo/components/style_derive/to_css.rs
@@ -143,35 +143,44 @@ fn derive_variant_fields_expr(
         let mut expr = quote! { style_traits::ToCss::to_css(#first, dest) };
         if let Some(condition) = attrs.skip_if {
             expr = quote! {
                 if !#condition(#first) {
                     #expr
                 }
             }
         }
+
+        if let Some(condition) = attrs.contextual_skip_if {
+            expr = quote! {
+                if !#condition(#(#bindings),*) {
+                    #expr
+                }
+            }
+        }
         return expr;
     }
 
-    let mut expr = derive_single_field_expr(first, attrs, where_clause);
+    let mut expr = derive_single_field_expr(first, attrs, where_clause, bindings);
     for (binding, attrs) in iter {
-        derive_single_field_expr(binding, attrs, where_clause).to_tokens(&mut expr)
+        derive_single_field_expr(binding, attrs, where_clause, bindings).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<WhereClause>,
+    bindings: &[BindingInfo],
 ) -> TokenStream {
     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)?;
@@ -211,16 +220,24 @@ fn derive_single_field_expr(
     if let Some(condition) = attrs.skip_if {
         expr = quote! {
             if !#condition(#field) {
                 #expr
             }
         }
     }
 
+    if let Some(condition) = attrs.contextual_skip_if {
+        expr = quote! {
+            if !#condition(#(#bindings),*) {
+                #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.
@@ -244,10 +261,11 @@ pub struct CssVariantAttrs {
 #[darling(attributes(css), default)]
 #[derive(Default, FromField)]
 pub struct CssFieldAttrs {
     pub if_empty: Option<String>,
     pub field_bound: bool,
     pub iterable: bool,
     pub skip: bool,
     pub represents_keyword: bool,
+    pub contextual_skip_if: Option<Path>,
     pub skip_if: Option<Path>,
 }
--- a/servo/components/style_traits/values.rs
+++ b/servo/components/style_traits/values.rs
@@ -32,16 +32,20 @@ use std::fmt::{self, Write};
 /// * if `#[css(dimension)]` is found on a variant, that variant needs
 ///   to have a single member. The variant would be serialized as a CSS
 ///   dimension token, like: <member><identifier>;
 /// * if `#[css(skip)]` is found on a field, the `ToCss` call for that field
 ///   is skipped;
 /// * if `#[css(skip_if = "function")]` is found on a field, the `ToCss` call
 ///   for that field is skipped if `function` returns true. This function is
 ///   provided the field as an argument;
+/// * if `#[css(contextual_skip_if = "function")]` is found on a field, the
+///   `ToCss` call for that field is skipped if `function` returns true. This
+///   function is given all the fields in the current struct or variant as an
+///   argument;
 /// * `#[css(represents_keyword)]` can be used on bool fields in order to
 ///   serialize the field name if the field is true, or nothing otherwise.  It
 ///   also collects those keywords for `SpecifiedValueInfo`.
 /// * finally, one can put `#[css(derive_debug)]` on the whole type, to
 ///   implement `Debug` by a single call to `ToCss::to_css`.
 pub trait ToCss {
     /// Serialize `self` in CSS syntax, writing to `dest`.
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result