Skip to content

Commit 03950f1

Browse files
committed
Replace usage of the TextWriter trait with std::fmt::Write.
1 parent e7cd128 commit 03950f1

File tree

4 files changed

+92
-101
lines changed

4 files changed

+92
-101
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,4 @@ tempdir = "0.3"
1919

2020
[dependencies]
2121
encoding = "0.2"
22-
text_writer = "0.1.1"
2322
matches = "0.1"

src/color.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55
use std::ascii::AsciiExt;
66
use std::fmt;
77

8-
use text_writer::{self, TextWriter};
9-
108
use super::{Token, Parser, ToCss};
119

1210

1311
/// A color with red, green, blue, and alpha components.
14-
#[derive(Clone, Copy, PartialEq)]
12+
#[derive(Clone, Copy, PartialEq, Debug)]
1513
pub struct RGBA {
1614
/// The red channel. Nominally in 0.0 ... 1.0.
1715
pub red: f32,
@@ -24,7 +22,7 @@ pub struct RGBA {
2422
}
2523

2624
impl ToCss for RGBA {
27-
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
25+
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
2826
if self.alpha == 1f32 {
2927
write!(dest, "rgb({}, {}, {})",
3028
(self.red * 255.).round(),
@@ -41,7 +39,7 @@ impl ToCss for RGBA {
4139
}
4240

4341
/// A <color> value.
44-
#[derive(Clone, Copy, PartialEq)]
42+
#[derive(Clone, Copy, PartialEq, Debug)]
4543
pub enum Color {
4644
/// The 'currentColor' keyword
4745
CurrentColor,
@@ -50,22 +48,14 @@ pub enum Color {
5048
}
5149

5250
impl ToCss for Color {
53-
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
51+
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
5452
match self {
5553
&Color::CurrentColor => dest.write_str("currentColor"),
5654
&Color::RGBA(rgba) => rgba.to_css(dest),
5755
}
5856
}
5957
}
6058

61-
impl fmt::Debug for RGBA {
62-
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
63-
}
64-
65-
impl fmt::Debug for Color {
66-
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
67-
}
68-
6959
impl Color {
7060
/// Parse a <color> value, per CSS Color Module Level 3.
7161
///

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
6464
*/
6565

6666
extern crate encoding;
67-
extern crate text_writer;
6867
#[macro_use] extern crate matches;
6968
#[cfg(test)] extern crate tempdir;
7069
#[cfg(test)] extern crate rustc_serialize;

src/serializer.rs

Lines changed: 88 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
use std::fmt;
5+
use std::ascii::AsciiExt;
66
use std::cmp;
7-
8-
use text_writer::{self, TextWriter};
7+
use std::fmt::{self, Write};
98

109
use super::{Token, NumericValue, PercentageValue};
1110

1211

1312
/// Trait for things the can serialize themselves in CSS syntax.
1413
pub trait ToCss {
1514
/// Serialize `self` in CSS syntax, writing to `dest`.
16-
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter;
15+
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write;
1716

1817
/// Serialize `self` in CSS syntax and return a string.
1918
///
@@ -38,15 +37,14 @@ pub trait ToCss {
3837
///
3938
/// (This is a convenience wrapper for `to_css` and probably should not be overridden.)
4039
#[inline]
41-
fn fmt_to_css<W>(&self, dest: &mut W) -> fmt::Result where W: TextWriter {
40+
fn fmt_to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
4241
self.to_css(dest).map_err(|_| fmt::Error)
4342
}
4443
}
4544

4645

4746
#[inline]
48-
fn write_numeric<W>(value: NumericValue, dest: &mut W) -> text_writer::Result
49-
where W: TextWriter {
47+
fn write_numeric<W>(value: NumericValue, dest: &mut W) -> fmt::Result where W: fmt::Write {
5048
// `value.value >= 0` is true for negative 0.
5149
if value.has_sign && value.value.is_sign_positive() {
5250
try!(dest.write_str("+"));
@@ -67,30 +65,28 @@ where W: TextWriter {
6765

6866

6967
impl<'a> ToCss for Token<'a> {
70-
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
68+
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
7169
match *self {
7270
Token::Ident(ref value) => try!(serialize_identifier(&**value, dest)),
7371
Token::AtKeyword(ref value) => {
74-
try!(dest.write_char('@'));
72+
try!(dest.write_str("@"));
7573
try!(serialize_identifier(&**value, dest));
7674
},
7775
Token::Hash(ref value) => {
78-
try!(dest.write_char('#'));
79-
for c in value.chars() {
80-
try!(serialize_char(c, dest, /* is_identifier_start = */ false));
81-
}
76+
try!(dest.write_str("#"));
77+
try!(serialize_name(value, dest));
8278
},
8379
Token::IDHash(ref value) => {
84-
try!(dest.write_char('#'));
80+
try!(dest.write_str("#"));
8581
try!(serialize_identifier(&**value, dest));
8682
}
8783
Token::QuotedString(ref value) => try!(serialize_string(&**value, dest)),
8884
Token::Url(ref value) => {
8985
try!(dest.write_str("url("));
9086
try!(serialize_string(&**value, dest));
91-
try!(dest.write_char(')'));
87+
try!(dest.write_str(")"));
9288
},
93-
Token::Delim(value) => try!(dest.write_char(value)),
89+
Token::Delim(value) => try!(write!(dest, "{}", value)),
9490

9591
Token::Number(value) => try!(write_numeric(value, dest)),
9692
Token::Percentage(PercentageValue { unit_value, int_value, has_sign }) => {
@@ -100,17 +96,15 @@ impl<'a> ToCss for Token<'a> {
10096
has_sign: has_sign,
10197
};
10298
try!(write_numeric(value, dest));
103-
try!(dest.write_char('%'));
99+
try!(dest.write_str("%"));
104100
},
105101
Token::Dimension(value, ref unit) => {
106102
try!(write_numeric(value, dest));
107103
// Disambiguate with scientific notation.
108104
let unit = &**unit;
109105
if unit == "e" || unit == "E" || unit.starts_with("e-") || unit.starts_with("E-") {
110106
try!(dest.write_str("\\65 "));
111-
for c in unit[1..].chars() {
112-
try!(serialize_char(c, dest, /* is_identifier_start = */ false));
113-
}
107+
try!(serialize_name(&unit[1..], dest));
114108
} else {
115109
try!(serialize_identifier(unit, dest));
116110
}
@@ -140,9 +134,9 @@ impl<'a> ToCss for Token<'a> {
140134

141135
Token::WhiteSpace(content) => try!(dest.write_str(content)),
142136
Token::Comment(content) => try!(write!(dest, "/*{}*/", content)),
143-
Token::Colon => try!(dest.write_char(':')),
144-
Token::Semicolon => try!(dest.write_char(';')),
145-
Token::Comma => try!(dest.write_char(',')),
137+
Token::Colon => try!(dest.write_str(":")),
138+
Token::Semicolon => try!(dest.write_str(";")),
139+
Token::Comma => try!(dest.write_str(",")),
146140
Token::IncludeMatch => try!(dest.write_str("~=")),
147141
Token::DashMatch => try!(dest.write_str("|=")),
148142
Token::PrefixMatch => try!(dest.write_str("^=")),
@@ -154,123 +148,132 @@ impl<'a> ToCss for Token<'a> {
154148

155149
Token::Function(ref name) => {
156150
try!(serialize_identifier(&**name, dest));
157-
try!(dest.write_char('('));
151+
try!(dest.write_str("("));
158152
},
159-
Token::ParenthesisBlock => try!(dest.write_char('(')),
160-
Token::SquareBracketBlock => try!(dest.write_char('[')),
161-
Token::CurlyBracketBlock => try!(dest.write_char('{')),
153+
Token::ParenthesisBlock => try!(dest.write_str("(")),
154+
Token::SquareBracketBlock => try!(dest.write_str("[")),
155+
Token::CurlyBracketBlock => try!(dest.write_str("{")),
162156

163157
Token::BadUrl => try!(dest.write_str("url(<bad url>)")),
164158
Token::BadString => try!(dest.write_str("\"<bad string>\n")),
165-
Token::CloseParenthesis => try!(dest.write_char(')')),
166-
Token::CloseSquareBracket => try!(dest.write_char(']')),
167-
Token::CloseCurlyBracket => try!(dest.write_char('}')),
159+
Token::CloseParenthesis => try!(dest.write_str(")")),
160+
Token::CloseSquareBracket => try!(dest.write_str("]")),
161+
Token::CloseCurlyBracket => try!(dest.write_str("}")),
168162
}
169163
Ok(())
170164
}
171165
}
172166

173167

174168
/// Write a CSS identifier, escaping characters as necessary.
175-
pub fn serialize_identifier<W>(value: &str, dest: &mut W) -> text_writer::Result
176-
where W:TextWriter {
177-
// TODO: avoid decoding/re-encoding UTF-8?
178-
let mut iter = value.chars();
179-
let mut c = iter.next().unwrap();
180-
if c == '-' {
181-
c = match iter.next() {
182-
None => return dest.write_str("\\-"),
183-
Some(c) => { try!(dest.write_char('-')); c },
169+
pub fn serialize_identifier<W>(mut value: &str, dest: &mut W) -> fmt::Result where W:fmt::Write {
170+
if value.is_empty() {
171+
return Ok(())
172+
}
173+
174+
if value.starts_with("--") {
175+
try!(dest.write_str("--"));
176+
serialize_name(&value[2..], dest)
177+
} else if value == "-" {
178+
dest.write_str("\\-")
179+
} else {
180+
if value.as_bytes()[0] == b'-' {
181+
try!(dest.write_str("-"));
182+
value = &value[1..];
184183
}
185-
};
186-
try!(serialize_char(c, dest, /* is_identifier_start = */ true));
187-
for c in iter {
188-
try!(serialize_char(c, dest, /* is_identifier_start = */ false));
184+
if let digit @ b'0'...b'9' = value.as_bytes()[0] {
185+
try!(write!(dest, "\\3{} ", digit as char));
186+
value = &value[1..];
187+
}
188+
serialize_name(value, dest)
189189
}
190-
Ok(())
191190
}
192191

193192

194-
#[inline]
195-
fn serialize_char<W>(c: char, dest: &mut W, is_identifier_start: bool) -> text_writer::Result
196-
where W: TextWriter {
197-
match c {
198-
'0'...'9' if is_identifier_start => try!(write!(dest, "\\3{} ", c)),
199-
'-' if is_identifier_start => try!(dest.write_str("\\-")),
200-
'0'...'9' | 'A'...'Z' | 'a'...'z' | '_' | '-' => try!(dest.write_char(c)),
201-
_ if c > '\x7F' => try!(dest.write_char(c)),
202-
'\n' => try!(dest.write_str("\\A ")),
203-
'\r' => try!(dest.write_str("\\D ")),
204-
'\x0C' => try!(dest.write_str("\\C ")),
205-
_ => { try!(dest.write_char('\\')); try!(dest.write_char(c)) },
206-
};
207-
Ok(())
193+
fn serialize_name<W>(value: &str, dest: &mut W) -> fmt::Result where W:fmt::Write {
194+
let mut chunk_start = 0;
195+
for (i, b) in value.bytes().enumerate() {
196+
let escaped = match b {
197+
b'0'...b'9' | b'A'...b'Z' | b'a'...b'z' | b'_' | b'-' => continue,
198+
_ if !b.is_ascii() => continue,
199+
b'\n' => Some("\\A "),
200+
b'\r' => Some("\\D "),
201+
b'\x0C' => Some("\\C "),
202+
_ => None,
203+
};
204+
try!(dest.write_str(&value[chunk_start..i]));
205+
if let Some(escaped) = escaped {
206+
try!(dest.write_str(escaped));
207+
} else {
208+
try!(write!(dest, "\\{}", b as char));
209+
}
210+
chunk_start = i + 1;
211+
}
212+
dest.write_str(&value[chunk_start..])
208213
}
209214

210215

211216
/// Write a double-quoted CSS string token, escaping content as necessary.
212-
pub fn serialize_string<W>(value: &str, dest: &mut W) -> text_writer::Result
213-
where W: TextWriter {
214-
try!(dest.write_char('"'));
217+
pub fn serialize_string<W>(value: &str, dest: &mut W) -> fmt::Result where W: fmt::Write {
218+
try!(dest.write_str("\""));
215219
try!(CssStringWriter::new(dest).write_str(value));
216-
try!(dest.write_char('"'));
220+
try!(dest.write_str("\""));
217221
Ok(())
218222
}
219223

220224

221-
/// A `TextWriter` adaptor that escapes text for writing as a double-quoted CSS string.
225+
/// A `fmt::Write` adapter that escapes text for writing as a double-quoted CSS string.
222226
/// Quotes are not included.
223227
///
224228
/// Typical usage:
225229
///
226230
/// ```{rust,ignore}
227-
/// fn write_foo<W>(foo: &Foo, dest: &mut W) -> text_writer::Result where W: TextWriter {
228-
/// try!(dest.write_char('"'));
231+
/// fn write_foo<W>(foo: &Foo, dest: &mut W) -> fmt::Result where W: fmt::Write {
232+
/// try!(dest.write_str("\""));
229233
/// {
230234
/// let mut string_dest = CssStringWriter::new(dest);
231235
/// // Write into string_dest...
232236
/// }
233-
/// try!(dest.write_char('"'));
237+
/// try!(dest.write_str("\""));
234238
/// Ok(())
235239
/// }
236240
/// ```
237241
pub struct CssStringWriter<'a, W: 'a> {
238242
inner: &'a mut W,
239243
}
240244

241-
impl<'a, W> CssStringWriter<'a, W> where W: TextWriter {
245+
impl<'a, W> CssStringWriter<'a, W> where W: fmt::Write {
242246
/// Wrap a text writer to create a `CssStringWriter`.
243247
pub fn new(inner: &'a mut W) -> CssStringWriter<'a, W> {
244248
CssStringWriter { inner: inner }
245249
}
246250
}
247251

248-
impl<'a, W> TextWriter for CssStringWriter<'a, W> where W: TextWriter {
249-
fn write_str(&mut self, s: &str) -> text_writer::Result {
250-
// TODO: avoid decoding/re-encoding UTF-8?
251-
for c in s.chars() {
252-
try!(self.write_char(c))
253-
}
254-
Ok(())
255-
}
256-
257-
fn write_char(&mut self, c: char) -> text_writer::Result {
258-
match c {
259-
'"' => self.inner.write_str("\\\""),
260-
'\\' => self.inner.write_str("\\\\"),
261-
'\n' => self.inner.write_str("\\A "),
262-
'\r' => self.inner.write_str("\\D "),
263-
'\x0C' => self.inner.write_str("\\C "),
264-
_ => self.inner.write_char(c),
252+
impl<'a, W> fmt::Write for CssStringWriter<'a, W> where W: fmt::Write {
253+
fn write_str(&mut self, s: &str) -> fmt::Result {
254+
let mut chunk_start = 0;
255+
for (i, b) in s.bytes().enumerate() {
256+
let escaped = match b {
257+
b'"' => "\\\"",
258+
b'\\' => "\\\\",
259+
b'\n' => "\\A ",
260+
b'\r' => "\\D ",
261+
b'\x0C' => "\\C ",
262+
_ => continue,
263+
};
264+
try!(self.inner.write_str(&s[chunk_start..i]));
265+
try!(self.inner.write_str(escaped));
266+
chunk_start = i + 1;
265267
}
268+
self.inner.write_str(&s[chunk_start..])
266269
}
267270
}
268271

269272

270273
macro_rules! impl_tocss_for_number {
271274
($T: ty) => {
272275
impl<'a> ToCss for $T {
273-
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
276+
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
274277
write!(dest, "{}", *self)
275278
}
276279
}

0 commit comments

Comments
 (0)