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 // ignore-lexer-test FIXME #15679
13 //! Operations on ASCII strings and characters
17 use collections::Collection;
21 use option::{Option, Some, None};
22 use slice::{ImmutableVector, MutableVector, Vector};
23 use str::{Str, StrAllocating, StrSlice};
25 use to_string::IntoStr;
28 /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
29 #[deriving(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
30 pub struct Ascii { chr: u8 }
33 /// Converts an ascii character into a `u8`.
35 pub fn to_byte(self) -> u8 {
39 /// Converts an ascii character into a `char`.
41 pub fn to_char(self) -> char {
47 #[deprecated="renamed to `to_lowercase`"]
48 pub fn to_lower(self) -> Ascii {
52 /// Convert to lowercase.
54 pub fn to_lowercase(self) -> Ascii {
55 Ascii{chr: ASCII_LOWER_MAP[self.chr as uint]}
60 #[deprecated="renamed to `to_uppercase`"]
61 pub fn to_upper(self) -> Ascii {
65 /// Convert to uppercase.
67 pub fn to_uppercase(self) -> Ascii {
68 Ascii{chr: ASCII_UPPER_MAP[self.chr as uint]}
71 /// Compares two ascii characters of equality, ignoring case.
73 pub fn eq_ignore_case(self, other: Ascii) -> bool {
74 ASCII_LOWER_MAP[self.chr as uint] == ASCII_LOWER_MAP[other.chr as uint]
77 // the following methods are like ctype, and the implementation is inspired by musl
81 #[deprecated="renamed to `is_alphabetic`"]
82 pub fn is_alpha(&self) -> bool {
86 /// Check if the character is a letter (a-z, A-Z)
88 pub fn is_alphabetic(&self) -> bool {
89 (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
92 /// Check if the character is a number (0-9)
94 pub fn is_digit(&self) -> bool {
95 self.chr >= 0x30 && self.chr <= 0x39
100 #[deprecated="renamed to `is_alphanumeric`"]
101 pub fn is_alnum(&self) -> bool {
102 self.is_alphanumeric()
105 /// Check if the character is a letter or number
107 pub fn is_alphanumeric(&self) -> bool {
108 self.is_alpha() || self.is_digit()
111 /// Check if the character is a space or horizontal tab
113 pub fn is_blank(&self) -> bool {
114 self.chr == ' ' as u8 || self.chr == '\t' as u8
117 /// Check if the character is a control character
119 pub fn is_control(&self) -> bool {
120 self.chr < 0x20 || self.chr == 0x7F
123 /// Checks if the character is printable (except space)
125 pub fn is_graph(&self) -> bool {
126 (self.chr - 0x21) < 0x5E
129 /// Checks if the character is printable (including space)
131 pub fn is_print(&self) -> bool {
132 (self.chr - 0x20) < 0x5F
136 #[allow(missing_doc)]
137 #[deprecated="renamed to `is_lowercase`"]
138 pub fn is_lower(&self) -> bool {
142 /// Checks if the character is lowercase
144 pub fn is_lowercase(&self) -> bool {
145 (self.chr - 'a' as u8) < 26
149 #[allow(missing_doc)]
150 #[deprecated="renamed to `is_uppercase`"]
151 pub fn is_upper(&self) -> bool {
155 /// Checks if the character is uppercase
157 pub fn is_uppercase(&self) -> bool {
158 (self.chr - 'A' as u8) < 26
161 /// Checks if the character is punctuation
163 pub fn is_punctuation(&self) -> bool {
164 self.is_graph() && !self.is_alnum()
167 /// Checks if the character is a valid hex digit
169 pub fn is_hex(&self) -> bool {
170 self.is_digit() || ((self.chr | 32u8) - 'a' as u8) < 6
174 impl<'a> fmt::Show for Ascii {
175 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176 (self.chr as char).fmt(f)
180 /// Trait for converting into an ascii type.
181 pub trait AsciiCast<T> {
182 /// Convert to an ascii type, fail on non-ASCII input.
184 fn to_ascii(&self) -> T {
185 assert!(self.is_ascii());
186 unsafe {self.to_ascii_nocheck()}
189 /// Convert to an ascii type, return None on non-ASCII input.
191 fn to_ascii_opt(&self) -> Option<T> {
193 Some(unsafe { self.to_ascii_nocheck() })
199 /// Convert to an ascii type, not doing any range asserts
200 unsafe fn to_ascii_nocheck(&self) -> T;
202 /// Check if convertible to ascii
203 fn is_ascii(&self) -> bool;
206 impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] {
208 unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
209 mem::transmute(*self)
213 fn is_ascii(&self) -> bool {
214 for b in self.iter() {
215 if !b.is_ascii() { return false; }
221 impl<'a> AsciiCast<&'a [Ascii]> for &'a str {
223 unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
224 mem::transmute(*self)
228 fn is_ascii(&self) -> bool {
229 self.bytes().all(|b| b.is_ascii())
233 impl AsciiCast<Ascii> for u8 {
235 unsafe fn to_ascii_nocheck(&self) -> Ascii {
240 fn is_ascii(&self) -> bool {
245 impl AsciiCast<Ascii> for char {
247 unsafe fn to_ascii_nocheck(&self) -> Ascii {
248 Ascii{ chr: *self as u8 }
252 fn is_ascii(&self) -> bool {
253 *self as u32 - ('\x7F' as u32 & *self as u32) == 0
257 /// Trait for copyless casting to an ascii vector.
258 pub trait OwnedAsciiCast {
259 /// Check if convertible to ascii
260 fn is_ascii(&self) -> bool;
262 /// Take ownership and cast to an ascii vector. Fail on non-ASCII input.
264 fn into_ascii(self) -> Vec<Ascii> {
265 assert!(self.is_ascii());
266 unsafe {self.into_ascii_nocheck()}
269 /// Take ownership and cast to an ascii vector. Return None on non-ASCII input.
271 fn into_ascii_opt(self) -> Option<Vec<Ascii>> {
273 Some(unsafe { self.into_ascii_nocheck() })
279 /// Take ownership and cast to an ascii vector.
280 /// Does not perform validation checks.
281 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
284 impl OwnedAsciiCast for String {
286 fn is_ascii(&self) -> bool {
287 self.as_slice().is_ascii()
291 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
292 let v: Vec<u8> = mem::transmute(self);
293 v.into_ascii_nocheck()
297 impl OwnedAsciiCast for Vec<u8> {
299 fn is_ascii(&self) -> bool {
300 self.as_slice().is_ascii()
304 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
309 /// Trait for converting an ascii type to a string. Needed to convert
310 /// `&[Ascii]` to `&str`.
312 /// Convert to a string.
313 fn as_str_ascii<'a>(&'a self) -> &'a str;
315 /// Convert to vector representing a lower cased ascii string.
316 fn to_lower(&self) -> Vec<Ascii>;
318 /// Convert to vector representing a upper cased ascii string.
319 fn to_upper(&self) -> Vec<Ascii>;
321 /// Compares two Ascii strings ignoring case.
322 fn eq_ignore_case(self, other: &[Ascii]) -> bool;
325 impl<'a> AsciiStr for &'a [Ascii] {
327 fn as_str_ascii<'a>(&'a self) -> &'a str {
328 unsafe { mem::transmute(*self) }
332 fn to_lower(&self) -> Vec<Ascii> {
333 self.iter().map(|a| a.to_lower()).collect()
337 fn to_upper(&self) -> Vec<Ascii> {
338 self.iter().map(|a| a.to_upper()).collect()
342 fn eq_ignore_case(self, other: &[Ascii]) -> bool {
343 self.iter().zip(other.iter()).all(|(&a, &b)| a.eq_ignore_case(b))
347 impl IntoStr for Vec<Ascii> {
349 fn into_string(self) -> String {
351 let s: &str = mem::transmute(self.as_slice());
357 /// Trait to convert to an owned byte vector by consuming self
358 pub trait IntoBytes {
359 /// Converts to an owned byte vector by consuming self
360 fn into_bytes(self) -> Vec<u8>;
363 impl IntoBytes for Vec<Ascii> {
364 fn into_bytes(self) -> Vec<u8> {
365 unsafe { mem::transmute(self) }
369 /// Extension methods for ASCII-subset only operations on owned strings
370 pub trait OwnedStrAsciiExt {
371 /// Convert the string to ASCII upper case:
372 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
373 /// but non-ASCII letters are unchanged.
374 fn into_ascii_upper(self) -> String;
376 /// Convert the string to ASCII lower case:
377 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
378 /// but non-ASCII letters are unchanged.
379 fn into_ascii_lower(self) -> String;
382 /// Extension methods for ASCII-subset only operations on string slices
383 pub trait StrAsciiExt {
384 /// Makes a copy of the string in ASCII upper case:
385 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
386 /// but non-ASCII letters are unchanged.
387 fn to_ascii_upper(&self) -> String;
389 /// Makes a copy of the string in ASCII lower case:
390 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
391 /// but non-ASCII letters are unchanged.
392 fn to_ascii_lower(&self) -> String;
394 /// Check that two strings are an ASCII case-insensitive match.
395 /// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
396 /// but without allocating and copying temporary strings.
397 fn eq_ignore_ascii_case(&self, other: &str) -> bool;
400 impl<'a> StrAsciiExt for &'a str {
402 fn to_ascii_upper(&self) -> String {
403 unsafe { str_copy_map_bytes(*self, ASCII_UPPER_MAP) }
407 fn to_ascii_lower(&self) -> String {
408 unsafe { str_copy_map_bytes(*self, ASCII_LOWER_MAP) }
412 fn eq_ignore_ascii_case(&self, other: &str) -> bool {
413 self.len() == other.len() &&
414 self.as_bytes().iter().zip(other.as_bytes().iter()).all(
415 |(byte_self, byte_other)| {
416 ASCII_LOWER_MAP[*byte_self as uint] ==
417 ASCII_LOWER_MAP[*byte_other as uint]
422 impl OwnedStrAsciiExt for String {
424 fn into_ascii_upper(self) -> String {
425 unsafe { str_map_bytes(self, ASCII_UPPER_MAP) }
429 fn into_ascii_lower(self) -> String {
430 unsafe { str_map_bytes(self, ASCII_LOWER_MAP) }
435 unsafe fn str_map_bytes(string: String, map: &'static [u8]) -> String {
436 let mut bytes = string.into_bytes();
438 for b in bytes.mut_iter() {
439 *b = map[*b as uint];
442 String::from_utf8(bytes).unwrap()
446 unsafe fn str_copy_map_bytes(string: &str, map: &'static [u8]) -> String {
447 let mut s = String::from_str(string);
448 for b in s.as_mut_bytes().mut_iter() {
449 *b = map[*b as uint];
454 static ASCII_LOWER_MAP: &'static [u8] = &[
455 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
456 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
457 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
458 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
459 b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
460 b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
461 b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
462 b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
465 b'a', b'b', b'c', b'd', b'e', b'f', b'g',
466 b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
467 b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
470 b'[', b'\\', b']', b'^', b'_',
471 b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g',
472 b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
473 b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
474 b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f,
475 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
476 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
477 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
478 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
479 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
480 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
481 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
482 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
483 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
484 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
485 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
486 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
487 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
488 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
489 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
490 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
493 static ASCII_UPPER_MAP: &'static [u8] = &[
494 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
495 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
496 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
497 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
498 b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
499 b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
500 b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
501 b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
502 b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
503 b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
504 b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
505 b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
508 b'A', b'B', b'C', b'D', b'E', b'F', b'G',
509 b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
510 b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
513 b'{', b'|', b'}', b'~', 0x7f,
514 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
515 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
516 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
517 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
518 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
519 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
520 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
521 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
522 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
523 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
524 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
525 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
526 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
527 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
528 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
529 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
541 macro_rules! v2ascii (
542 ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
543 (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
546 macro_rules! vec2ascii (
547 ($($e:expr),*) => (Vec::from_slice([$(Ascii{chr:$e}),*]));
552 assert_eq!(65u8.to_ascii().to_byte(), 65u8);
553 assert_eq!(65u8.to_ascii().to_char(), 'A');
554 assert_eq!('A'.to_ascii().to_char(), 'A');
555 assert_eq!('A'.to_ascii().to_byte(), 65u8);
557 assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
558 assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
559 assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
560 assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');
562 assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
563 assert_eq!('['.to_ascii().to_lower().to_char(), '[');
564 assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
565 assert_eq!('{'.to_ascii().to_upper().to_char(), '{');
567 assert!('0'.to_ascii().is_digit());
568 assert!('9'.to_ascii().is_digit());
569 assert!(!'/'.to_ascii().is_digit());
570 assert!(!':'.to_ascii().is_digit());
572 assert!((0x1fu8).to_ascii().is_control());
573 assert!(!' '.to_ascii().is_control());
574 assert!((0x7fu8).to_ascii().is_control());
576 assert!("banana".chars().all(|c| c.is_ascii()));
577 assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
581 fn test_ascii_vec() {
582 let test = &[40u8, 32u8, 59u8];
583 assert_eq!(test.to_ascii(), v2ascii!([40, 32, 59]));
584 assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59]));
585 let v = vec![40u8, 32u8, 59u8];
586 assert_eq!(v.as_slice().to_ascii(), v2ascii!([40, 32, 59]));
587 assert_eq!("( ;".to_string().as_slice().to_ascii(), v2ascii!([40, 32, 59]));
589 assert_eq!("abCDef&?#".to_ascii().to_lower().into_string(), "abcdef&?#".to_string());
590 assert_eq!("abCDef&?#".to_ascii().to_upper().into_string(), "ABCDEF&?#".to_string());
592 assert_eq!("".to_ascii().to_lower().into_string(), "".to_string());
593 assert_eq!("YMCA".to_ascii().to_lower().into_string(), "ymca".to_string());
594 assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_string(), "ABCDEFXYZ:.;".to_string());
596 assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
598 assert!("".is_ascii());
599 assert!("a".is_ascii());
600 assert!(!"\u2009".is_ascii());
605 fn test_ascii_vec_ng() {
606 assert_eq!("abCDef&?#".to_ascii().to_lower().into_string(), "abcdef&?#".to_string());
607 assert_eq!("abCDef&?#".to_ascii().to_upper().into_string(), "ABCDEF&?#".to_string());
608 assert_eq!("".to_ascii().to_lower().into_string(), "".to_string());
609 assert_eq!("YMCA".to_ascii().to_lower().into_string(), "ymca".to_string());
610 assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_string(), "ABCDEFXYZ:.;".to_string());
614 fn test_owned_ascii_vec() {
615 assert_eq!(("( ;".to_string()).into_ascii(), vec2ascii![40, 32, 59]);
616 assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii(), vec2ascii![40, 32, 59]);
620 fn test_ascii_as_str() {
621 let v = v2ascii!([40, 32, 59]);
622 assert_eq!(v.as_str_ascii(), "( ;");
626 fn test_ascii_into_string() {
627 assert_eq!(vec2ascii![40, 32, 59].into_string(), "( ;".to_string());
628 assert_eq!(vec2ascii!(40, 32, 59).into_string(), "( ;".to_string());
632 fn test_ascii_to_bytes() {
633 assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
636 #[test] #[should_fail]
637 fn test_ascii_vec_fail_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii(); }
639 #[test] #[should_fail]
640 fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }
642 #[test] #[should_fail]
643 fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }
645 #[test] #[should_fail]
646 fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
650 assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
651 assert_eq!(255u8.to_ascii_opt(), None);
653 assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
654 assert_eq!('λ'.to_ascii_opt(), None);
656 assert_eq!("zoä华".to_ascii_opt(), None);
658 let test1 = &[127u8, 128u8, 255u8];
659 assert_eq!((test1).to_ascii_opt(), None);
661 let v = [40u8, 32u8, 59u8];
662 let v2 = v2ascii!(&[40, 32, 59]);
663 assert_eq!(v.to_ascii_opt(), Some(v2));
664 let v = [127u8, 128u8, 255u8];
665 assert_eq!(v.to_ascii_opt(), None);
668 let v2 = v2ascii!(&[40, 32, 59]);
669 assert_eq!(v.to_ascii_opt(), Some(v2));
670 assert_eq!("zoä华".to_ascii_opt(), None);
672 assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
673 assert_eq!((vec![127u8, 128u8, 255u8]).into_ascii_opt(), None);
675 assert_eq!(("( ;".to_string()).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
676 assert_eq!(("zoä华".to_string()).into_ascii_opt(), None);
680 fn test_to_ascii_upper() {
681 assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), "URL()URL()URL()üRL".to_string());
682 assert_eq!("hıKß".to_ascii_upper(), "HıKß".to_string());
686 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
688 assert_eq!((from_u32(i).unwrap()).to_string().as_slice().to_ascii_upper(),
689 (from_u32(upper).unwrap()).to_string())
695 fn test_to_ascii_lower() {
696 assert_eq!("url()URL()uRl()Ürl".to_ascii_lower(), "url()url()url()Ürl".to_string());
697 // Dotted capital I, Kelvin sign, Sharp S.
698 assert_eq!("HİKß".to_ascii_lower(), "hİKß".to_string());
702 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
704 assert_eq!((from_u32(i).unwrap()).to_string().as_slice().to_ascii_lower(),
705 (from_u32(lower).unwrap()).to_string())
711 fn test_into_ascii_upper() {
712 assert_eq!(("url()URL()uRl()ürl".to_string()).into_ascii_upper(),
713 "URL()URL()URL()üRL".to_string());
714 assert_eq!(("hıKß".to_string()).into_ascii_upper(), "HıKß".to_string());
718 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
720 assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_upper(),
721 (from_u32(upper).unwrap()).to_string())
727 fn test_into_ascii_lower() {
728 assert_eq!(("url()URL()uRl()Ürl".to_string()).into_ascii_lower(),
729 "url()url()url()Ürl".to_string());
730 // Dotted capital I, Kelvin sign, Sharp S.
731 assert_eq!(("HİKß".to_string()).into_ascii_lower(), "hİKß".to_string());
735 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
737 assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_lower(),
738 (from_u32(lower).unwrap()).to_string())
744 fn test_eq_ignore_ascii_case() {
745 assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
746 assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
747 // Dotted capital I, Kelvin sign, Sharp S.
748 assert!("HİKß".eq_ignore_ascii_case("hİKß"));
749 assert!(!"İ".eq_ignore_ascii_case("i"));
750 assert!(!"K".eq_ignore_ascii_case("k"));
751 assert!(!"ß".eq_ignore_ascii_case("s"));
756 let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 }
758 assert!((from_u32(i).unwrap()).to_string().as_slice().eq_ignore_ascii_case(
759 (from_u32(lower).unwrap()).to_string().as_slice()));
765 fn test_to_string() {
766 let s = Ascii{ chr: 't' as u8 }.to_string();
767 assert_eq!(s, "t".to_string());
772 let c = Ascii { chr: 't' as u8 };
773 assert_eq!(format!("{}", c), "t".to_string());