Auto merge of #17291 - servo:derive-all-the-things, r=<try>

Function support for #[derive(ToCss)] and an Animatable fix
This commit is contained in:
bors-servo 2017-06-13 01:24:53 -07:00 committed by GitHub
commit 44eb8c8e4f
10 changed files with 100 additions and 80 deletions

View file

@ -401,7 +401,7 @@ impl CounterStyleOrNone {
use gecko_bindings::bindings::Gecko_SetCounterStyleToName as set_name; use gecko_bindings::bindings::Gecko_SetCounterStyleToName as set_name;
use gecko_bindings::bindings::Gecko_SetCounterStyleToSymbols as set_symbols; use gecko_bindings::bindings::Gecko_SetCounterStyleToSymbols as set_symbols;
match self { match self {
CounterStyleOrNone::None_ => unsafe { CounterStyleOrNone::None => unsafe {
set_name(gecko_value, atom!("none").into_addrefed()); set_name(gecko_value, atom!("none").into_addrefed());
}, },
CounterStyleOrNone::Name(name) => unsafe { CounterStyleOrNone::Name(name) => unsafe {

View file

@ -1246,7 +1246,14 @@ impl Animatable for LengthOrPercentageOrNone {
(LengthOrPercentageOrNone::None, LengthOrPercentageOrNone::None) => { (LengthOrPercentageOrNone::None, LengthOrPercentageOrNone::None) => {
Ok(LengthOrPercentageOrNone::None) Ok(LengthOrPercentageOrNone::None)
} }
_ => Err(()) (this, other) => {
let this = <Option<CalcLengthOrPercentage>>::from(this);
let other = <Option<CalcLengthOrPercentage>>::from(other);
match this.add_weighted(&other, self_portion, other_portion) {
Ok(Some(result)) => Ok(LengthOrPercentageOrNone::Calc(result)),
_ => Err(()),
}
},
} }
} }
@ -1273,7 +1280,12 @@ impl Animatable for LengthOrPercentageOrNone {
LengthOrPercentageOrNone::Percentage(ref other)) => { LengthOrPercentageOrNone::Percentage(ref other)) => {
this.compute_distance(other) this.compute_distance(other)
}, },
_ => Err(()) (this, other) => {
// If one of the element is Auto, Option<> will be None, and the returned distance is Err(())
let this = <Option<CalcLengthOrPercentage>>::from(this);
let other = <Option<CalcLengthOrPercentage>>::from(other);
this.compute_distance(&other)
},
} }
} }
} }

View file

