@@ -16,9 +16,8 @@ use str::StrSlice;
16
16
use str:: OwnedStr ;
17
17
use container:: Container ;
18
18
use cast;
19
- use ptr;
20
19
use iter:: Iterator ;
21
- use vec:: { CopyableVector , ImmutableVector } ;
20
+ use vec:: { CopyableVector , ImmutableVector , MutableVector } ;
22
21
use to_bytes:: IterBytes ;
23
22
use option:: { Some , None } ;
24
23
@@ -61,7 +60,7 @@ impl Ascii {
61
60
impl ToStr for Ascii {
62
61
#[ inline]
63
62
fn to_str ( & self ) -> ~str {
64
- // self.chr is allways a valid utf8 byte, no need for the check
63
+ // self.chr is always a valid utf8 byte, no need for the check
65
64
unsafe { str:: raw:: from_byte ( self . chr ) }
66
65
}
67
66
}
@@ -253,16 +252,29 @@ impl ToBytesConsume for ~[Ascii] {
253
252
}
254
253
}
255
254
256
- /// Extension methods for ASCII-subset only operations on strings
257
- pub trait StrAsciiExt {
255
+ /// Extension methods for ASCII-subset only operations on owned strings
256
+ pub trait OwnedStrAsciiExt {
258
257
/// Convert the string to ASCII upper case:
259
258
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
260
259
/// but non-ASCII letters are unchanged.
261
- fn to_ascii_upper ( & self ) -> ~str ;
260
+ fn into_ascii_upper ( self ) -> ~str ;
262
261
263
262
/// Convert the string to ASCII lower case:
264
263
/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
265
264
/// but non-ASCII letters are unchanged.
265
+ fn into_ascii_lower ( self ) -> ~str ;
266
+ }
267
+
268
+ /// Extension methods for ASCII-subset only operations on string slices
269
+ pub trait StrAsciiExt {
270
+ /// Makes a copy of the string in ASCII upper case:
271
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
272
+ /// but non-ASCII letters are unchanged.
273
+ fn to_ascii_upper ( & self ) -> ~str ;
274
+
275
+ /// Makes a copy of the string in ASCII lower case:
276
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
277
+ /// but non-ASCII letters are unchanged.
266
278
fn to_ascii_lower ( & self ) -> ~str ;
267
279
268
280
/// Check that two strings are an ASCII case-insensitive match.
@@ -274,12 +286,12 @@ pub trait StrAsciiExt {
274
286
impl < ' self > StrAsciiExt for & ' self str {
275
287
#[ inline]
276
288
fn to_ascii_upper ( & self ) -> ~str {
277
- map_bytes ( * self , ASCII_UPPER_MAP )
289
+ unsafe { str_copy_map_bytes ( * self , ASCII_UPPER_MAP ) }
278
290
}
279
291
280
292
#[ inline]
281
293
fn to_ascii_lower ( & self ) -> ~str {
282
- map_bytes ( * self , ASCII_LOWER_MAP )
294
+ unsafe { str_copy_map_bytes ( * self , ASCII_LOWER_MAP ) }
283
295
}
284
296
285
297
#[ inline]
@@ -289,20 +301,34 @@ impl<'self> StrAsciiExt for &'self str {
289
301
}
290
302
}
291
303
304
+ impl OwnedStrAsciiExt for ~str {
305
+ #[ inline]
306
+ fn into_ascii_upper ( self ) -> ~str {
307
+ unsafe { str_map_bytes ( self , ASCII_UPPER_MAP ) }
308
+ }
309
+
310
+ #[ inline]
311
+ fn into_ascii_lower ( self ) -> ~str {
312
+ unsafe { str_map_bytes ( self , ASCII_LOWER_MAP ) }
313
+ }
314
+ }
315
+
292
316
#[ inline]
293
- fn map_bytes( string : & str , map : & ' static [ u8 ] ) -> ~str {
294
- let len = string. len ( ) ;
295
- let mut result = str:: with_capacity ( len) ;
296
- unsafe {
297
- do result. as_mut_buf |mut buf, _| {
298
- for c in string. as_bytes ( ) . iter ( ) {
299
- * buf = map[ * c] ;
300
- buf = ptr:: mut_offset ( buf, 1 )
301
- }
302
- }
303
- str:: raw:: set_len ( & mut result, len) ;
317
+ unsafe fn str_map_bytes ( string : ~str , map : & ' static [ u8 ] ) -> ~str {
318
+ let mut bytes = string. into_bytes ( ) ;
319
+
320
+ for b in bytes. mut_iter ( ) {
321
+ * b = map[ * b] ;
304
322
}
305
- result
323
+
324
+ str:: raw:: from_utf8_owned ( bytes)
325
+ }
326
+
327
+ #[ inline]
328
+ unsafe fn str_copy_map_bytes ( string : & str , map : & ' static [ u8 ] ) -> ~str {
329
+ let bytes = string. byte_iter ( ) . map ( |b| map[ b] ) . to_owned_vec ( ) ;
330
+
331
+ str:: raw:: from_utf8_owned ( bytes)
306
332
}
307
333
308
334
static ASCII_LOWER_MAP : & ' static [ u8 ] = & [
@@ -494,6 +520,37 @@ mod tests {
494
520
}
495
521
}
496
522
523
+ #[test]
524
+ fn test_into_ascii_upper() {
525
+ assert_eq!((~" url( ) URL ( ) uRl( ) ürl").into_ascii_upper(), ~" URL ( ) URL ( ) URL ( ) üRL");
526
+ assert_eq!((~" hıKß").into_ascii_upper(), ~" HıKß ");
527
+
528
+ let mut i = 0;
529
+ while i <= 500 {
530
+ let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
531
+ else { i };
532
+ assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_upper(),
533
+ from_char(from_u32(upper).unwrap()))
534
+ i += 1;
535
+ }
536
+ }
537
+
538
+ #[test]
539
+ fn test_into_ascii_lower() {
540
+ assert_eq!((~" url( ) URL ( ) uRl( ) Ürl").into_ascii_lower(), ~" url( ) url( ) url( ) Ürl");
541
+ // Dotted capital I, Kelvin sign, Sharp S.
542
+ assert_eq!((~" HİKß ").into_ascii_lower(), ~" hİKß");
543
+
544
+ let mut i = 0;
545
+ while i <= 500 {
546
+ let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
547
+ else { i };
548
+ assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_lower(),
549
+ from_char(from_u32(lower).unwrap()))
550
+ i += 1;
551
+ }
552
+ }
553
+
497
554
#[test]
498
555
fn test_eq_ignore_ascii_case() {
499
556
assert!(" url( ) URL ( ) uRl( ) Ürl".eq_ignore_ascii_case(" url( ) url( ) url( ) Ürl"));
0 commit comments