1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Operations on ASCII strings and characters
13 use to_str::{IntoStr};
18 use container::Container;
22 use slice::{ImmutableVector, MutableVector, Vector};
24 use option::{Option, Some, None};
26 /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
27 #[deriving(Clone, Eq, Ord, TotalOrd, TotalEq, Hash)]
28 pub struct Ascii { priv chr: u8 }
31 /// Converts an ascii character into a `u8`.
33 pub fn to_byte(self) -> u8 {
37 /// Converts an ascii character into a `char`.
39 pub fn to_char(self) -> char {
43 /// Convert to lowercase.
45 pub fn to_lower(self) -> Ascii {
46 Ascii{chr: ASCII_LOWER_MAP[self.chr]}
49 /// Convert to uppercase.
51 pub fn to_upper(self) -> Ascii {
52 Ascii{chr: ASCII_UPPER_MAP[self.chr]}
55 /// Compares two ascii characters of equality, ignoring case.
57 pub fn eq_ignore_case(self, other: Ascii) -> bool {
58 ASCII_LOWER_MAP[self.chr] == ASCII_LOWER_MAP[other.chr]
61 // the following methods are like ctype, and the implementation is inspired by musl
63 /// Check if the character is a letter (a-z, A-Z)
65 pub fn is_alpha(&self) -> bool {
66 (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
69 /// Check if the character is a number (0-9)
71 pub fn is_digit(&self) -> bool {
72 self.chr >= 0x30 && self.chr <= 0x39
75 /// Check if the character is a letter or number
77 pub fn is_alnum(&self) -> bool {
78 self.is_alpha() || self.is_digit()
81 /// Check if the character is a space or horizontal tab
83 pub fn is_blank(&self) -> bool {
84 self.chr == ' ' as u8 || self.chr == '\t' as u8
87 /// Check if the character is a control character
89 pub fn is_control(&self) -> bool {
90 self.chr < 0x20 || self.chr == 0x7F
93 /// Checks if the character is printable (except space)
95 pub fn is_graph(&self) -> bool {
96 (self.chr - 0x21) < 0x5E
99 /// Checks if the character is printable (including space)
101 pub fn is_print(&self) -> bool {
102 (self.chr - 0x20) < 0x5F
105 /// Checks if the character is lowercase
107 pub fn is_lower(&self) -> bool {
108 (self.chr - 'a' as u8) < 26
111 /// Checks if the character is uppercase
113 pub fn is_upper(&self) -> bool {
114 (self.chr - 'A' as u8) < 26
117 /// Checks if the character is punctuation
119 pub fn is_punctuation(&self) -> bool {
120 self.is_graph() && !self.is_alnum()
123 /// Checks if the character is a valid hex digit
125 pub fn is_hex(&self) -> bool {
126 self.is_digit() || ((self.chr | 32u8) - 'a' as u8) < 6
130 impl<'a> fmt::Show for Ascii {
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 (self.chr as char).fmt(f)
136 /// Trait for converting into an ascii type.
137 pub trait AsciiCast<T> {
138 /// Convert to an ascii type, fail on non-ASCII input.
140 fn to_ascii(&self) -> T {
141 assert!(self.is_ascii());
142 unsafe {self.to_ascii_nocheck()}
145 /// Convert to an ascii type, return None on non-ASCII input.
147 fn to_ascii_opt(&self) -> Option<T> {
149 Some(unsafe { self.to_ascii_nocheck() })
155 /// Convert to an ascii type, not doing any range asserts
156 unsafe fn to_ascii_nocheck(&self) -> T;
158 /// Check if convertible to ascii
159 fn is_ascii(&self) -> bool;
162 impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] {
164 unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
165 cast::transmute(*self)
169 fn is_ascii(&self) -> bool {
170 for b in self.iter() {
171 if !b.is_ascii() { return false; }
177 impl<'a> AsciiCast<&'a [Ascii]> for &'a str {
179 unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
180 cast::transmute(*self)
184 fn is_ascii(&self) -> bool {
185 self.bytes().all(|b| b.is_ascii())
189 impl AsciiCast<Ascii> for u8 {
191 unsafe fn to_ascii_nocheck(&self) -> Ascii {
196 fn is_ascii(&self) -> bool {
201 impl AsciiCast<Ascii> for char {
203 unsafe fn to_ascii_nocheck(&self) -> Ascii {
204 Ascii{ chr: *self as u8 }
208 fn is_ascii(&self) -> bool {
209 *self as u32 - ('\x7F' as u32 & *self as u32) == 0
213 /// Trait for copyless casting to an ascii vector.
214 pub trait OwnedAsciiCast {
215 /// Check if convertible to ascii
216 fn is_ascii(&self) -> bool;
218 /// Take ownership and cast to an ascii vector. Fail on non-ASCII input.
220 fn into_ascii(self) -> ~[Ascii] {
221 assert!(self.is_ascii());
222 unsafe {self.into_ascii_nocheck()}
225 /// Take ownership and cast to an ascii vector. Return None on non-ASCII input.
227 fn into_ascii_opt(self) -> Option<~[Ascii]> {
229 Some(unsafe { self.into_ascii_nocheck() })
235 /// Take ownership and cast to an ascii vector.
236 /// Does not perform validation checks.
237 unsafe fn into_ascii_nocheck(self) -> ~[Ascii];
240 impl OwnedAsciiCast for ~[u8] {
242 fn is_ascii(&self) -> bool {
243 self.as_slice().is_ascii()
247 unsafe fn into_ascii_nocheck(self) -> ~[Ascii] {
248 cast::transmute(self)
252 impl OwnedAsciiCast for ~str {
254 fn is_ascii(&self) -> bool {
255 self.as_slice().is_ascii()
259 unsafe fn into_ascii_nocheck(self) -> ~[Ascii] {
260 cast::transmute(self)
264 /// Trait for converting an ascii type to a string. Needed to convert
265 /// `&[Ascii]` to `&str`.
267 /// Convert to a string.
268 fn as_str_ascii<'a>(&'a self) -> &'a str;
270 /// Convert to vector representing a lower cased ascii string.
271 fn to_lower(&self) -> ~[Ascii];
273 /// Convert to vector representing a upper cased ascii string.
274 fn to_upper(&self) -> ~[Ascii];
276 /// Compares two Ascii strings ignoring case.
277 fn eq_ignore_case(self, other: &[Ascii]) -> bool;
280 impl<'a> AsciiStr for &'a [Ascii] {
282 fn as_str_ascii<'a>(&'a self) -> &'a str {
283 unsafe { cast::transmute(*self) }
287 fn to_lower(&self) -> ~[Ascii] {
288 self.map(|a| a.to_lower())
292 fn to_upper(&self) -> ~[Ascii] {
293 self.map(|a| a.to_upper())
297 fn eq_ignore_case(self, other: &[Ascii]) -> bool {
298 self.iter().zip(other.iter()).all(|(&a, &b)| a.eq_ignore_case(b))
302 impl IntoStr for ~[Ascii] {
304 fn into_str(self) -> ~str {
305 unsafe { cast::transmute(self) }
309 impl IntoStr for Vec<Ascii> {
311 fn into_str(self) -> ~str {
312 let v: ~[Ascii] = self.move_iter().collect();
313 unsafe { cast::transmute(v) }
317 /// Trait to convert to an owned byte array by consuming self
318 pub trait IntoBytes {
319 /// Converts to an owned byte array by consuming self
320 fn into_bytes(self) -> ~[u8];
323 impl IntoBytes for ~[Ascii] {
324 fn into_bytes(self) -> ~[u8] {
325 unsafe { cast::transmute(self) }
329 /// Extension methods for ASCII-subset only operations on owned strings
330 pub trait OwnedStrAsciiExt {
331 /// Convert the string to ASCII upper case:
332 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
333 /// but non-ASCII letters are unchanged.
334 fn into_ascii_upper(self) -> ~str;
336 /// Convert the string to ASCII lower case:
337 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
338 /// but non-ASCII letters are unchanged.
339 fn into_ascii_lower(self) -> ~str;
342 /// Extension methods for ASCII-subset only operations on string slices
343 pub trait StrAsciiExt {
344 /// Makes a copy of the string in ASCII upper case:
345 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
346 /// but non-ASCII letters are unchanged.
347 fn to_ascii_upper(&self) -> ~str;
349 /// Makes a copy of the string in ASCII lower case:
350 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
351 /// but non-ASCII letters are unchanged.
352 fn to_ascii_lower(&self) -> ~str;
354 /// Check that two strings are an ASCII case-insensitive match.
355 /// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
356 /// but without allocating and copying temporary strings.
357 fn eq_ignore_ascii_case(&self, other: &str) -> bool;
360 impl<'a> StrAsciiExt for &'a str {
362 fn to_ascii_upper(&self) -> ~str {
363 unsafe { str_copy_map_bytes(*self, ASCII_UPPER_MAP) }
367 fn to_ascii_lower(&self) -> ~str {
368 unsafe { str_copy_map_bytes(*self, ASCII_LOWER_MAP) }
372 fn eq_ignore_ascii_case(&self, other: &str) -> bool {
373 self.len() == other.len() && self.as_bytes().iter().zip(other.as_bytes().iter()).all(
374 |(byte_self, byte_other)| ASCII_LOWER_MAP[*byte_self] == ASCII_LOWER_MAP[*byte_other])
378 impl OwnedStrAsciiExt for ~str {
380 fn into_ascii_upper(self) -> ~str {
381 unsafe { str_map_bytes(self, ASCII_UPPER_MAP) }
385 fn into_ascii_lower(self) -> ~str {
386 unsafe { str_map_bytes(self, ASCII_LOWER_MAP) }
391 unsafe fn str_map_bytes(string: ~str, map: &'static [u8]) -> ~str {
392 let mut bytes = string.into_bytes();
394 for b in bytes.mut_iter() {
398 str::raw::from_utf8_owned(bytes)
402 unsafe fn str_copy_map_bytes(string: &str, map: &'static [u8]) -> ~str {
403 let bytes = string.bytes().map(|b| map[b]).collect::<~[_]>();
405 str::raw::from_utf8_owned(bytes)
408 static ASCII_LOWER_MAP: &'static [u8] = &[
409 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
410 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
411 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
412 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
413 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
414 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
415 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
416 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
417 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
418 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
419 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
420 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
421 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
422 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
423 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
424 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
425 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
426 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
427 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
428 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
429 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
430 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
431 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
432 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
433 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
434 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
435 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
436 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
437 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
438 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
439 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
440 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
443 static ASCII_UPPER_MAP: &'static [u8] = &[
444 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
445 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
446 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
447 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
448 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
449 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
450 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
451 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
452 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
453 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
454 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
455 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
456 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
457 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
458 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
459 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
460 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
461 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
462 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
463 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
464 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
465 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
466 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
467 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
468 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
469 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
470 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
471 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
472 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
473 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
474 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
475 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
487 macro_rules! v2ascii (
488 ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
489 (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
490 (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
493 macro_rules! vec2ascii (
494 ($($e:expr),*) => (Vec::from_slice([$(Ascii{chr:$e}),*]));
499 assert_eq!(65u8.to_ascii().to_byte(), 65u8);
500 assert_eq!(65u8.to_ascii().to_char(), 'A');
501 assert_eq!('A'.to_ascii().to_char(), 'A');
502 assert_eq!('A'.to_ascii().to_byte(), 65u8);
504 assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
505 assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
506 assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
507 assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');
509 assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
510 assert_eq!('['.to_ascii().to_lower().to_char(), '[');
511 assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
512 assert_eq!('{'.to_ascii().to_upper().to_char(), '{');
514 assert!('0'.to_ascii().is_digit());
515 assert!('9'.to_ascii().is_digit());
516 assert!(!'/'.to_ascii().is_digit());
517 assert!(!':'.to_ascii().is_digit());
519 assert!((0x1fu8).to_ascii().is_control());
520 assert!(!' '.to_ascii().is_control());
521 assert!((0x7fu8).to_ascii().is_control());
523 assert!("banana".chars().all(|c| c.is_ascii()));
524 assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
528 fn test_ascii_vec() {
529 let test = &[40u8, 32u8, 59u8];
530 assert_eq!(test.to_ascii(), v2ascii!([40, 32, 59]));
531 assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59]));
532 // FIXME: #5475 borrowchk error, owned vectors do not live long enough
533 // if chained-from directly
534 let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
535 let v = ~"( ;"; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
537 assert_eq!("abCDef&?#".to_ascii().to_lower().into_str(), ~"abcdef&?#");
538 assert_eq!("abCDef&?#".to_ascii().to_upper().into_str(), ~"ABCDEF&?#");
540 assert_eq!("".to_ascii().to_lower().into_str(), ~"");
541 assert_eq!("YMCA".to_ascii().to_lower().into_str(), ~"ymca");
542 assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_str(), ~"ABCDEFXYZ:.;");
544 assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
546 assert!("".is_ascii());
547 assert!("a".is_ascii());
548 assert!(!"\u2009".is_ascii());
553 fn test_ascii_vec_ng() {
554 assert_eq!(Vec::from_slice("abCDef&?#".to_ascii().to_lower()).into_str(), ~"abcdef&?#");
555 assert_eq!(Vec::from_slice("abCDef&?#".to_ascii().to_upper()).into_str(), ~"ABCDEF&?#");
557 assert_eq!(Vec::from_slice("".to_ascii().to_lower()).into_str(), ~"");
558 assert_eq!(Vec::from_slice("YMCA".to_ascii().to_lower()).into_str(), ~"ymca");
559 assert_eq!(Vec::from_slice("abcDEFxyz:.;".to_ascii().to_upper()).into_str(),
564 fn test_owned_ascii_vec() {
565 assert_eq!((~"( ;").into_ascii(), v2ascii!(~[40, 32, 59]));
566 assert_eq!((~[40u8, 32u8, 59u8]).into_ascii(), v2ascii!(~[40, 32, 59]));
570 fn test_ascii_as_str() {
571 let v = v2ascii!([40, 32, 59]);
572 assert_eq!(v.as_str_ascii(), "( ;");
576 fn test_ascii_into_str() {
577 assert_eq!(v2ascii!(~[40, 32, 59]).into_str(), ~"( ;");
578 assert_eq!(vec2ascii!(40, 32, 59).into_str(), ~"( ;");
582 fn test_ascii_to_bytes() {
583 assert_eq!(v2ascii!(~[40, 32, 59]).into_bytes(), ~[40u8, 32u8, 59u8]);
586 #[test] #[should_fail]
587 fn test_ascii_vec_fail_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii(); }
589 #[test] #[should_fail]
590 fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }
592 #[test] #[should_fail]
593 fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }
595 #[test] #[should_fail]
596 fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
600 assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
601 assert_eq!(255u8.to_ascii_opt(), None);
603 assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
604 assert_eq!('λ'.to_ascii_opt(), None);
606 assert_eq!("zoä华".to_ascii_opt(), None);
608 let test1 = &[127u8, 128u8, 255u8];
609 assert_eq!((test1).to_ascii_opt(), None);
611 let v = [40u8, 32u8, 59u8];
612 let v2 = v2ascii!(&[40, 32, 59]);
613 assert_eq!(v.to_ascii_opt(), Some(v2));
614 let v = [127u8, 128u8, 255u8];
615 assert_eq!(v.to_ascii_opt(), None);
618 let v2 = v2ascii!(&[40, 32, 59]);
619 assert_eq!(v.to_ascii_opt(), Some(v2));
620 assert_eq!("zoä华".to_ascii_opt(), None);
622 assert_eq!((~[40u8, 32u8, 59u8]).into_ascii_opt(), Some(v2ascii!(~[40, 32, 59])));
623 assert_eq!((~[127u8, 128u8, 255u8]).into_ascii_opt(), None);
625 assert_eq!((~"( ;").into_ascii_opt(), Some(v2ascii!(~[40, 32, 59])));
626 assert_eq!((~"zoä华").into_ascii_opt(), None);
630 fn test_to_ascii_upper() {
631 assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), ~"URL()URL()URL()üRL");
632 assert_eq!("hıKß".to_ascii_upper(), ~"HıKß");
636 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
638 assert_eq!(from_char(from_u32(i).unwrap()).to_ascii_upper(),
639 from_char(from_u32(upper).unwrap()))
645 fn test_to_ascii_lower() {
646 assert_eq!("url()URL()uRl()Ürl".to_ascii_lower(), ~"url()url()url()Ürl");
647 // Dotted capital I, Kelvin sign, Sharp S.
648 assert_eq!("HİKß".to_ascii_lower(), ~"hİKß");
652 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
654 assert_eq!(from_char(from_u32(i).unwrap()).to_ascii_lower(),
655 from_char(from_u32(lower).unwrap()))
661 fn test_into_ascii_upper() {
662 assert_eq!((~"url()URL()uRl()ürl").into_ascii_upper(), ~"URL()URL()URL()üRL");
663 assert_eq!((~"hıKß").into_ascii_upper(), ~"HıKß");
667 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
669 assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_upper(),
670 from_char(from_u32(upper).unwrap()))
676 fn test_into_ascii_lower() {
677 assert_eq!((~"url()URL()uRl()Ürl").into_ascii_lower(), ~"url()url()url()Ürl");
678 // Dotted capital I, Kelvin sign, Sharp S.
679 assert_eq!((~"HİKß").into_ascii_lower(), ~"hİKß");
683 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
685 assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_lower(),
686 from_char(from_u32(lower).unwrap()))
692 fn test_eq_ignore_ascii_case() {
693 assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
694 assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
695 // Dotted capital I, Kelvin sign, Sharp S.
696 assert!("HİKß".eq_ignore_ascii_case("hİKß"));
697 assert!(!"İ".eq_ignore_ascii_case("i"));
698 assert!(!"K".eq_ignore_ascii_case("k"));
699 assert!(!"ß".eq_ignore_ascii_case("s"));
704 let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 }
706 assert!(from_char(from_u32(i).unwrap()).
707 eq_ignore_ascii_case(from_char(from_u32(lower).unwrap())));
714 let s = Ascii{ chr: 't' as u8 }.to_str();
720 let c = Ascii { chr: 't' as u8 };
721 assert_eq!(format!("{}", c), ~"t");