@ -63,7 +63,7 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu
pub fn from_gecko_keyword(value: u32) -> Self { pub fn from_gecko_keyword(value: u32) -> Self {
use gecko_bindings::structs; use gecko_bindings::structs;
SpecifiedValue::CounterStyle(if value == structs::NS_STYLE_LIST_STYLE_NONE { SpecifiedValue::CounterStyle(if value == structs::NS_STYLE_LIST_STYLE_NONE {
CounterStyleOrNone::None_ CounterStyleOrNone::None
} else { } else {
<% <%
values = """disc circle square decimal lower-roman values = """disc circle square decimal lower-roman

View file

@ -62,7 +62,7 @@
list_style_type::SpecifiedValue::none list_style_type::SpecifiedValue::none
% else: % else:
use values::generics::CounterStyleOrNone; use values::generics::CounterStyleOrNone;
list_style_type::SpecifiedValue::CounterStyle(CounterStyleOrNone::None_) list_style_type::SpecifiedValue::CounterStyle(CounterStyleOrNone::None)
% endif % endif
} }

View file

@ -157,6 +157,25 @@ impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
} }
} }
impl From<LengthOrPercentageOrNone> for Option<CalcLengthOrPercentage> {
fn from(len: LengthOrPercentageOrNone) -> Option<CalcLengthOrPercentage> {
match len {
LengthOrPercentageOrNone::Percentage(this) => {
Some(CalcLengthOrPercentage::new(Au(0), Some(this)))
}
LengthOrPercentageOrNone::Length(this) => {
Some(CalcLengthOrPercentage::new(this, None))
}
LengthOrPercentageOrNone::Calc(this) => {
Some(this)
}
LengthOrPercentageOrNone::None => {
None
}
}
}
}
impl ToCss for CalcLengthOrPercentage { impl ToCss for CalcLengthOrPercentage {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match (self.length, self.percentage) { match (self.length, self.percentage) {

View file

@ -92,7 +92,7 @@ pub struct Ellipse<H, V, LengthOrPercentage> {
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius /// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue)] #[derive(Clone, Copy, Debug, PartialEq, ToComputedValue, ToCss)]
pub enum ShapeRadius<LengthOrPercentage> { pub enum ShapeRadius<LengthOrPercentage> {
Length(LengthOrPercentage), Length(LengthOrPercentage),
ClosestSide, ClosestSide,
@ -161,17 +161,6 @@ impl<L> Default for ShapeRadius<L> {
fn default() -> Self { ShapeRadius::ClosestSide } fn default() -> Self { ShapeRadius::ClosestSide }
} }
impl<L: ToCss> ToCss for ShapeRadius<L> {
#[inline]
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
ShapeRadius::Length(ref lop) => lop.to_css(dest),
ShapeRadius::ClosestSide => dest.write_str("closest-side"),
ShapeRadius::FarthestSide => dest.write_str("farthest-side"),
}
}
}
impl<L: ToCss> ToCss for Polygon<L> { impl<L: ToCss> ToCss for Polygon<L> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
dest.write_str("polygon(")?; dest.write_str("polygon(")?;

View file

@ -5,15 +5,13 @@
//! Generic types for legacy Gecko-only properties that should probably be //! Generic types for legacy Gecko-only properties that should probably be
//! unshipped at some point in the future. //! unshipped at some point in the future.
use std::fmt;
use style_traits::ToCss;
/// A generic value for scroll snap points. /// A generic value for scroll snap points.
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] #[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
pub enum ScrollSnapPoint<LengthOrPercentage> { pub enum ScrollSnapPoint<LengthOrPercentage> {
/// `none` /// `none`
None, None,
/// `repeat(<length-or-percentage>)` /// `repeat(<length-or-percentage>)`
#[css(function)]
Repeat(LengthOrPercentage) Repeat(LengthOrPercentage)
} }
@ -33,22 +31,3 @@ impl<L> ScrollSnapPoint<L> {
} }
} }
} }
impl<L> ToCss for ScrollSnapPoint<L>
where
L: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
match *self {
ScrollSnapPoint::None => dest.write_str("none"),
ScrollSnapPoint::Repeat(ref length) => {
dest.write_str("repeat(")?;
length.to_css(dest)?;
dest.write_str(")")
},
}
}
}

View file

