Introduce #[css(if_empty = "…", iterable)]

This commit is contained in:
Anthony Ramine 2018-03-07 13:07:13 +01:00
parent 92f116a95c
commit 90b23963b7
4 changed files with 48 additions and 80 deletions

View file

@ -83,10 +83,6 @@
need_animatable=need_animatable, **kwargs)"> need_animatable=need_animatable, **kwargs)">
#[allow(unused_imports)] #[allow(unused_imports)]
use smallvec::SmallVec; use smallvec::SmallVec;
% if allow_empty:
use std::fmt::{self, Write};
use style_traits::{CssWriter, Separator, ToCss};
% endif
pub mod single_value { pub mod single_value {
#[allow(unused_imports)] #[allow(unused_imports)]
@ -120,23 +116,22 @@
use values::computed::ComputedVecIter; use values::computed::ComputedVecIter;
/// The computed value, effectively a list of single values. /// The computed value, effectively a list of single values.
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
% if need_animatable or animation_value_type == "ComputedValue":
#[derive(Animate, ComputeSquaredDistance)]
% endif
% if not allow_empty:
% if separator == "Comma": % if separator == "Comma":
#[css(comma)] #[css(comma)]
% endif % endif
#[derive(ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
% if need_animatable or animation_value_type == "ComputedValue":
#[derive(Animate, ComputeSquaredDistance)]
% endif % endif
pub struct T( pub struct T(
% if not allow_empty:
#[css(iterable)]
% else:
#[css(if_empty = "none", iterable)]
% endif
% if allow_empty and allow_empty != "NotInitial": % if allow_empty and allow_empty != "NotInitial":
pub Vec<single_value::T>, pub Vec<single_value::T>,
% else: % else:
% if not allow_empty:
#[css(iterable)]
% endif
pub SmallVec<[single_value::T; 1]>, pub SmallVec<[single_value::T; 1]>,
% endif % endif
); );
@ -165,63 +160,20 @@
} }
} }
% if allow_empty:
impl ToCss for computed_value::T {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
let mut iter = self.0.iter();
if let Some(val) = iter.next() {
val.to_css(dest)?;
} else {
return dest.write_str("none");
}
for i in iter {
dest.write_str(::style_traits::${separator}::separator())?;
i.to_css(dest)?;
}
Ok(())
}
}
% endif
/// The specified value of ${name}. /// The specified value of ${name}.
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
% if not allow_empty:
% if separator == "Comma": % if separator == "Comma":
#[css(comma)] #[css(comma)]
% endif % endif
#[derive(ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
% endif
pub struct SpecifiedValue( pub struct SpecifiedValue(
% if not allow_empty: % if not allow_empty:
#[css(iterable)] #[css(iterable)]
% else:
#[css(if_empty = "none", iterable)]
% endif % endif
pub Vec<single_value::SpecifiedValue>, pub Vec<single_value::SpecifiedValue>,
); );
% if allow_empty:
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
let mut iter = self.0.iter();
if let Some(val) = iter.next() {
val.to_css(dest)?;
} else {
return dest.write_str("none");
}
for i in iter {
dest.write_str(::style_traits::${separator}::separator())?;
i.to_css(dest)?;
}
Ok(())
}
}
% endif
pub fn get_initial_value() -> computed_value::T { pub fn get_initial_value() -> computed_value::T {
% if allow_empty and allow_empty != "NotInitial": % if allow_empty and allow_empty != "NotInitial":
computed_value::T(vec![]) computed_value::T(vec![])

View file

@ -736,9 +736,12 @@ pub enum VariantAlternates {
HistoricalForms, HistoricalForms,
} }
#[derive(Clone, Debug, MallocSizeOf, PartialEq)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
/// List of Variant Alternates /// List of Variant Alternates
pub struct VariantAlternatesList(pub Box<[VariantAlternates]>); pub struct VariantAlternatesList(
#[css(if_empty = "normal", iterable)]
pub Box<[VariantAlternates]>,
);
impl VariantAlternatesList { impl VariantAlternatesList {
/// Returns the length of all variant alternates. /// Returns the length of all variant alternates.
@ -759,25 +762,6 @@ impl VariantAlternatesList {
} }
} }
impl ToCss for VariantAlternatesList {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.0.is_empty() {
return dest.write_str("normal");
}
let mut iter = self.0.iter();
iter.next().unwrap().to_css(dest)?;
for alternate in iter {
dest.write_str(" ")?;
alternate.to_css(dest)?;
}
Ok(())
}
}
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
/// Control over the selection of these alternate glyphs /// Control over the selection of these alternate glyphs
pub enum FontVariantAlternates { pub enum FontVariantAlternates {

View file

@ -150,6 +150,20 @@ fn derive_single_field_expr(
where_clause: &mut WhereClause, where_clause: &mut WhereClause,
) -> Tokens { ) -> Tokens {
if attrs.iterable { 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.item(&::style_traits::values::Verbatim(#if_empty))?;
} else {
for item in iter {
writer.item(&item)?;
}
}
}
};
}
quote! { quote! {
for item in #field.iter() { for item in #field.iter() {
writer.item(&item)?; writer.item(&item)?;
@ -186,6 +200,7 @@ pub struct CssVariantAttrs {
#[darling(attributes(css), default)] #[darling(attributes(css), default)]
#[derive(Default, FromField)] #[derive(Default, FromField)]
struct CssFieldAttrs { struct CssFieldAttrs {
if_empty: Option<String>,
ignore_bound: bool, ignore_bound: bool,
iterable: bool, iterable: bool,
skip: bool, skip: bool,

View file

@ -27,6 +27,8 @@ use std::fmt::{self, Write};
/// * if `#[css(iterable)]` is found on a function variant, that variant needs /// * if `#[css(iterable)]` is found on a function variant, that variant needs
/// to have a single member, and that member needs to be iterable. The /// to have a single member, and that member needs to be iterable. The
/// iterable will be serialized as the arguments for the function; /// iterable will be serialized as the arguments for the function;
/// * an iterable field can also be annotated with `#[css(if_empty = "foo")]`
/// to print `"foo"` if the iterator is empty;
/// * if `#[css(dimension)]` is found on a variant, that variant needs /// * if `#[css(dimension)]` is found on a variant, that variant needs
/// to have a single member. The variant would be serialized as a CSS /// to have a single member. The variant would be serialized as a CSS
/// dimension token, like: <member><identifier>; /// dimension token, like: <member><identifier>;
@ -210,6 +212,21 @@ where
} }
} }
/// A wrapper type that implements `ToCss` by printing its inner field.
pub struct Verbatim<'a, T>(pub &'a T)
where
T: ?Sized + 'a;
impl<'a, T> ToCss for Verbatim<'a, T>
where
T: AsRef<str> + ?Sized + 'a,
{
#[inline]
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write {
dest.write_str(self.0.as_ref())
}
}
/// Type used as the associated type in the `OneOrMoreSeparated` trait on a /// Type used as the associated type in the `OneOrMoreSeparated` trait on a
/// type to indicate that a serialized list of elements of this type is /// type to indicate that a serialized list of elements of this type is
/// separated by commas. /// separated by commas.