2
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
4
5
- use std:: fmt ;
5
+ use std:: ascii :: AsciiExt ;
6
6
use std:: cmp;
7
-
8
- use text_writer:: { self , TextWriter } ;
7
+ use std:: fmt:: { self , Write } ;
9
8
10
9
use super :: { Token , NumericValue , PercentageValue } ;
11
10
12
11
13
12
/// Trait for things the can serialize themselves in CSS syntax.
14
13
pub trait ToCss {
15
14
/// 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 ;
17
16
18
17
/// Serialize `self` in CSS syntax and return a string.
19
18
///
@@ -38,15 +37,14 @@ pub trait ToCss {
38
37
///
39
38
/// (This is a convenience wrapper for `to_css` and probably should not be overridden.)
40
39
#[ 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 {
42
41
self . to_css ( dest) . map_err ( |_| fmt:: Error )
43
42
}
44
43
}
45
44
46
45
47
46
#[ 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 {
50
48
// `value.value >= 0` is true for negative 0.
51
49
if value. has_sign && value. value . is_sign_positive ( ) {
52
50
try!( dest. write_str ( "+" ) ) ;
@@ -67,30 +65,28 @@ where W: TextWriter {
67
65
68
66
69
67
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 {
71
69
match * self {
72
70
Token :: Ident ( ref value) => try!( serialize_identifier ( & * * value, dest) ) ,
73
71
Token :: AtKeyword ( ref value) => {
74
- try!( dest. write_char ( '@' ) ) ;
72
+ try!( dest. write_str ( "@" ) ) ;
75
73
try!( serialize_identifier ( & * * value, dest) ) ;
76
74
} ,
77
75
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) ) ;
82
78
} ,
83
79
Token :: IDHash ( ref value) => {
84
- try!( dest. write_char ( '#' ) ) ;
80
+ try!( dest. write_str ( "#" ) ) ;
85
81
try!( serialize_identifier ( & * * value, dest) ) ;
86
82
}
87
83
Token :: QuotedString ( ref value) => try!( serialize_string ( & * * value, dest) ) ,
88
84
Token :: Url ( ref value) => {
89
85
try!( dest. write_str ( "url(" ) ) ;
90
86
try!( serialize_string ( & * * value, dest) ) ;
91
- try!( dest. write_char ( ')' ) ) ;
87
+ try!( dest. write_str ( ")" ) ) ;
92
88
} ,
93
- Token :: Delim ( value) => try!( dest . write_char ( value) ) ,
89
+ Token :: Delim ( value) => try!( write ! ( dest , "{}" , value) ) ,
94
90
95
91
Token :: Number ( value) => try!( write_numeric ( value, dest) ) ,
96
92
Token :: Percentage ( PercentageValue { unit_value, int_value, has_sign } ) => {
@@ -100,17 +96,15 @@ impl<'a> ToCss for Token<'a> {
100
96
has_sign : has_sign,
101
97
} ;
102
98
try!( write_numeric ( value, dest) ) ;
103
- try!( dest. write_char ( '%' ) ) ;
99
+ try!( dest. write_str ( "%" ) ) ;
104
100
} ,
105
101
Token :: Dimension ( value, ref unit) => {
106
102
try!( write_numeric ( value, dest) ) ;
107
103
// Disambiguate with scientific notation.
108
104
let unit = & * * unit;
109
105
if unit == "e" || unit == "E" || unit. starts_with ( "e-" ) || unit. starts_with ( "E-" ) {
110
106
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) ) ;
114
108
} else {
115
109
try!( serialize_identifier ( unit, dest) ) ;
116
110
}
@@ -140,9 +134,9 @@ impl<'a> ToCss for Token<'a> {
140
134
141
135
Token :: WhiteSpace ( content) => try!( dest. write_str ( content) ) ,
142
136
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 ( "," ) ) ,
146
140
Token :: IncludeMatch => try!( dest. write_str ( "~=" ) ) ,
147
141
Token :: DashMatch => try!( dest. write_str ( "|=" ) ) ,
148
142
Token :: PrefixMatch => try!( dest. write_str ( "^=" ) ) ,
@@ -154,123 +148,132 @@ impl<'a> ToCss for Token<'a> {
154
148
155
149
Token :: Function ( ref name) => {
156
150
try!( serialize_identifier ( & * * name, dest) ) ;
157
- try!( dest. write_char ( '(' ) ) ;
151
+ try!( dest. write_str ( "(" ) ) ;
158
152
} ,
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 ( "{" ) ) ,
162
156
163
157
Token :: BadUrl => try!( dest. write_str ( "url(<bad url>)" ) ) ,
164
158
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 ( "}" ) ) ,
168
162
}
169
163
Ok ( ( ) )
170
164
}
171
165
}
172
166
173
167
174
168
/// 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 ..] ;
184
183
}
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)
189
189
}
190
- Ok ( ( ) )
191
190
}
192
191
193
192
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..] )
208
213
}
209
214
210
215
211
216
/// 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 ( "\" " ) ) ;
215
219
try!( CssStringWriter :: new ( dest) . write_str ( value) ) ;
216
- try!( dest. write_char ( '"' ) ) ;
220
+ try!( dest. write_str ( " \" " ) ) ;
217
221
Ok ( ( ) )
218
222
}
219
223
220
224
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.
222
226
/// Quotes are not included.
223
227
///
224
228
/// Typical usage:
225
229
///
226
230
/// ```{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("\"" ));
229
233
/// {
230
234
/// let mut string_dest = CssStringWriter::new(dest);
231
235
/// // Write into string_dest...
232
236
/// }
233
- /// try!(dest.write_char('"' ));
237
+ /// try!(dest.write_str("\"" ));
234
238
/// Ok(())
235
239
/// }
236
240
/// ```
237
241
pub struct CssStringWriter < ' a , W : ' a > {
238
242
inner : & ' a mut W ,
239
243
}
240
244
241
- impl < ' a , W > CssStringWriter < ' a , W > where W : TextWriter {
245
+ impl < ' a , W > CssStringWriter < ' a , W > where W : fmt :: Write {
242
246
/// Wrap a text writer to create a `CssStringWriter`.
243
247
pub fn new ( inner : & ' a mut W ) -> CssStringWriter < ' a , W > {
244
248
CssStringWriter { inner : inner }
245
249
}
246
250
}
247
251
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 ;
265
267
}
268
+ self . inner . write_str ( & s[ chunk_start..] )
266
269
}
267
270
}
268
271
269
272
270
273
macro_rules! impl_tocss_for_number {
271
274
( $T: ty) => {
272
275
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 {
274
277
write!( dest, "{}" , * self )
275
278
}
276
279
}
0 commit comments