@ -54,13 +54,14 @@ impl SymbolsType {
/// ///
/// Since wherever <counter-style> is used, 'none' is a valid value as /// Since wherever <counter-style> is used, 'none' is a valid value as
/// well, we combine them into one type to make code simpler. /// well, we combine them into one type to make code simpler.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, Eq, PartialEq, ToCss)]
pub enum CounterStyleOrNone { pub enum CounterStyleOrNone {
/// none /// `none`
None_, None,
/// <counter-style-name> /// `<counter-style-name>`
Name(CustomIdent), Name(CustomIdent),
/// symbols() /// `symbols()`
#[css(function)]
Symbols(SymbolsType, Symbols), Symbols(SymbolsType, Symbols),
} }
@ -84,7 +85,7 @@ impl Parse for CounterStyleOrNone {
return Ok(CounterStyleOrNone::Name(name)); return Ok(CounterStyleOrNone::Name(name));
} }
if input.try(|i| i.expect_ident_matching("none")).is_ok() { if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(CounterStyleOrNone::None_); return Ok(CounterStyleOrNone::None);
} }
if input.try(|i| i.expect_function_matching("symbols")).is_ok() { if input.try(|i| i.expect_function_matching("symbols")).is_ok() {
return input.parse_nested_block(|input| { return input.parse_nested_block(|input| {
@ -108,23 +109,6 @@ impl Parse for CounterStyleOrNone {
} }
} }
impl ToCss for CounterStyleOrNone {
#[inline]
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self {
&CounterStyleOrNone::None_ => dest.write_str("none"),
&CounterStyleOrNone::Name(ref name) => name.to_css(dest),
&CounterStyleOrNone::Symbols(ref symbols_type, ref symbols) => {
dest.write_str("symbols(")?;
symbols_type.to_css(dest)?;
dest.write_str(" ")?;
symbols.to_css(dest)?;
dest.write_str(")")
}
}
}
}
/// A settings tag, defined by a four-character tag and a setting value /// A settings tag, defined by a four-character tag and a setting value
/// ///
/// For font-feature-settings, this is a tag and an integer, /// For font-feature-settings, this is a tag and an integer,

View file

@ -25,7 +25,7 @@ pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream {
to_computed_value::derive(input).to_string().parse().unwrap() to_computed_value::derive(input).to_string().parse().unwrap()
} }
#[proc_macro_derive(ToCss)] #[proc_macro_derive(ToCss, attributes(css))]
pub fn derive_to_css(stream: TokenStream) -> TokenStream { pub fn derive_to_css(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap(); let input = syn::parse_derive_input(&stream.to_string()).unwrap();
to_css::derive(input).to_string().parse().unwrap() to_css::derive(input).to_string().parse().unwrap()

View file

@ -16,24 +16,61 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let style = synstructure::BindStyle::Ref.into(); let style = synstructure::BindStyle::Ref.into();
let match_body = synstructure::each_variant(&input, &style, |bindings, variant| { let match_body = synstructure::each_variant(&input, &style, |bindings, variant| {
if bindings.is_empty() { let mut identifier = to_css_identifier(variant.ident.as_ref());
let identifier = to_css_identifier(variant.ident.as_ref()); let mut expr = if bindings.is_empty() {
return Some(quote! { quote! {
::std::fmt::Write::write_str(dest, #identifier) ::std::fmt::Write::write_str(dest, #identifier)
}); }
} } else {
let (first, rest) = bindings.split_first().expect("unit variants are not yet supported"); let (first, rest) = bindings.split_first().expect("unit variants are not yet supported");
where_clause.predicates.push(where_predicate(first.field.ty.clone())); where_clause.predicates.push(where_predicate(first.field.ty.clone()));
let mut expr = quote! { let mut expr = quote! {
::style_traits::ToCss::to_css(#first, dest) ::style_traits::ToCss::to_css(#first, dest)
};
for binding in rest {
where_clause.predicates.push(where_predicate(binding.field.ty.clone()));
expr = quote! {
#expr?;
::std::fmt::Write::write_str(dest, " ")?;
::style_traits::ToCss::to_css(#binding, dest)
}; };
for binding in rest {
where_clause.predicates.push(where_predicate(binding.field.ty.clone()));
expr = quote! {
#expr?;
::std::fmt::Write::write_str(dest, " ")?;
::style_traits::ToCss::to_css(#binding, dest)
};
}
expr
};
let mut css_attrs = variant.attrs.iter().filter(|attr| attr.name() == "css");
let is_function = css_attrs.next().map_or(false, |attr| {
match attr.value {
syn::MetaItem::List(ref ident, ref items) if ident.as_ref() == "css" => {
let mut nested = items.iter();
let is_function = nested.next().map_or(false, |attr| {
match *attr {
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(ref ident)) => {
if ident.as_ref() != "function" {
panic!("only `#[css(function)]` is supported for now")
}
true
},
_ => panic!("only `#[css(<ident>)]` is supported for now"),
}
});
if nested.next().is_some() {
panic!("only `#[css()]` or `#[css(<ident>)]` is supported for now")
}
is_function
},
_ => panic!("only `#[css(...)]` is supported for now"),
}
});
if css_attrs.next().is_some() {
panic!("only a single `#[css(...)]` attribute is supported for now");
}
if is_function {
identifier.push_str("(");
expr = quote! {
::std::fmt::Write::write_str(dest, #identifier)?;
#expr?;
::std::fmt::Write::write_str(dest, ")")
}
} }
Some(expr) Some(expr)
}); });