1212
1313use container:: Container ;
1414use option:: { None , Option , Some } ;
15- use str;
16- use str:: { StrSlice , OwnedStr } ;
17- use u32;
18- use uint;
15+ use str:: StrSlice ;
1916use unicode:: { derived_property, general_category} ;
2017
18+ #[ cfg( test) ] use str:: OwnedStr ;
19+
2120#[ cfg( not( test) ) ] use cmp:: { Eq , Ord } ;
2221#[ cfg( not( test) ) ] use num:: Zero ;
2322
@@ -202,21 +201,21 @@ pub fn from_digit(num: uint, radix: uint) -> Option<char> {
202201/// - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`
203202/// - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`
204203///
205- pub fn escape_unicode ( c : char ) -> ~str {
206- let s = u32:: to_str_radix ( c as u32 , 16 u) ;
207- let ( c, pad) = cond ! (
208- ( c <= '\xff' ) { ( 'x' , 2 u) }
209- ( c <= '\uffff' ) { ( 'u' , 4 u) }
210- _ { ( 'U' , 8 u) }
204+ pub fn escape_unicode ( c : char , f : & fn ( char ) ) {
205+ // avoid calling str::to_str_radix because we don't really need to allocate
206+ // here.
207+ f ( '\\' ) ;
208+ let pad = cond ! (
209+ ( c <= '\xff' ) { f( 'x' ) ; 2 }
210+ ( c <= '\uffff' ) { f( 'u' ) ; 4 }
211+ _ { f( 'U' ) ; 8 }
211212 ) ;
212- assert ! ( s . len ( ) <= pad ) ;
213- let mut out = ~" \\ " ;
214- out . push_str ( str :: from_char ( c ) ) ;
215- for uint :: range ( s . len ( ) , pad ) |_| {
216- out . push_str ( "0" ) ;
213+ for int :: range_step ( 4 * ( pad - 1 ) , - 1 , - 4 ) |offset| {
214+ match ( ( c as u32 ) >> offset ) & 0xf {
215+ i @ 0 .. 9 => { f ( '0' + i as char ) ; }
216+ i => { f ( 'a' + ( i - 10 ) as char ) ; }
217+ }
217218 }
218- out. push_str ( s) ;
219- out
220219}
221220
222221///
@@ -231,16 +230,16 @@ pub fn escape_unicode(c: char) -> ~str {
231230/// - Any other chars in the range [0x20,0x7e] are not escaped.
232231/// - Any other chars are given hex unicode escapes; see `escape_unicode`.
233232///
234- pub fn escape_default ( c : char ) -> ~ str {
233+ pub fn escape_default ( c : char , f : & fn ( char ) ) {
235234 match c {
236- '\t' => ~" \\ t" ,
237- '\r' => ~" \\ r",
238- '\n' => ~" \\ n" ,
239- '\\' => ~" \\ \\ " ,
240- '\'' => ~" \\ ' " ,
241- '"' => ~" \\ \" " ,
242- '\x20' .. '\x7e' => str :: from_char ( c) ,
243- _ => c. escape_unicode ( ) ,
235+ '\t' => { f ( '\\' ) ; f ( 't' ) ; }
236+ '\r' => { f ( '\\' ) ; f ( 'r' ) ; }
237+ '\n' => { f ( '\\' ) ; f ( 'n' ) ; }
238+ '\\' => { f ( '\\' ) ; f ( '\\' ) ; }
239+ '\'' => { f ( ' \\') ; f ( '\'' ) ; }
240+ '"' => { f ( '\\' ) ; f ( '"' ) ; }
241+ '\x20' .. '\x7e' => { f ( c) ; }
242+ _ => c. escape_unicode ( f ) ,
244243 }
245244}
246245
@@ -274,8 +273,8 @@ pub trait Char {
274273 fn is_digit_radix ( & self , radix : uint ) -> bool ;
275274 fn to_digit ( & self , radix : uint ) -> Option < uint > ;
276275 fn from_digit ( num : uint , radix : uint ) -> Option < char > ;
277- fn escape_unicode ( & self ) -> ~ str ;
278- fn escape_default ( & self ) -> ~ str ;
276+ fn escape_unicode ( & self , f : & fn ( char ) ) ;
277+ fn escape_default ( & self , f : & fn ( char ) ) ;
279278 fn len_utf8_bytes ( & self ) -> uint ;
280279}
281280
@@ -302,9 +301,9 @@ impl Char for char {
302301
303302 fn from_digit ( num : uint , radix : uint ) -> Option < char > { from_digit ( num, radix) }
304303
305- fn escape_unicode ( & self ) -> ~ str { escape_unicode ( * self ) }
304+ fn escape_unicode ( & self , f : & fn ( char ) ) { escape_unicode ( * self , f ) }
306305
307- fn escape_default ( & self ) -> ~ str { escape_default ( * self ) }
306+ fn escape_default ( & self , f : & fn ( char ) ) { escape_default ( * self , f ) }
308307
309308 fn len_utf8_bytes ( & self ) -> uint { len_utf8_bytes ( * self ) }
310309}
@@ -392,27 +391,37 @@ fn test_is_digit() {
392391
393392#[ test]
394393fn test_escape_default( ) {
395- assert_eq ! ( '\n' . escape_default( ) , ~"\\ n");
396- assert_eq!('\r '.escape_default(), ~" \\ r");
397- assert_eq!('\''.escape_default(), ~" \\ ' ");
398- assert_eq!('" ' . escape_default( ) , ~"\\ \" ") ;
399- assert_eq ! ( ' ' . escape_default( ) , ~" ");
400- assert_eq!('a'.escape_default(), ~" a");
401- assert_eq!('~'.escape_default(), ~" ~") ;
402- assert_eq ! ( '\x00' . escape_default( ) , ~"\\ x00");
403- assert_eq!('\x1f '.escape_default(), ~" \\ x1f");
404- assert_eq!('\x7f '.escape_default(), ~" \\ x7f");
405- assert_eq!('\xff '.escape_default(), ~" \\ xff");
406- assert_eq!('\u011b '.escape_default(), ~" \\ u011b");
407- assert_eq!('\U 0001d4b6'.escape_default(), ~" \\ U0001d4b6 ");
394+ fn string( c : char ) -> ~str {
395+ let mut result = ~"";
396+ do escape_default ( c) |c| { result. push_char ( c) ; }
397+ return result;
398+ }
399+ assert_eq ! ( string( '\n' ) , ~"\\ n");
400+ assert_eq!(string('\r '), ~" \\ r");
401+ assert_eq!(string('\''), ~" \\ ' ");
402+ assert_eq!(string('" ' ) , ~"\\ \" ") ;
403+ assert_eq ! ( string( ' ' ) , ~" ");
404+ assert_eq!(string('a'), ~" a");
405+ assert_eq!(string('~'), ~" ~") ;
406+ assert_eq ! ( string( '\x00' ) , ~"\\ x00");
407+ assert_eq!(string('\x1f '), ~" \\ x1f");
408+ assert_eq!(string('\x7f '), ~" \\ x7f");
409+ assert_eq!(string('\xff '), ~" \\ xff");
410+ assert_eq!(string('\u011b '), ~" \\ u011b");
411+ assert_eq!(string('\U 0001d4b6'), ~" \\ U0001d4b6 ");
408412}
409413
410414#[test]
411415fn test_escape_unicode() {
412- assert_eq!('\x00 '.escape_unicode(), ~" \\ x00");
413- assert_eq!('\n '.escape_unicode(), ~" \\ x0a");
414- assert_eq!(' '.escape_unicode(), ~" \\ x20");
415- assert_eq!('a'.escape_unicode(), ~" \\ x61");
416- assert_eq!('\u011b '.escape_unicode(), ~" \\ u011b");
417- assert_eq!('\U 0001d4b6'.escape_unicode(), ~"\\ U0001d4b6" ) ;
416+ fn string(c: char) -> ~str {
417+ let mut result = ~" ";
418+ do escape_unicode(c) |c| { result.push_char(c); }
419+ return result;
420+ }
421+ assert_eq!(string('\x00 '), ~" \\ x00");
422+ assert_eq!(string('\n '), ~" \\ x0a");
423+ assert_eq!(string(' '), ~" \\ x20");
424+ assert_eq!(string('a'), ~" \\ x61");
425+ assert_eq!(string('\u011b '), ~" \\ u011b");
426+ assert_eq!(string('\U 0001d4b6'), ~"\\ U0001d4b6" ) ;
418427}
0 commit comments