mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Simplify machinery to serialise optional parts of CSS values
We simply implement ToCss for Option<T>, printing nothing if the value is None, and we then use SequenceWriter to skip writing of separators around empty parts.
This commit is contained in:
parent
cedd5222d2
commit
39e29f557e
8 changed files with 152 additions and 131 deletions
|
@ -6,7 +6,7 @@
|
|||
|
||||
use app_units::Au;
|
||||
use cssparser::{UnicodeRange, serialize_string};
|
||||
use std::fmt;
|
||||
use std::fmt::{self, Write};
|
||||
|
||||
/// Serialises a value according to its CSS representation.
|
||||
///
|
||||
|
@ -22,7 +22,7 @@ use std::fmt;
|
|||
/// of their fields.
|
||||
pub trait ToCss {
|
||||
/// Serialize `self` in CSS syntax, writing to `dest`.
|
||||
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: Write;
|
||||
|
||||
/// Serialize `self` in CSS syntax and return a string.
|
||||
///
|
||||
|
@ -36,25 +36,151 @@ pub trait ToCss {
|
|||
}
|
||||
|
||||
impl<'a, T> ToCss for &'a T where T: ToCss + ?Sized {
|
||||
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: Write {
|
||||
(*self).to_css(dest)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for str {
|
||||
#[inline]
|
||||
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: Write {
|
||||
serialize_string(self, dest)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for String {
|
||||
#[inline]
|
||||
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: Write {
|
||||
serialize_string(self, dest)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToCss for Option<T>
|
||||
where
|
||||
T: ToCss,
|
||||
{
|
||||
#[inline]
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: Write {
|
||||
self.as_ref().map_or(Ok(()), |value| value.to_css(dest))
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience wrapper to serialise CSS values separated by a given string.
|
||||
pub struct SequenceWriter<'a, W> {
|
||||
writer: TrackedWriter<W>,
|
||||
separator: &'a str,
|
||||
}
|
||||
|
||||
impl<'a, W> SequenceWriter<'a, W>
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
/// Create a new sequence writer.
|
||||
#[inline]
|
||||
pub fn new(writer: W, separator: &'a str) -> Self {
|
||||
SequenceWriter {
|
||||
writer: TrackedWriter::new(writer),
|
||||
separator: separator,
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialises a CSS value, writing any separator as necessary.
|
||||
///
|
||||
/// The separator is never written before any `item` produces any output,
|
||||
/// and is written in subsequent calls only if the `item` produces some
|
||||
/// output on its own again. This lets us handle `Option<T>` fields by
|
||||
/// just not printing anything on `None`.
|
||||
#[inline]
|
||||
pub fn item<T>(&mut self, item: &T) -> fmt::Result
|
||||
where
|
||||
T: ToCss,
|
||||
{
|
||||
if self.writer.has_written {
|
||||
item.to_css(&mut PrefixedWriter::new(&mut self.writer, self.separator))
|
||||
} else {
|
||||
item.to_css(&mut self.writer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TrackedWriter<W> {
|
||||
writer: W,
|
||||
has_written: bool,
|
||||
}
|
||||
|
||||
impl<W> TrackedWriter<W>
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
#[inline]
|
||||
fn new(writer: W) -> Self {
|
||||
TrackedWriter {
|
||||
writer: writer,
|
||||
has_written: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> Write for TrackedWriter<W>
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
if !s.is_empty() {
|
||||
self.has_written = true;
|
||||
}
|
||||
self.writer.write_str(s)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_char(&mut self, c: char) -> fmt::Result {
|
||||
self.has_written = true;
|
||||
self.writer.write_char(c)
|
||||
}
|
||||
}
|
||||
|
||||
struct PrefixedWriter<'a, W> {
|
||||
writer: W,
|
||||
prefix: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a, W> PrefixedWriter<'a, W>
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
#[inline]
|
||||
fn new(writer: W, prefix: &'a str) -> Self {
|
||||
PrefixedWriter {
|
||||
writer: writer,
|
||||
prefix: Some(prefix),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, W> Write for PrefixedWriter<'a, W>
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
if !s.is_empty() {
|
||||
if let Some(prefix) = self.prefix.take() {
|
||||
self.writer.write_str(prefix)?;
|
||||
}
|
||||
}
|
||||
self.writer.write_str(s)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_char(&mut self, c: char) -> fmt::Result {
|
||||
if let Some(prefix) = self.prefix.take() {
|
||||
self.writer.write_str(prefix)?;
|
||||
}
|
||||
self.writer.write_char(c)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// separated by commas.
|
||||
|
@ -103,7 +229,7 @@ impl OneOrMoreSeparated for UnicodeRange {
|
|||
}
|
||||
|
||||
impl<T> ToCss for Vec<T> where T: ToCss + OneOrMoreSeparated {
|
||||
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: Write {
|
||||
let mut iter = self.iter();
|
||||
iter.next().unwrap().to_css(dest)?;
|
||||
for item in iter {
|
||||
|
@ -116,14 +242,14 @@ impl<T> ToCss for Vec<T> where T: ToCss + OneOrMoreSeparated {
|
|||
|
||||
impl<T> ToCss for Box<T> where T: ?Sized + ToCss {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||
where W: fmt::Write,
|
||||
where W: Write,
|
||||
{
|
||||
(**self).to_css(dest)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for Au {
|
||||
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: Write {
|
||||
write!(dest, "{}px", self.to_f64_px())
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +257,7 @@ impl ToCss for Au {
|
|||
macro_rules! impl_to_css_for_predefined_type {
|
||||
($name: ty) => {
|
||||
impl<'a> ToCss for $name {
|
||||
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: Write {
|
||||
::cssparser::ToCss::to_css(self, dest)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue