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 container::Container;
17 use option::{Option, Some, None};
18 use slice::{ImmutableVector, MutableVector, Vector};
19 use str::{OwnedStr, Str, StrAllocating, StrSlice};
22 use to_str::{IntoStr};
25 /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
26 #[deriving(Clone, Eq, Ord, TotalOrd, TotalEq, Hash)]
27 pub struct Ascii { chr: u8 }
30 /// Converts an ascii character into a `u8`.
32 pub fn to_byte(self) -> u8 {
36 /// Converts an ascii character into a `char`.
38 pub fn to_char(self) -> char {
42 /// Convert to lowercase.
44 pub fn to_lower(self) -> Ascii {
45 Ascii{chr: ASCII_LOWER_MAP[self.chr as uint]}
48 /// Convert to uppercase.
50 pub fn to_upper(self) -> Ascii {
51 Ascii{chr: ASCII_UPPER_MAP[self.chr as uint]}
54 /// Compares two ascii characters of equality, ignoring case.
56 pub fn eq_ignore_case(self, other: Ascii) -> bool {
57 ASCII_LOWER_MAP[self.chr as uint] == ASCII_LOWER_MAP[other.chr as uint]
60 // the following methods are like ctype, and the implementation is inspired by musl
62 /// Check if the character is a letter (a-z, A-Z)
64 pub fn is_alpha(&self) -> bool {
65 (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
68 /// Check if the character is a number (0-9)
70 pub fn is_digit(&self) -> bool {
71 self.chr >= 0x30 && self.chr <= 0x39
74 /// Check if the character is a letter or number
76 pub fn is_alnum(&self) -> bool {
77 self.is_alpha() || self.is_digit()
80 /// Check if the character is a space or horizontal tab
82 pub fn is_blank(&self) -> bool {
83 self.chr == ' ' as u8 || self.chr == '\t' as u8
86 /// Check if the character is a control character
88 pub fn is_control(&self) -> bool {
89 self.chr < 0x20 || self.chr == 0x7F
92 /// Checks if the character is printable (except space)
94 pub fn is_graph(&self) -> bool {
95 (self.chr - 0x21) < 0x5E
98 /// Checks if the character is printable (including space)
100 pub fn is_print(&self) -> bool {
101 (self.chr - 0x20) < 0x5F
104 /// Checks if the character is lowercase
106 pub fn is_lower(&self) -> bool {
107 (self.chr - 'a' as u8) < 26
110 /// Checks if the character is uppercase
112 pub fn is_upper(&self) -> bool {
113 (self.chr - 'A' as u8) < 26
116 /// Checks if the character is punctuation
118 pub fn is_punctuation(&self) -> bool {
119 self.is_graph() && !self.is_alnum()
122 /// Checks if the character is a valid hex digit
124 pub fn is_hex(&self) -> bool {
125 self.is_digit() || ((self.chr | 32u8) - 'a' as u8) < 6
129 impl<'a> fmt::Show for Ascii {
130 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131 (self.chr as char).fmt(f)
135 /// Trait for converting into an ascii type.
136 pub trait AsciiCast<T> {
137 /// Convert to an ascii type, fail on non-ASCII input.
139 fn to_ascii(&self) -> T {
140 assert!(self.is_ascii());
141 unsafe {self.to_ascii_nocheck()}
144 /// Convert to an ascii type, return None on non-ASCII input.
146 fn to_ascii_opt(&self) -> Option<T> {
148 Some(unsafe { self.to_ascii_nocheck() })
154 /// Convert to an ascii type, not doing any range asserts
155 unsafe fn to_ascii_nocheck(&self) -> T;
157 /// Check if convertible to ascii
158 fn is_ascii(&self) -> bool;
161 impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] {
163 unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
164 mem::transmute(*self)
168 fn is_ascii(&self) -> bool {
169 for b in self.iter() {
170 if !b.is_ascii() { return false; }
176 impl<'a> AsciiCast<&'a [Ascii]> for &'a str {
178 unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
179 mem::transmute(*self)
183 fn is_ascii(&self) -> bool {
184 self.bytes().all(|b| b.is_ascii())
188 impl AsciiCast<Ascii> for u8 {
190 unsafe fn to_ascii_nocheck(&self) -> Ascii {
195 fn is_ascii(&self) -> bool {
200 impl AsciiCast<Ascii> for char {
202 unsafe fn to_ascii_nocheck(&self) -> Ascii {
203 Ascii{ chr: *self as u8 }
207 fn is_ascii(&self) -> bool {
208 *self as u32 - ('\x7F' as u32 & *self as u32) == 0
212 /// Trait for copyless casting to an ascii vector.
213 pub trait OwnedAsciiCast {
214 /// Check if convertible to ascii
215 fn is_ascii(&self) -> bool;
217 /// Take ownership and cast to an ascii vector. Fail on non-ASCII input.
219 fn into_ascii(self) -> Vec<Ascii> {
220 assert!(self.is_ascii());
221 unsafe {self.into_ascii_nocheck()}
224 /// Take ownership and cast to an ascii vector. Return None on non-ASCII input.
226 fn into_ascii_opt(self) -> Option<Vec<Ascii>> {
228 Some(unsafe { self.into_ascii_nocheck() })
234 /// Take ownership and cast to an ascii vector.
235 /// Does not perform validation checks.
236 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
239 impl OwnedAsciiCast for ~[u8] {
241 fn is_ascii(&self) -> bool {
242 self.as_slice().is_ascii()
246 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
247 mem::transmute(Vec::from_slice(self.as_slice()))
251 impl OwnedAsciiCast for StrBuf {
253 fn is_ascii(&self) -> bool {
254 self.as_slice().is_ascii()
258 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
259 let v: Vec<u8> = mem::transmute(self);
260 v.into_ascii_nocheck()
264 impl OwnedAsciiCast for Vec<u8> {
266 fn is_ascii(&self) -> bool {
267 self.as_slice().is_ascii()
271 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
276 /// Trait for converting an ascii type to a string. Needed to convert
277 /// `&[Ascii]` to `&str`.
279 /// Convert to a string.
280 fn as_str_ascii<'a>(&'a self) -> &'a str;
282 /// Convert to vector representing a lower cased ascii string.
283 fn to_lower(&self) -> Vec<Ascii>;
285 /// Convert to vector representing a upper cased ascii string.
286 fn to_upper(&self) -> Vec<Ascii>;
288 /// Compares two Ascii strings ignoring case.
289 fn eq_ignore_case(self, other: &[Ascii]) -> bool;
292 impl<'a> AsciiStr for &'a [Ascii] {
294 fn as_str_ascii<'a>(&'a self) -> &'a str {
295 unsafe { mem::transmute(*self) }
299 fn to_lower(&self) -> Vec<Ascii> {
300 self.iter().map(|a| a.to_lower()).collect()
304 fn to_upper(&self) -> Vec<Ascii> {
305 self.iter().map(|a| a.to_upper()).collect()
309 fn eq_ignore_case(self, other: &[Ascii]) -> bool {
310 self.iter().zip(other.iter()).all(|(&a, &b)| a.eq_ignore_case(b))
314 impl IntoStr for ~[Ascii] {
316 fn into_str(self) -> StrBuf {
317 let vector: Vec<Ascii> = self.as_slice().iter().map(|x| *x).collect();
322 impl IntoStr for Vec<Ascii> {
324 fn into_str(self) -> StrBuf {
326 let s: &str = mem::transmute(self.as_slice());
332 /// Trait to convert to an owned byte vector by consuming self
333 pub trait IntoBytes {
334 /// Converts to an owned byte vector by consuming self
335 fn into_bytes(self) -> Vec<u8>;
338 impl IntoBytes for Vec<Ascii> {
339 fn into_bytes(self) -> Vec<u8> {
340 unsafe { mem::transmute(self) }
344 /// Extension methods for ASCII-subset only operations on owned strings
345 pub trait OwnedStrAsciiExt {
346 /// Convert the string to ASCII upper case:
347 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
348 /// but non-ASCII letters are unchanged.
349 fn into_ascii_upper(self) -> StrBuf;
351 /// Convert the string to ASCII lower case:
352 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
353 /// but non-ASCII letters are unchanged.
354 fn into_ascii_lower(self) -> StrBuf;
357 /// Extension methods for ASCII-subset only operations on string slices
358 pub trait StrAsciiExt {
359 /// Makes a copy of the string in ASCII upper case:
360 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
361 /// but non-ASCII letters are unchanged.
362 fn to_ascii_upper(&self) -> StrBuf;
364 /// Makes a copy of the string in ASCII lower case:
365 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
366 /// but non-ASCII letters are unchanged.
367 fn to_ascii_lower(&self) -> StrBuf;
369 /// Check that two strings are an ASCII case-insensitive match.
370 /// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
371 /// but without allocating and copying temporary strings.
372 fn eq_ignore_ascii_case(&self, other: &str) -> bool;
375 impl<'a> StrAsciiExt for &'a str {
377 fn to_ascii_upper(&self) -> StrBuf {
378 unsafe { str_copy_map_bytes(*self, ASCII_UPPER_MAP) }
382 fn to_ascii_lower(&self) -> StrBuf {
383 unsafe { str_copy_map_bytes(*self, ASCII_LOWER_MAP) }
387 fn eq_ignore_ascii_case(&self, other: &str) -> bool {
388 self.len() == other.len() &&
389 self.as_bytes().iter().zip(other.as_bytes().iter()).all(
390 |(byte_self, byte_other)| {
391 ASCII_LOWER_MAP[*byte_self as uint] ==
392 ASCII_LOWER_MAP[*byte_other as uint]
397 impl OwnedStrAsciiExt for StrBuf {
399 fn into_ascii_upper(self) -> StrBuf {
400 unsafe { str_map_bytes(self, ASCII_UPPER_MAP) }
404 fn into_ascii_lower(self) -> StrBuf {
405 unsafe { str_map_bytes(self, ASCII_LOWER_MAP) }
410 unsafe fn str_map_bytes(string: StrBuf, map: &'static [u8]) -> StrBuf {
411 let mut bytes = string.into_bytes();
413 for b in bytes.mut_iter() {
414 *b = map[*b as uint];
417 str::from_utf8(bytes.as_slice()).unwrap().to_strbuf()
421 unsafe fn str_copy_map_bytes(string: &str, map: &'static [u8]) -> StrBuf {
422 let mut s = string.to_strbuf();
423 for b in s.as_mut_bytes().mut_iter() {
424 *b = map[*b as uint];
429 static ASCII_LOWER_MAP: &'static [u8] = &[
430 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
431 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
432 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
433 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
434 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
435 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
436 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
437 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
438 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
439 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
440 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
441 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
442 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
443 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
444 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
445 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
446 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
447 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
448 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
449 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
450 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
451 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
452 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
453 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
454 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
455 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
456 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
457 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
458 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
459 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
460 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
461 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
464 static ASCII_UPPER_MAP: &'static [u8] = &[
465 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
466 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
467 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
468 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
469 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
470 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
471 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
472 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
473 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
474 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
475 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
476 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
477 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
478 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
479 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
480 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
481 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
482 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
483 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
484 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
485 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
486 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
487 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
488 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
489 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
490 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
491 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
492 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
493 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
494 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
495 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
496 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
509 macro_rules! v2ascii (
510 ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
511 (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
514 macro_rules! vec2ascii (
515 ($($e:expr),*) => (Vec::from_slice([$(Ascii{chr:$e}),*]));
520 assert_eq!(65u8.to_ascii().to_byte(), 65u8);
521 assert_eq!(65u8.to_ascii().to_char(), 'A');
522 assert_eq!('A'.to_ascii().to_char(), 'A');
523 assert_eq!('A'.to_ascii().to_byte(), 65u8);
525 assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
526 assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
527 assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
528 assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');
530 assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
531 assert_eq!('['.to_ascii().to_lower().to_char(), '[');
532 assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
533 assert_eq!('{'.to_ascii().to_upper().to_char(), '{');
535 assert!('0'.to_ascii().is_digit());
536 assert!('9'.to_ascii().is_digit());
537 assert!(!'/'.to_ascii().is_digit());
538 assert!(!':'.to_ascii().is_digit());
540 assert!((0x1fu8).to_ascii().is_control());
541 assert!(!' '.to_ascii().is_control());
542 assert!((0x7fu8).to_ascii().is_control());
544 assert!("banana".chars().all(|c| c.is_ascii()));
545 assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
549 fn test_ascii_vec() {
550 let test = &[40u8, 32u8, 59u8];
551 assert_eq!(test.to_ascii(), v2ascii!([40, 32, 59]));
552 assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59]));
553 // FIXME: #5475 borrowchk error, owned vectors do not live long enough
554 // if chained-from directly
555 let v = box [40u8, 32u8, 59u8];
556 assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
557 let v = "( ;".to_strbuf();
558 assert_eq!(v.as_slice().to_ascii(), v2ascii!([40, 32, 59]));
560 assert_eq!("abCDef&?#".to_ascii().to_lower().into_str(), "abcdef&?#".to_strbuf());
561 assert_eq!("abCDef&?#".to_ascii().to_upper().into_str(), "ABCDEF&?#".to_strbuf());
563 assert_eq!("".to_ascii().to_lower().into_str(), "".to_strbuf());
564 assert_eq!("YMCA".to_ascii().to_lower().into_str(), "ymca".to_strbuf());
565 assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_str(), "ABCDEFXYZ:.;".to_strbuf());
567 assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
569 assert!("".is_ascii());
570 assert!("a".is_ascii());
571 assert!(!"\u2009".is_ascii());
576 fn test_ascii_vec_ng() {
577 assert_eq!("abCDef&?#".to_ascii().to_lower().into_str(), "abcdef&?#".to_strbuf());
578 assert_eq!("abCDef&?#".to_ascii().to_upper().into_str(), "ABCDEF&?#".to_strbuf());
579 assert_eq!("".to_ascii().to_lower().into_str(), "".to_strbuf());
580 assert_eq!("YMCA".to_ascii().to_lower().into_str(), "ymca".to_strbuf());
581 assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_str(), "ABCDEFXYZ:.;".to_strbuf());
585 fn test_owned_ascii_vec() {
586 assert_eq!(("( ;".to_strbuf()).into_ascii(), vec2ascii![40, 32, 59]);
587 assert_eq!((box [40u8, 32u8, 59u8]).into_ascii(), vec2ascii![40, 32, 59]);
591 fn test_ascii_as_str() {
592 let v = v2ascii!([40, 32, 59]);
593 assert_eq!(v.as_str_ascii(), "( ;");
597 fn test_ascii_into_str() {
598 assert_eq!(vec2ascii![40, 32, 59].into_str(), "( ;".to_strbuf());
599 assert_eq!(vec2ascii!(40, 32, 59).into_str(), "( ;".to_strbuf());
603 fn test_ascii_to_bytes() {
604 assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
607 #[test] #[should_fail]
608 fn test_ascii_vec_fail_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii(); }
610 #[test] #[should_fail]
611 fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }
613 #[test] #[should_fail]
614 fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }
616 #[test] #[should_fail]
617 fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
621 assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
622 assert_eq!(255u8.to_ascii_opt(), None);
624 assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
625 assert_eq!('λ'.to_ascii_opt(), None);
627 assert_eq!("zoä华".to_ascii_opt(), None);
629 let test1 = &[127u8, 128u8, 255u8];
630 assert_eq!((test1).to_ascii_opt(), None);
632 let v = [40u8, 32u8, 59u8];
633 let v2 = v2ascii!(&[40, 32, 59]);
634 assert_eq!(v.to_ascii_opt(), Some(v2));
635 let v = [127u8, 128u8, 255u8];
636 assert_eq!(v.to_ascii_opt(), None);
639 let v2 = v2ascii!(&[40, 32, 59]);
640 assert_eq!(v.to_ascii_opt(), Some(v2));
641 assert_eq!("zoä华".to_ascii_opt(), None);
643 assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
644 assert_eq!((vec![127u8, 128u8, 255u8]).into_ascii_opt(), None);
646 assert_eq!(("( ;".to_strbuf()).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
647 assert_eq!(("zoä华".to_strbuf()).into_ascii_opt(), None);
651 fn test_to_ascii_upper() {
652 assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), "URL()URL()URL()üRL".to_strbuf());
653 assert_eq!("hıKß".to_ascii_upper(), "HıKß".to_strbuf());
657 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
659 assert_eq!(from_char(from_u32(i).unwrap()).as_slice().to_ascii_upper(),
660 from_char(from_u32(upper).unwrap()).to_strbuf())
666 fn test_to_ascii_lower() {
667 assert_eq!("url()URL()uRl()Ürl".to_ascii_lower(), "url()url()url()Ürl".to_strbuf());
668 // Dotted capital I, Kelvin sign, Sharp S.
669 assert_eq!("HİKß".to_ascii_lower(), "hİKß".to_strbuf());
673 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
675 assert_eq!(from_char(from_u32(i).unwrap()).as_slice().to_ascii_lower(),
676 from_char(from_u32(lower).unwrap()).to_strbuf())
682 fn test_into_ascii_upper() {
683 assert_eq!(("url()URL()uRl()ürl".to_strbuf()).into_ascii_upper(),
684 "URL()URL()URL()üRL".to_strbuf());
685 assert_eq!(("hıKß".to_strbuf()).into_ascii_upper(), "HıKß".to_strbuf());
689 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
691 assert_eq!(from_char(from_u32(i).unwrap()).to_strbuf().into_ascii_upper(),
692 from_char(from_u32(upper).unwrap()).to_strbuf())
698 fn test_into_ascii_lower() {
699 assert_eq!(("url()URL()uRl()Ürl".to_strbuf()).into_ascii_lower(),
700 "url()url()url()Ürl".to_strbuf());
701 // Dotted capital I, Kelvin sign, Sharp S.
702 assert_eq!(("HİKß".to_strbuf()).into_ascii_lower(), "hİKß".to_strbuf());
706 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
708 assert_eq!(from_char(from_u32(i).unwrap()).to_strbuf().into_ascii_lower(),
709 from_char(from_u32(lower).unwrap()).to_strbuf())
715 fn test_eq_ignore_ascii_case() {
716 assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
717 assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
718 // Dotted capital I, Kelvin sign, Sharp S.
719 assert!("HİKß".eq_ignore_ascii_case("hİKß"));
720 assert!(!"İ".eq_ignore_ascii_case("i"));
721 assert!(!"K".eq_ignore_ascii_case("k"));
722 assert!(!"ß".eq_ignore_ascii_case("s"));
727 let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 }
729 assert!(from_char(from_u32(i).unwrap()).as_slice()
730 .eq_ignore_ascii_case(
733 .unwrap()).as_slice()));
740 let s = Ascii{ chr: 't' as u8 }.to_str();
741 assert_eq!(s, "t".to_strbuf());
746 let c = Ascii { chr: 't' as u8 };
747 assert_eq!(format_strbuf!("{}", c), "t".to_strbuf());