33//! Provides an iterator over attributes key/value pairs
44
55use errors:: { Error , Result } ;
6- use escape:: { escape , unescape , unescape_with } ;
6+ use escape:: { do_unescape , escape } ;
77use reader:: { is_whitespace, Reader } ;
88use std:: borrow:: Cow ;
99use std:: collections:: HashMap ;
@@ -96,7 +96,7 @@ impl<'a> Attribute<'a> {
9696 ///
9797 /// See also [`unescaped_value_with_custom_entities()`](#method.unescaped_value_with_custom_entities)
9898 pub fn unescaped_value ( & self ) -> Result < Cow < [ u8 ] > > {
99- unescape ( & * self . value ) . map_err ( Error :: EscapeError )
99+ self . make_unescaped_value ( None )
100100 }
101101
102102 /// Returns the unescaped value, using custom entities.
@@ -116,24 +116,14 @@ impl<'a> Attribute<'a> {
116116 & self ,
117117 custom_entities : & HashMap < Vec < u8 > , Vec < u8 > > ,
118118 ) -> Result < Cow < [ u8 ] > > {
119- unescape_with ( & * self . value , custom_entities) . map_err ( Error :: EscapeError )
119+ self . make_unescaped_value ( Some ( custom_entities) )
120120 }
121121
122- /// Decode then unescapes the value
123- ///
124- /// This allocates a `String` in all cases. For performance reasons it might be a better idea to
125- /// instead use one of:
126- ///
127- /// * [`Reader::decode()`], as it only allocates when the decoding can't be performed otherwise.
128- /// * [`unescaped_value()`], as it doesn't allocate when no escape sequences are used.
129- ///
130- /// [`unescaped_value()`]: #method.unescaped_value
131- /// [`Reader::decode()`]: ../../reader/struct.Reader.html#method.decode
132- #[ cfg( feature = "encoding" ) ]
133- pub fn unescape_and_decode_value < B : BufRead > ( & self , reader : & Reader < B > ) -> Result < String > {
134- let decoded = reader. decode ( & * self . value ) ;
135- let unescaped = unescape ( decoded. as_bytes ( ) ) . map_err ( Error :: EscapeError ) ?;
136- String :: from_utf8 ( unescaped. into_owned ( ) ) . map_err ( |e| Error :: Utf8 ( e. utf8_error ( ) ) )
122+ fn make_unescaped_value (
123+ & self ,
124+ custom_entities : Option < & HashMap < Vec < u8 > , Vec < u8 > > > ,
125+ ) -> Result < Cow < [ u8 ] > > {
126+ do_unescape ( & * self . value , custom_entities) . map_err ( Error :: EscapeError )
137127 }
138128
139129 /// Decode then unescapes the value
@@ -146,11 +136,8 @@ impl<'a> Attribute<'a> {
146136 ///
147137 /// [`unescaped_value()`]: #method.unescaped_value
148138 /// [`Reader::decode()`]: ../../reader/struct.Reader.html#method.decode
149- #[ cfg( not( feature = "encoding" ) ) ]
150139 pub fn unescape_and_decode_value < B : BufRead > ( & self , reader : & Reader < B > ) -> Result < String > {
151- let decoded = reader. decode ( & * self . value ) ?;
152- let unescaped = unescape ( decoded. as_bytes ( ) ) . map_err ( Error :: EscapeError ) ?;
153- String :: from_utf8 ( unescaped. into_owned ( ) ) . map_err ( |e| Error :: Utf8 ( e. utf8_error ( ) ) )
140+ self . do_unescape_and_decode_value ( reader, None )
154141 }
155142
156143 /// Decode then unescapes the value with custom entities
@@ -161,47 +148,42 @@ impl<'a> Attribute<'a> {
161148 /// * [`Reader::decode()`], as it only allocates when the decoding can't be performed otherwise.
162149 /// * [`unescaped_value()`], as it doesn't allocate when no escape sequences are used.
163150 ///
164- /// [`unescaped_value_with_custom_entities()`]: #method.unescaped_value
151+ /// [`unescaped_value_with_custom_entities()`]: #method.unescaped_value_with_custom_entities
165152 /// [`Reader::decode()`]: ../../reader/struct.Reader.html#method.decode
166153 ///
167154 /// # Pre-condition
168155 ///
169156 /// The keys and values of `custom_entities`, if any, must be valid UTF-8.
170- #[ cfg( feature = "encoding" ) ]
171157 pub fn unescape_and_decode_value_with_custom_entities < B : BufRead > (
172158 & self ,
173159 reader : & Reader < B > ,
174160 custom_entities : & HashMap < Vec < u8 > , Vec < u8 > > ,
161+ ) -> Result < String > {
162+ self . do_unescape_and_decode_value ( reader, Some ( custom_entities) )
163+ }
164+
165+ /// The keys and values of `custom_entities`, if any, must be valid UTF-8.
166+ #[ cfg( feature = "encoding" ) ]
167+ fn do_unescape_and_decode_value < B : BufRead > (
168+ & self ,
169+ reader : & Reader < B > ,
170+ custom_entities : Option < & HashMap < Vec < u8 > , Vec < u8 > > > ,
175171 ) -> Result < String > {
176172 let decoded = reader. decode ( & * self . value ) ;
177173 let unescaped =
178- unescape_with ( decoded. as_bytes ( ) , custom_entities) . map_err ( Error :: EscapeError ) ?;
174+ do_unescape ( decoded. as_bytes ( ) , custom_entities) . map_err ( Error :: EscapeError ) ?;
179175 String :: from_utf8 ( unescaped. into_owned ( ) ) . map_err ( |e| Error :: Utf8 ( e. utf8_error ( ) ) )
180176 }
181177
182- /// Decode then unescapes the value with custom entities
183- ///
184- /// This allocates a `String` in all cases. For performance reasons it might be a better idea to
185- /// instead use one of:
186- ///
187- /// * [`Reader::decode()`], as it only allocates when the decoding can't be performed otherwise.
188- /// * [`unescaped_value()`], as it doesn't allocate when no escape sequences are used.
189- ///
190- /// [`unescaped_value_with_custom_entities()`]: #method.unescaped_value_with_custom_entities
191- /// [`Reader::decode()`]: ../../reader/struct.Reader.html#method.decode
192- ///
193- /// # Pre-condition
194- ///
195- /// The keys and values of `custom_entities`, if any, must be valid UTF-8.
196178 #[ cfg( not( feature = "encoding" ) ) ]
197- pub fn unescape_and_decode_value_with_custom_entities < B : BufRead > (
179+ fn do_unescape_and_decode_value < B : BufRead > (
198180 & self ,
199181 reader : & Reader < B > ,
200- custom_entities : & HashMap < Vec < u8 > , Vec < u8 > > ,
182+ custom_entities : Option < & HashMap < Vec < u8 > , Vec < u8 > > > ,
201183 ) -> Result < String > {
202184 let decoded = reader. decode ( & * self . value ) ?;
203185 let unescaped =
204- unescape_with ( decoded. as_bytes ( ) , custom_entities) . map_err ( Error :: EscapeError ) ?;
186+ do_unescape ( decoded. as_bytes ( ) , custom_entities) . map_err ( Error :: EscapeError ) ?;
205187 String :: from_utf8 ( unescaped. into_owned ( ) ) . map_err ( |e| Error :: Utf8 ( e. utf8_error ( ) ) )
206188 }
207189
@@ -217,9 +199,7 @@ impl<'a> Attribute<'a> {
217199 & self ,
218200 reader : & mut Reader < B > ,
219201 ) -> Result < String > {
220- let decoded = reader. decode_without_bom ( & * self . value ) ;
221- let unescaped = unescape ( decoded. as_bytes ( ) ) . map_err ( Error :: EscapeError ) ?;
222- String :: from_utf8 ( unescaped. into_owned ( ) ) . map_err ( |e| Error :: Utf8 ( e. utf8_error ( ) ) )
202+ self . do_unescape_and_decode_without_bom ( reader, None )
223203 }
224204
225205 /// helper method to unescape then decode self using the reader encoding
@@ -234,9 +214,7 @@ impl<'a> Attribute<'a> {
234214 & self ,
235215 reader : & Reader < B > ,
236216 ) -> Result < String > {
237- let decoded = reader. decode_without_bom ( & * self . value ) ?;
238- let unescaped = unescape ( decoded. as_bytes ( ) ) . map_err ( Error :: EscapeError ) ?;
239- String :: from_utf8 ( unescaped. into_owned ( ) ) . map_err ( |e| Error :: Utf8 ( e. utf8_error ( ) ) )
217+ self . do_unescape_and_decode_without_bom ( reader, None )
240218 }
241219
242220 /// helper method to unescape then decode self using the reader encoding with custom entities
@@ -256,10 +234,7 @@ impl<'a> Attribute<'a> {
256234 reader : & mut Reader < B > ,
257235 custom_entities : & HashMap < Vec < u8 > , Vec < u8 > > ,
258236 ) -> Result < String > {
259- let decoded = reader. decode_without_bom ( & * self . value ) ;
260- let unescaped =
261- unescape_with ( decoded. as_bytes ( ) , custom_entities) . map_err ( Error :: EscapeError ) ?;
262- String :: from_utf8 ( unescaped. into_owned ( ) ) . map_err ( |e| Error :: Utf8 ( e. utf8_error ( ) ) )
237+ self . do_unescape_and_decode_without_bom ( reader, Some ( custom_entities) )
263238 }
264239
265240 /// helper method to unescape then decode self using the reader encoding with custom entities
@@ -278,10 +253,31 @@ impl<'a> Attribute<'a> {
278253 & self ,
279254 reader : & Reader < B > ,
280255 custom_entities : & HashMap < Vec < u8 > , Vec < u8 > > ,
256+ ) -> Result < String > {
257+ self . do_unescape_and_decode_without_bom ( reader, Some ( custom_entities) )
258+ }
259+
260+ #[ cfg( feature = "encoding" ) ]
261+ fn do_unescape_and_decode_without_bom < B : BufRead > (
262+ & self ,
263+ reader : & mut Reader < B > ,
264+ custom_entities : Option < & HashMap < Vec < u8 > , Vec < u8 > > > ,
265+ ) -> Result < String > {
266+ let decoded = reader. decode_without_bom ( & * self . value ) ;
267+ let unescaped =
268+ do_unescape ( decoded. as_bytes ( ) , custom_entities) . map_err ( Error :: EscapeError ) ?;
269+ String :: from_utf8 ( unescaped. into_owned ( ) ) . map_err ( |e| Error :: Utf8 ( e. utf8_error ( ) ) )
270+ }
271+
272+ #[ cfg( not( feature = "encoding" ) ) ]
273+ fn do_unescape_and_decode_without_bom < B : BufRead > (
274+ & self ,
275+ reader : & Reader < B > ,
276+ custom_entities : Option < & HashMap < Vec < u8 > , Vec < u8 > > > ,
281277 ) -> Result < String > {
282278 let decoded = reader. decode_without_bom ( & * self . value ) ?;
283279 let unescaped =
284- unescape_with ( decoded. as_bytes ( ) , custom_entities) . map_err ( Error :: EscapeError ) ?;
280+ do_unescape ( decoded. as_bytes ( ) , custom_entities) . map_err ( Error :: EscapeError ) ?;
285281 String :: from_utf8 ( unescaped. into_owned ( ) ) . map_err ( |e| Error :: Utf8 ( e. utf8_error ( ) ) )
286282 }
287283}
0 commit comments