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 { 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 as uint]}
49 /// Convert to uppercase.
51 pub fn to_upper(self) -> Ascii {
52 Ascii{chr: ASCII_UPPER_MAP[self.chr as uint]}
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 as uint] == ASCII_LOWER_MAP[other.chr as uint]
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.iter().map(|a| a.to_lower()).collect()
292 fn to_upper(&self) -> ~[Ascii] {
293 self.iter().map(|a| a.to_upper()).collect()
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() &&
374 self.as_bytes().iter().zip(other.as_bytes().iter()).all(
375 |(byte_self, byte_other)| {
376 ASCII_LOWER_MAP[*byte_self as uint] ==
377 ASCII_LOWER_MAP[*byte_other as uint]
382 impl OwnedStrAsciiExt for ~str {
384 fn into_ascii_upper(self) -> ~str {
385 unsafe { str_map_bytes(self, ASCII_UPPER_MAP) }
389 fn into_ascii_lower(self) -> ~str {
390 unsafe { str_map_bytes(self, ASCII_LOWER_MAP) }
395 unsafe fn str_map_bytes(string: ~str, map: &'static [u8]) -> ~str {
396 let mut bytes = string.into_bytes();
398 for b in bytes.mut_iter() {
399 *b = map[*b as uint];
402 str::raw::from_utf8_owned(bytes)
406 unsafe fn str_copy_map_bytes(string: &str, map: &'static [u8]) -> ~str {
407 let bytes = string.bytes().map(|b| map[b as uint]).collect::<~[_]>();
409 str::raw::from_utf8_owned(bytes)
412 static ASCII_LOWER_MAP: &'static [u8] = &[
413 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
414 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
415 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
416 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
417 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
418 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
419 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
420 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
421 0x40, 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, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
425 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
426 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
427 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
428 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
429 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
430 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
431 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
432 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
433 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
434 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
435 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
436 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
437 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
438 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
439 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
440 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
441 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
442 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
443 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
444 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
447 static ASCII_UPPER_MAP: &'static [u8] = &[
448 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
449 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
450 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
451 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
452 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
453 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
454 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
455 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
456 0x40, 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, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
460 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
461 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
462 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
463 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
464 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
465 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
466 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
467 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
468 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
469 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
470 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
471 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
472 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
473 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
474 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
475 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
476 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
477 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
478 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
479 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
492 macro_rules! v2ascii (
493 ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
494 (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
495 (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
498 macro_rules! vec2ascii (
499 ($($e:expr),*) => (Vec::from_slice([$(Ascii{chr:$e}),*]));
504 assert_eq!(65u8.to_ascii().to_byte(), 65u8);
505 assert_eq!(65u8.to_ascii().to_char(), 'A');
506 assert_eq!('A'.to_ascii().to_char(), 'A');
507 assert_eq!('A'.to_ascii().to_byte(), 65u8);
509 assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
510 assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
511 assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
512 assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');
514 assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
515 assert_eq!('['.to_ascii().to_lower().to_char(), '[');
516 assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
517 assert_eq!('{'.to_ascii().to_upper().to_char(), '{');
519 assert!('0'.to_ascii().is_digit());
520 assert!('9'.to_ascii().is_digit());
521 assert!(!'/'.to_ascii().is_digit());
522 assert!(!':'.to_ascii().is_digit());
524 assert!((0x1fu8).to_ascii().is_control());
525 assert!(!' '.to_ascii().is_control());
526 assert!((0x7fu8).to_ascii().is_control());
528 assert!("banana".chars().all(|c| c.is_ascii()));
529 assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
533 fn test_ascii_vec() {
534 let test = &[40u8, 32u8, 59u8];
535 assert_eq!(test.to_ascii(), v2ascii!([40, 32, 59]));
536 assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59]));
537 // FIXME: #5475 borrowchk error, owned vectors do not live long enough
538 // if chained-from directly
539 let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
540 let v = "( ;".to_owned(); assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
542 assert_eq!("abCDef&?#".to_ascii().to_lower().into_str(), "abcdef&?#".to_owned());
543 assert_eq!("abCDef&?#".to_ascii().to_upper().into_str(), "ABCDEF&?#".to_owned());
545 assert_eq!("".to_ascii().to_lower().into_str(), "".to_owned());
546 assert_eq!("YMCA".to_ascii().to_lower().into_str(), "ymca".to_owned());
547 assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_str(), "ABCDEFXYZ:.;".to_owned());
549 assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
551 assert!("".is_ascii());
552 assert!("a".is_ascii());
553 assert!(!"\u2009".is_ascii());
558 fn test_ascii_vec_ng() {
559 assert_eq!(Vec::from_slice("abCDef&?#".to_ascii().to_lower()).into_str(),
560 "abcdef&?#".to_owned());
561 assert_eq!(Vec::from_slice("abCDef&?#".to_ascii().to_upper()).into_str(),
562 "ABCDEF&?#".to_owned());
563 assert_eq!(Vec::from_slice("".to_ascii().to_lower()).into_str(), "".to_owned());
564 assert_eq!(Vec::from_slice("YMCA".to_ascii().to_lower()).into_str(), "ymca".to_owned());
565 assert_eq!(Vec::from_slice("abcDEFxyz:.;".to_ascii().to_upper()).into_str(),
566 "ABCDEFXYZ:.;".to_owned());
570 fn test_owned_ascii_vec() {
571 assert_eq!(("( ;".to_owned()).into_ascii(), v2ascii!(~[40, 32, 59]));
572 assert_eq!((~[40u8, 32u8, 59u8]).into_ascii(), v2ascii!(~[40, 32, 59]));
576 fn test_ascii_as_str() {
577 let v = v2ascii!([40, 32, 59]);
578 assert_eq!(v.as_str_ascii(), "( ;");
582 fn test_ascii_into_str() {
583 assert_eq!(v2ascii!(~[40, 32, 59]).into_str(), "( ;".to_owned());
584 assert_eq!(vec2ascii!(40, 32, 59).into_str(), "( ;".to_owned());
588 fn test_ascii_to_bytes() {
589 assert_eq!(v2ascii!(~[40, 32, 59]).into_bytes(), ~[40u8, 32u8, 59u8]);
592 #[test] #[should_fail]
593 fn test_ascii_vec_fail_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii(); }
595 #[test] #[should_fail]
596 fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }
598 #[test] #[should_fail]
599 fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }
601 #[test] #[should_fail]
602 fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
606 assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
607 assert_eq!(255u8.to_ascii_opt(), None);
609 assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
610 assert_eq!('λ'.to_ascii_opt(), None);
612 assert_eq!("zoä华".to_ascii_opt(), None);
614 let test1 = &[127u8, 128u8, 255u8];
615 assert_eq!((test1).to_ascii_opt(), None);
617 let v = [40u8, 32u8, 59u8];
618 let v2 = v2ascii!(&[40, 32, 59]);
619 assert_eq!(v.to_ascii_opt(), Some(v2));
620 let v = [127u8, 128u8, 255u8];
621 assert_eq!(v.to_ascii_opt(), None);
624 let v2 = v2ascii!(&[40, 32, 59]);
625 assert_eq!(v.to_ascii_opt(), Some(v2));
626 assert_eq!("zoä华".to_ascii_opt(), None);
628 assert_eq!((~[40u8, 32u8, 59u8]).into_ascii_opt(), Some(v2ascii!(~[40, 32, 59])));
629 assert_eq!((~[127u8, 128u8, 255u8]).into_ascii_opt(), None);
631 assert_eq!(("( ;".to_owned()).into_ascii_opt(), Some(v2ascii!(~[40, 32, 59])));
632 assert_eq!(("zoä华".to_owned()).into_ascii_opt(), None);
636 fn test_to_ascii_upper() {
637 assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), "URL()URL()URL()üRL".to_owned());
638 assert_eq!("hıKß".to_ascii_upper(), "HıKß".to_owned());
642 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
644 assert_eq!(from_char(from_u32(i).unwrap()).to_ascii_upper(),
645 from_char(from_u32(upper).unwrap()))
651 fn test_to_ascii_lower() {
652 assert_eq!("url()URL()uRl()Ürl".to_ascii_lower(), "url()url()url()Ürl".to_owned());
653 // Dotted capital I, Kelvin sign, Sharp S.
654 assert_eq!("HİKß".to_ascii_lower(), "hİKß".to_owned());
658 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
660 assert_eq!(from_char(from_u32(i).unwrap()).to_ascii_lower(),
661 from_char(from_u32(lower).unwrap()))
667 fn test_into_ascii_upper() {
668 assert_eq!(("url()URL()uRl()ürl".to_owned()).into_ascii_upper(),
669 "URL()URL()URL()üRL".to_owned());
670 assert_eq!(("hıKß".to_owned()).into_ascii_upper(), "HıKß".to_owned());
674 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
676 assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_upper(),
677 from_char(from_u32(upper).unwrap()))
683 fn test_into_ascii_lower() {
684 assert_eq!(("url()URL()uRl()Ürl".to_owned()).into_ascii_lower(),
685 "url()url()url()Ürl".to_owned());
686 // Dotted capital I, Kelvin sign, Sharp S.
687 assert_eq!(("HİKß".to_owned()).into_ascii_lower(), "hİKß".to_owned());
691 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
693 assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_lower(),
694 from_char(from_u32(lower).unwrap()))
700 fn test_eq_ignore_ascii_case() {
701 assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
702 assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
703 // Dotted capital I, Kelvin sign, Sharp S.
704 assert!("HİKß".eq_ignore_ascii_case("hİKß"));
705 assert!(!"İ".eq_ignore_ascii_case("i"));
706 assert!(!"K".eq_ignore_ascii_case("k"));
707 assert!(!"ß".eq_ignore_ascii_case("s"));
712 let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 }
714 assert!(from_char(from_u32(i).unwrap()).
715 eq_ignore_ascii_case(from_char(from_u32(lower).unwrap())));
722 let s = Ascii{ chr: 't' as u8 }.to_str();
723 assert_eq!(s, "t".to_owned());
728 let c = Ascii { chr: 't' as u8 };
729 assert_eq!(format!("{}", c), "t".to_owned());