1 // Copyright 2013 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::{ToStr,ToStrConsume};
17 use container::Container;
20 use vec::{ImmutableVector, MutableVector};
21 use to_bytes::IterBytes;
22 use option::{Some, None};
24 /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
25 #[deriving(Clone, Eq, Ord, TotalOrd, TotalEq)]
26 pub struct Ascii { priv chr: u8 }
29 /// Converts a ascii character into a `u8`.
31 pub fn to_byte(self) -> u8 {
35 /// Converts a ascii character into a `char`.
37 pub fn to_char(self) -> char {
41 /// Convert to lowercase.
43 pub fn to_lower(self) -> Ascii {
44 Ascii{chr: ASCII_LOWER_MAP[self.chr]}
47 /// Convert to uppercase.
49 pub fn to_upper(self) -> Ascii {
50 Ascii{chr: ASCII_UPPER_MAP[self.chr]}
53 /// Compares two ascii characters of equality, ignoring case.
55 pub fn eq_ignore_case(self, other: Ascii) -> bool {
56 ASCII_LOWER_MAP[self.chr] == ASCII_LOWER_MAP[other.chr]
59 // the following methods are like ctype, and the implementation is inspired by musl
61 /// Check if the character is a letter (a-z, A-Z)
63 pub fn is_alpha(&self) -> bool {
64 (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
67 /// Check if the character is a number (0-9)
69 pub fn is_digit(&self) -> bool {
70 self.chr >= 0x30 && self.chr <= 0x39
73 /// Check if the character is a letter or number
75 pub fn is_alnum(&self) -> bool {
76 self.is_alpha() || self.is_digit()
79 /// Check if the character is a space or horizontal tab
81 pub fn is_blank(&self) -> bool {
82 self.chr == ' ' as u8 || self.chr == '\t' as u8
85 /// Check if the character is a control character
87 pub fn is_control(&self) -> bool {
88 self.chr < 0x20 || self.chr == 0x7F
91 /// Checks if the character is printable (except space)
93 pub fn is_graph(&self) -> bool {
94 (self.chr - 0x21) < 0x5E
97 /// Checks if the character is printable (including space)
99 pub fn is_print(&self) -> bool {
100 (self.chr - 0x20) < 0x5F
103 /// Checks if the character is lowercase
105 pub fn is_lower(&self) -> bool {
106 (self.chr - 'a' as u8) < 26
109 /// Checks if the character is uppercase
111 pub fn is_upper(&self) -> bool {
112 (self.chr - 'A' as u8) < 26
115 /// Checks if the character is punctuation
117 pub fn is_punctuation(&self) -> bool {
118 self.is_graph() && !self.is_alnum()
121 /// Checks if the character is a valid hex digit
123 pub fn is_hex(&self) -> bool {
124 self.is_digit() || ((self.chr | 32u8) - 'a' as u8) < 6
128 impl ToStr for Ascii {
130 fn to_str(&self) -> ~str {
131 // self.chr is always a valid utf8 byte, no need for the check
132 unsafe { str::raw::from_byte(self.chr) }
136 /// Trait for converting into an ascii type.
137 pub trait AsciiCast<T> {
138 /// Convert to an ascii type
139 fn to_ascii(&self) -> T;
141 /// Convert to an ascii type, not doing any range asserts
142 unsafe fn to_ascii_nocheck(&self) -> T;
144 /// Check if convertible to ascii
145 fn is_ascii(&self) -> bool;
148 impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
150 fn to_ascii(&self) -> &'self[Ascii] {
151 assert!(self.is_ascii());
152 unsafe {self.to_ascii_nocheck()}
156 unsafe fn to_ascii_nocheck(&self) -> &'self[Ascii] {
157 cast::transmute(*self)
161 fn is_ascii(&self) -> bool {
162 for b in self.iter() {
163 if !b.is_ascii() { return false; }
169 impl<'self> AsciiCast<&'self [Ascii]> for &'self str {
171 fn to_ascii(&self) -> &'self [Ascii] {
172 assert!(self.is_ascii());
173 unsafe { self.to_ascii_nocheck() }
177 unsafe fn to_ascii_nocheck(&self) -> &'self [Ascii] {
178 cast::transmute(*self)
182 fn is_ascii(&self) -> bool {
183 self.bytes().all(|b| b.is_ascii())
187 impl AsciiCast<Ascii> for u8 {
189 fn to_ascii(&self) -> Ascii {
190 assert!(self.is_ascii());
191 unsafe {self.to_ascii_nocheck()}
195 unsafe fn to_ascii_nocheck(&self) -> Ascii {
200 fn is_ascii(&self) -> bool {
205 impl AsciiCast<Ascii> for char {
207 fn to_ascii(&self) -> Ascii {
208 assert!(self.is_ascii());
209 unsafe {self.to_ascii_nocheck()}
213 unsafe fn to_ascii_nocheck(&self) -> Ascii {
214 Ascii{ chr: *self as u8 }
218 fn is_ascii(&self) -> bool {
219 *self as u32 - ('\x7F' as u32 & *self as u32) == 0
223 /// Trait for copyless casting to an ascii vector.
224 pub trait OwnedAsciiCast {
225 /// Take ownership and cast to an ascii vector.
226 fn into_ascii(self) -> ~[Ascii];
228 /// Take ownership and cast to an ascii vector.
229 /// Does not perform validation checks.
230 unsafe fn into_ascii_nocheck(self) -> ~[Ascii];
233 impl OwnedAsciiCast for ~[u8] {
235 fn into_ascii(self) -> ~[Ascii] {
236 assert!(self.is_ascii());
237 unsafe {self.into_ascii_nocheck()}
241 unsafe fn into_ascii_nocheck(self) -> ~[Ascii] {
242 cast::transmute(self)
246 impl OwnedAsciiCast for ~str {
248 fn into_ascii(self) -> ~[Ascii] {
249 assert!(self.is_ascii());
250 unsafe {self.into_ascii_nocheck()}
254 unsafe fn into_ascii_nocheck(self) -> ~[Ascii] {
255 cast::transmute(self)
259 /// Trait for converting an ascii type to a string. Needed to convert
260 /// `&[Ascii]` to `&str`.
262 /// Convert to a string.
263 fn as_str_ascii<'a>(&'a self) -> &'a str;
265 /// Convert to vector representing a lower cased ascii string.
266 fn to_lower(&self) -> ~[Ascii];
268 /// Convert to vector representing a upper cased ascii string.
269 fn to_upper(&self) -> ~[Ascii];
271 /// Compares two Ascii strings ignoring case.
272 fn eq_ignore_case(self, other: &[Ascii]) -> bool;
275 impl<'self> AsciiStr for &'self [Ascii] {
277 fn as_str_ascii<'a>(&'a self) -> &'a str {
278 unsafe { cast::transmute(*self) }
282 fn to_lower(&self) -> ~[Ascii] {
283 self.map(|a| a.to_lower())
287 fn to_upper(&self) -> ~[Ascii] {
288 self.map(|a| a.to_upper())
292 fn eq_ignore_case(self, other: &[Ascii]) -> bool {
293 self.iter().zip(other.iter()).all(|(&a, &b)| a.eq_ignore_case(b))
297 impl ToStrConsume for ~[Ascii] {
299 fn into_str(self) -> ~str {
300 unsafe { cast::transmute(self) }
304 impl IterBytes for Ascii {
306 fn iter_bytes(&self, _lsb0: bool, f: |buf: &[u8]| -> bool) -> bool {
311 /// Trait to convert to a owned byte array by consuming self
312 pub trait ToBytesConsume {
313 /// Converts to a owned byte array by consuming self
314 fn into_bytes(self) -> ~[u8];
317 impl ToBytesConsume for ~[Ascii] {
318 fn into_bytes(self) -> ~[u8] {
319 unsafe { cast::transmute(self) }
323 /// Extension methods for ASCII-subset only operations on owned strings
324 pub trait OwnedStrAsciiExt {
325 /// Convert the string to ASCII upper case:
326 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
327 /// but non-ASCII letters are unchanged.
328 fn into_ascii_upper(self) -> ~str;
330 /// Convert the string to ASCII lower case:
331 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
332 /// but non-ASCII letters are unchanged.
333 fn into_ascii_lower(self) -> ~str;
336 /// Extension methods for ASCII-subset only operations on string slices
337 pub trait StrAsciiExt {
338 /// Makes a copy of the string in ASCII upper case:
339 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
340 /// but non-ASCII letters are unchanged.
341 fn to_ascii_upper(&self) -> ~str;
343 /// Makes a copy of the string in ASCII lower case:
344 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
345 /// but non-ASCII letters are unchanged.
346 fn to_ascii_lower(&self) -> ~str;
348 /// Check that two strings are an ASCII case-insensitive match.
349 /// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
350 /// but without allocating and copying temporary strings.
351 fn eq_ignore_ascii_case(&self, other: &str) -> bool;
354 impl<'self> StrAsciiExt for &'self str {
356 fn to_ascii_upper(&self) -> ~str {
357 unsafe { str_copy_map_bytes(*self, ASCII_UPPER_MAP) }
361 fn to_ascii_lower(&self) -> ~str {
362 unsafe { str_copy_map_bytes(*self, ASCII_LOWER_MAP) }
366 fn eq_ignore_ascii_case(&self, other: &str) -> bool {
367 self.len() == other.len() && self.as_bytes().iter().zip(other.as_bytes().iter()).all(
368 |(byte_self, byte_other)| ASCII_LOWER_MAP[*byte_self] == ASCII_LOWER_MAP[*byte_other])
372 impl OwnedStrAsciiExt for ~str {
374 fn into_ascii_upper(self) -> ~str {
375 unsafe { str_map_bytes(self, ASCII_UPPER_MAP) }
379 fn into_ascii_lower(self) -> ~str {
380 unsafe { str_map_bytes(self, ASCII_LOWER_MAP) }
385 unsafe fn str_map_bytes(string: ~str, map: &'static [u8]) -> ~str {
386 let mut bytes = string.into_bytes();
388 for b in bytes.mut_iter() {
392 str::raw::from_utf8_owned(bytes)
396 unsafe fn str_copy_map_bytes(string: &str, map: &'static [u8]) -> ~str {
397 let bytes = string.bytes().map(|b| map[b]).to_owned_vec();
399 str::raw::from_utf8_owned(bytes)
402 static ASCII_LOWER_MAP: &'static [u8] = &[
403 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
404 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
405 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
406 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
407 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
408 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
409 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
410 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
411 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
412 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
413 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
414 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
415 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
416 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
417 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
418 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
419 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
420 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
421 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
422 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
423 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
424 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
425 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
426 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
427 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
428 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
429 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
430 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
431 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
432 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
433 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
434 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
437 static ASCII_UPPER_MAP: &'static [u8] = &[
438 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
439 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
440 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
441 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
442 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
443 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
444 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
445 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
446 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
447 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
448 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
449 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
450 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
451 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
452 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
453 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
454 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
455 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
456 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
457 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
458 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
459 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
460 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
461 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
462 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
463 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
464 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
465 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
466 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
467 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
468 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
469 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
479 macro_rules! v2ascii (
480 ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
481 (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
486 assert_eq!(65u8.to_ascii().to_byte(), 65u8);
487 assert_eq!(65u8.to_ascii().to_char(), 'A');
488 assert_eq!('A'.to_ascii().to_char(), 'A');
489 assert_eq!('A'.to_ascii().to_byte(), 65u8);
491 assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
492 assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
493 assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
494 assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');
496 assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
497 assert_eq!('['.to_ascii().to_lower().to_char(), '[');
498 assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
499 assert_eq!('{'.to_ascii().to_upper().to_char(), '{');
501 assert!('0'.to_ascii().is_digit());
502 assert!('9'.to_ascii().is_digit());
503 assert!(!'/'.to_ascii().is_digit());
504 assert!(!':'.to_ascii().is_digit());
506 assert!((0x1fu8).to_ascii().is_control());
507 assert!(!' '.to_ascii().is_control());
508 assert!((0x7fu8).to_ascii().is_control());
510 assert!("banana".chars().all(|c| c.is_ascii()));
511 assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
515 fn test_ascii_vec() {
516 assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
517 assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59]));
518 // FIXME: #5475 borrowchk error, owned vectors do not live long enough
519 // if chained-from directly
520 let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
521 let v = ~"( ;"; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
523 assert_eq!("abCDef&?#".to_ascii().to_lower().into_str(), ~"abcdef&?#");
524 assert_eq!("abCDef&?#".to_ascii().to_upper().into_str(), ~"ABCDEF&?#");
526 assert_eq!("".to_ascii().to_lower().into_str(), ~"");
527 assert_eq!("YMCA".to_ascii().to_lower().into_str(), ~"ymca");
528 assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_str(), ~"ABCDEFXYZ:.;");
530 assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
532 assert!("".is_ascii());
533 assert!("a".is_ascii());
534 assert!(!"\u2009".is_ascii());
539 fn test_owned_ascii_vec() {
540 assert_eq!((~"( ;").into_ascii(), v2ascii!(~[40, 32, 59]));
541 assert_eq!((~[40u8, 32u8, 59u8]).into_ascii(), v2ascii!(~[40, 32, 59]));
545 fn test_ascii_as_str() {
546 let v = v2ascii!([40, 32, 59]);
547 assert_eq!(v.as_str_ascii(), "( ;");
551 fn test_ascii_into_str() {
552 assert_eq!(v2ascii!(~[40, 32, 59]).into_str(), ~"( ;");
556 fn test_ascii_to_bytes() {
557 assert_eq!(v2ascii!(~[40, 32, 59]).into_bytes(), ~[40u8, 32u8, 59u8]);
560 #[test] #[should_fail]
561 fn test_ascii_vec_fail_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii(); }
563 #[test] #[should_fail]
564 fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }
566 #[test] #[should_fail]
567 fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }
569 #[test] #[should_fail]
570 fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
573 fn test_to_ascii_upper() {
574 assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), ~"URL()URL()URL()üRL");
575 assert_eq!("hıKß".to_ascii_upper(), ~"HıKß");
579 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
581 assert_eq!(from_char(from_u32(i).unwrap()).to_ascii_upper(),
582 from_char(from_u32(upper).unwrap()))
588 fn test_to_ascii_lower() {
589 assert_eq!("url()URL()uRl()Ürl".to_ascii_lower(), ~"url()url()url()Ürl");
590 // Dotted capital I, Kelvin sign, Sharp S.
591 assert_eq!("HİKß".to_ascii_lower(), ~"hİKß");
595 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
597 assert_eq!(from_char(from_u32(i).unwrap()).to_ascii_lower(),
598 from_char(from_u32(lower).unwrap()))
604 fn test_into_ascii_upper() {
605 assert_eq!((~"url()URL()uRl()ürl").into_ascii_upper(), ~"URL()URL()URL()üRL");
606 assert_eq!((~"hıKß").into_ascii_upper(), ~"HıKß");
610 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
612 assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_upper(),
613 from_char(from_u32(upper).unwrap()))
619 fn test_into_ascii_lower() {
620 assert_eq!((~"url()URL()uRl()Ürl").into_ascii_lower(), ~"url()url()url()Ürl");
621 // Dotted capital I, Kelvin sign, Sharp S.
622 assert_eq!((~"HİKß").into_ascii_lower(), ~"hİKß");
626 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
628 assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_lower(),
629 from_char(from_u32(lower).unwrap()))
635 fn test_eq_ignore_ascii_case() {
636 assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
637 assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
638 // Dotted capital I, Kelvin sign, Sharp S.
639 assert!("HİKß".eq_ignore_ascii_case("hİKß"));
640 assert!(!"İ".eq_ignore_ascii_case("i"));
641 assert!(!"K".eq_ignore_ascii_case("k"));
642 assert!(!"ß".eq_ignore_ascii_case("s"));
647 let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 }
649 assert!(from_char(from_u32(i).unwrap()).
650 eq_ignore_ascii_case(from_char(from_u32(lower).unwrap())));
657 let s = Ascii{ chr: 't' as u8 }.to_str();