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 //! Most string operations in Rust act on UTF-8 strings. However, at times it
14 //! makes more sense to only consider the ASCII character set for a specific
17 //! The [`AsciiExt`] trait provides methods that allow for character
18 //! operations that only act on the ASCII subset and leave non-ASCII characters
21 //! The [`escape_default`] function provides an iterator over the bytes of an
22 //! escaped version of the character given.
24 //! [`AsciiExt`]: trait.AsciiExt.html
25 //! [`escape_default`]: fn.escape_default.html
27 #![stable(feature = "rust1", since = "1.0.0")]
31 use iter::FusedIterator;
33 /// Extension methods for ASCII-subset only operations.
35 /// Be aware that operations on seemingly non-ASCII characters can sometimes
36 /// have unexpected results. Consider this example:
39 /// use std::ascii::AsciiExt;
41 /// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFÉ");
42 /// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFé");
45 /// In the first example, the lowercased string is represented `"cafe\u{301}"`
46 /// (the last character is an acute accent [combining character]). Unlike the
47 /// other characters in the string, the combining character will not get mapped
48 /// to an uppercase variant, resulting in `"CAFE\u{301}"`. In the second
49 /// example, the lowercased string is represented `"caf\u{e9}"` (the last
50 /// character is a single Unicode character representing an 'e' with an acute
51 /// accent). Since the last character is defined outside the scope of ASCII,
52 /// it will not get mapped to an uppercase variant, resulting in `"CAF\u{e9}"`.
54 /// [combining character]: https://en.wikipedia.org/wiki/Combining_character
55 #[stable(feature = "rust1", since = "1.0.0")]
57 /// Container type for copied ASCII characters.
58 #[stable(feature = "rust1", since = "1.0.0")]
61 /// Checks if the value is within the ASCII range.
65 /// This method will be deprecated in favor of the identically-named
66 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
67 #[stable(feature = "rust1", since = "1.0.0")]
68 fn is_ascii(&self) -> bool;
70 /// Makes a copy of the value in its ASCII upper case equivalent.
72 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
73 /// but non-ASCII letters are unchanged.
75 /// To uppercase the value in-place, use [`make_ascii_uppercase`].
77 /// To uppercase ASCII characters in addition to non-ASCII characters, use
78 /// [`str::to_uppercase`].
82 /// This method will be deprecated in favor of the identically-named
83 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
85 /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase
86 /// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase
87 #[stable(feature = "rust1", since = "1.0.0")]
88 fn to_ascii_uppercase(&self) -> Self::Owned;
90 /// Makes a copy of the value in its ASCII lower case equivalent.
92 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
93 /// but non-ASCII letters are unchanged.
95 /// To lowercase the value in-place, use [`make_ascii_lowercase`].
97 /// To lowercase ASCII characters in addition to non-ASCII characters, use
98 /// [`str::to_lowercase`].
102 /// This method will be deprecated in favor of the identically-named
103 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
105 /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase
106 /// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase
107 #[stable(feature = "rust1", since = "1.0.0")]
108 fn to_ascii_lowercase(&self) -> Self::Owned;
110 /// Checks that two values are an ASCII case-insensitive match.
112 /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
113 /// but without allocating and copying temporaries.
117 /// This method will be deprecated in favor of the identically-named
118 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
119 #[stable(feature = "rust1", since = "1.0.0")]
120 fn eq_ignore_ascii_case(&self, other: &Self) -> bool;
122 /// Converts this type to its ASCII upper case equivalent in-place.
124 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
125 /// but non-ASCII letters are unchanged.
127 /// To return a new uppercased value without modifying the existing one, use
128 /// [`to_ascii_uppercase`].
132 /// This method will be deprecated in favor of the identically-named
133 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
135 /// [`to_ascii_uppercase`]: #tymethod.to_ascii_uppercase
136 #[stable(feature = "ascii", since = "1.9.0")]
137 fn make_ascii_uppercase(&mut self);
139 /// Converts this type to its ASCII lower case equivalent in-place.
141 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
142 /// but non-ASCII letters are unchanged.
144 /// To return a new lowercased value without modifying the existing one, use
145 /// [`to_ascii_lowercase`].
149 /// This method will be deprecated in favor of the identically-named
150 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
152 /// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase
153 #[stable(feature = "ascii", since = "1.9.0")]
154 fn make_ascii_lowercase(&mut self);
156 /// Checks if the value is an ASCII alphabetic character:
157 /// U+0041 'A' ... U+005A 'Z' or U+0061 'a' ... U+007A 'z'.
158 /// For strings, true if all characters in the string are
159 /// ASCII alphabetic.
163 /// This method will be deprecated in favor of the identically-named
164 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
165 #[unstable(feature = "ascii_ctype", issue = "39658")]
166 fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); }
168 /// Checks if the value is an ASCII uppercase character:
169 /// U+0041 'A' ... U+005A 'Z'.
170 /// For strings, true if all characters in the string are
175 /// This method will be deprecated in favor of the identically-named
176 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
177 #[unstable(feature = "ascii_ctype", issue = "39658")]
178 fn is_ascii_uppercase(&self) -> bool { unimplemented!(); }
180 /// Checks if the value is an ASCII lowercase character:
181 /// U+0061 'a' ... U+007A 'z'.
182 /// For strings, true if all characters in the string are
187 /// This method will be deprecated in favor of the identically-named
188 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
189 #[unstable(feature = "ascii_ctype", issue = "39658")]
190 fn is_ascii_lowercase(&self) -> bool { unimplemented!(); }
192 /// Checks if the value is an ASCII alphanumeric character:
193 /// U+0041 'A' ... U+005A 'Z', U+0061 'a' ... U+007A 'z', or
194 /// U+0030 '0' ... U+0039 '9'.
195 /// For strings, true if all characters in the string are
196 /// ASCII alphanumeric.
200 /// This method will be deprecated in favor of the identically-named
201 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
202 #[unstable(feature = "ascii_ctype", issue = "39658")]
203 fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); }
205 /// Checks if the value is an ASCII decimal digit:
206 /// U+0030 '0' ... U+0039 '9'.
207 /// For strings, true if all characters in the string are
212 /// This method will be deprecated in favor of the identically-named
213 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
214 #[unstable(feature = "ascii_ctype", issue = "39658")]
215 fn is_ascii_digit(&self) -> bool { unimplemented!(); }
217 /// Checks if the value is an ASCII hexadecimal digit:
218 /// U+0030 '0' ... U+0039 '9', U+0041 'A' ... U+0046 'F', or
219 /// U+0061 'a' ... U+0066 'f'.
220 /// For strings, true if all characters in the string are
221 /// ASCII hex digits.
225 /// This method will be deprecated in favor of the identically-named
226 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
227 #[unstable(feature = "ascii_ctype", issue = "39658")]
228 fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); }
230 /// Checks if the value is an ASCII punctuation character:
232 /// U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`
233 /// U+003A ... U+0040 `: ; < = > ? @`
234 /// U+005B ... U+0060 ``[ \\ ] ^ _ ` ``
235 /// U+007B ... U+007E `{ | } ~`
237 /// For strings, true if all characters in the string are
238 /// ASCII punctuation.
242 /// This method will be deprecated in favor of the identically-named
243 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
244 #[unstable(feature = "ascii_ctype", issue = "39658")]
245 fn is_ascii_punctuation(&self) -> bool { unimplemented!(); }
247 /// Checks if the value is an ASCII graphic character:
248 /// U+0021 '!' ... U+007E '~'.
249 /// For strings, true if all characters in the string are
250 /// ASCII graphic characters.
254 /// This method will be deprecated in favor of the identically-named
255 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
256 #[unstable(feature = "ascii_ctype", issue = "39658")]
257 fn is_ascii_graphic(&self) -> bool { unimplemented!(); }
259 /// Checks if the value is an ASCII whitespace character:
260 /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED,
261 /// U+000C FORM FEED, or U+000D CARRIAGE RETURN.
262 /// For strings, true if all characters in the string are
263 /// ASCII whitespace.
265 /// Rust uses the WhatWG Infra Standard's [definition of ASCII
266 /// whitespace][infra-aw]. There are several other definitions in
267 /// wide use. For instance, [the POSIX locale][pct] includes
268 /// U+000B VERTICAL TAB as well as all the above characters,
269 /// but—from the very same specification—[the default rule for
270 /// "field splitting" in the Bourne shell][bfs] considers *only*
271 /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
273 /// If you are writing a program that will process an existing
274 /// file format, check what that format's definition of whitespace is
275 /// before using this function.
277 /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
278 /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
279 /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
283 /// This method will be deprecated in favor of the identically-named
284 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
285 #[unstable(feature = "ascii_ctype", issue = "39658")]
286 fn is_ascii_whitespace(&self) -> bool { unimplemented!(); }
288 /// Checks if the value is an ASCII control character:
289 /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE.
290 /// Note that most ASCII whitespace characters are control
291 /// characters, but SPACE is not.
295 /// This method will be deprecated in favor of the identically-named
296 /// inherent methods on `u8`, `char`, `[u8]` and `str`.
297 #[unstable(feature = "ascii_ctype", issue = "39658")]
298 fn is_ascii_control(&self) -> bool { unimplemented!(); }
301 macro_rules! delegating_ascii_methods {
304 fn is_ascii(&self) -> bool { self.is_ascii() }
307 fn to_ascii_uppercase(&self) -> Self::Owned { self.to_ascii_uppercase() }
310 fn to_ascii_lowercase(&self) -> Self::Owned { self.to_ascii_lowercase() }
313 fn eq_ignore_ascii_case(&self, o: &Self) -> bool { self.eq_ignore_ascii_case(o) }
316 fn make_ascii_uppercase(&mut self) { self.make_ascii_uppercase(); }
319 fn make_ascii_lowercase(&mut self) { self.make_ascii_lowercase(); }
323 macro_rules! delegating_ascii_ctype_methods {
326 fn is_ascii_alphabetic(&self) -> bool { self.is_ascii_alphabetic() }
329 fn is_ascii_uppercase(&self) -> bool { self.is_ascii_uppercase() }
332 fn is_ascii_lowercase(&self) -> bool { self.is_ascii_lowercase() }
335 fn is_ascii_alphanumeric(&self) -> bool { self.is_ascii_alphanumeric() }
338 fn is_ascii_digit(&self) -> bool { self.is_ascii_digit() }
341 fn is_ascii_hexdigit(&self) -> bool { self.is_ascii_hexdigit() }
344 fn is_ascii_punctuation(&self) -> bool { self.is_ascii_punctuation() }
347 fn is_ascii_graphic(&self) -> bool { self.is_ascii_graphic() }
350 fn is_ascii_whitespace(&self) -> bool { self.is_ascii_whitespace() }
353 fn is_ascii_control(&self) -> bool { self.is_ascii_control() }
357 #[stable(feature = "rust1", since = "1.0.0")]
358 impl AsciiExt for u8 {
361 delegating_ascii_methods!();
362 delegating_ascii_ctype_methods!();
365 #[stable(feature = "rust1", since = "1.0.0")]
366 impl AsciiExt for char {
369 delegating_ascii_methods!();
370 delegating_ascii_ctype_methods!();
373 #[stable(feature = "rust1", since = "1.0.0")]
374 impl AsciiExt for [u8] {
375 type Owned = Vec<u8>;
377 delegating_ascii_methods!();
380 fn is_ascii_alphabetic(&self) -> bool {
381 self.iter().all(|b| b.is_ascii_alphabetic())
385 fn is_ascii_uppercase(&self) -> bool {
386 self.iter().all(|b| b.is_ascii_uppercase())
390 fn is_ascii_lowercase(&self) -> bool {
391 self.iter().all(|b| b.is_ascii_lowercase())
395 fn is_ascii_alphanumeric(&self) -> bool {
396 self.iter().all(|b| b.is_ascii_alphanumeric())
400 fn is_ascii_digit(&self) -> bool {
401 self.iter().all(|b| b.is_ascii_digit())
405 fn is_ascii_hexdigit(&self) -> bool {
406 self.iter().all(|b| b.is_ascii_hexdigit())
410 fn is_ascii_punctuation(&self) -> bool {
411 self.iter().all(|b| b.is_ascii_punctuation())
415 fn is_ascii_graphic(&self) -> bool {
416 self.iter().all(|b| b.is_ascii_graphic())
420 fn is_ascii_whitespace(&self) -> bool {
421 self.iter().all(|b| b.is_ascii_whitespace())
425 fn is_ascii_control(&self) -> bool {
426 self.iter().all(|b| b.is_ascii_control())
430 #[stable(feature = "rust1", since = "1.0.0")]
431 impl AsciiExt for str {
434 delegating_ascii_methods!();
437 fn is_ascii_alphabetic(&self) -> bool {
438 self.bytes().all(|b| b.is_ascii_alphabetic())
442 fn is_ascii_uppercase(&self) -> bool {
443 self.bytes().all(|b| b.is_ascii_uppercase())
447 fn is_ascii_lowercase(&self) -> bool {
448 self.bytes().all(|b| b.is_ascii_lowercase())
452 fn is_ascii_alphanumeric(&self) -> bool {
453 self.bytes().all(|b| b.is_ascii_alphanumeric())
457 fn is_ascii_digit(&self) -> bool {
458 self.bytes().all(|b| b.is_ascii_digit())
462 fn is_ascii_hexdigit(&self) -> bool {
463 self.bytes().all(|b| b.is_ascii_hexdigit())
467 fn is_ascii_punctuation(&self) -> bool {
468 self.bytes().all(|b| b.is_ascii_punctuation())
472 fn is_ascii_graphic(&self) -> bool {
473 self.bytes().all(|b| b.is_ascii_graphic())
477 fn is_ascii_whitespace(&self) -> bool {
478 self.bytes().all(|b| b.is_ascii_whitespace())
482 fn is_ascii_control(&self) -> bool {
483 self.bytes().all(|b| b.is_ascii_control())
487 /// An iterator over the escaped version of a byte.
489 /// This `struct` is created by the [`escape_default`] function. See its
490 /// documentation for more.
492 /// [`escape_default`]: fn.escape_default.html
493 #[stable(feature = "rust1", since = "1.0.0")]
494 pub struct EscapeDefault {
499 /// Returns an iterator that produces an escaped version of a `u8`.
501 /// The default is chosen with a bias toward producing literals that are
502 /// legal in a variety of languages, including C++11 and similar C-family
503 /// languages. The exact rules are:
505 /// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
506 /// - Single-quote, double-quote and backslash chars are backslash-escaped.
507 /// - Any other chars in the range [0x20,0x7e] are not escaped.
508 /// - Any other chars are given hex escapes of the form '\xNN'.
509 /// - Unicode escapes are never generated by this function.
516 /// let escaped = ascii::escape_default(b'0').next().unwrap();
517 /// assert_eq!(b'0', escaped);
519 /// let mut escaped = ascii::escape_default(b'\t');
521 /// assert_eq!(b'\\', escaped.next().unwrap());
522 /// assert_eq!(b't', escaped.next().unwrap());
524 /// let mut escaped = ascii::escape_default(b'\r');
526 /// assert_eq!(b'\\', escaped.next().unwrap());
527 /// assert_eq!(b'r', escaped.next().unwrap());
529 /// let mut escaped = ascii::escape_default(b'\n');
531 /// assert_eq!(b'\\', escaped.next().unwrap());
532 /// assert_eq!(b'n', escaped.next().unwrap());
534 /// let mut escaped = ascii::escape_default(b'\'');
536 /// assert_eq!(b'\\', escaped.next().unwrap());
537 /// assert_eq!(b'\'', escaped.next().unwrap());
539 /// let mut escaped = ascii::escape_default(b'"');
541 /// assert_eq!(b'\\', escaped.next().unwrap());
542 /// assert_eq!(b'"', escaped.next().unwrap());
544 /// let mut escaped = ascii::escape_default(b'\\');
546 /// assert_eq!(b'\\', escaped.next().unwrap());
547 /// assert_eq!(b'\\', escaped.next().unwrap());
549 /// let mut escaped = ascii::escape_default(b'\x9d');
551 /// assert_eq!(b'\\', escaped.next().unwrap());
552 /// assert_eq!(b'x', escaped.next().unwrap());
553 /// assert_eq!(b'9', escaped.next().unwrap());
554 /// assert_eq!(b'd', escaped.next().unwrap());
556 #[stable(feature = "rust1", since = "1.0.0")]
557 pub fn escape_default(c: u8) -> EscapeDefault {
558 let (data, len) = match c {
559 b'\t' => ([b'\\', b't', 0, 0], 2),
560 b'\r' => ([b'\\', b'r', 0, 0], 2),
561 b'\n' => ([b'\\', b'n', 0, 0], 2),
562 b'\\' => ([b'\\', b'\\', 0, 0], 2),
563 b'\'' => ([b'\\', b'\'', 0, 0], 2),
564 b'"' => ([b'\\', b'"', 0, 0], 2),
565 b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1),
566 _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4),
569 return EscapeDefault { range: (0.. len), data: data };
571 fn hexify(b: u8) -> u8 {
579 #[stable(feature = "rust1", since = "1.0.0")]
580 impl Iterator for EscapeDefault {
582 fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) }
583 fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
585 #[stable(feature = "rust1", since = "1.0.0")]
586 impl DoubleEndedIterator for EscapeDefault {
587 fn next_back(&mut self) -> Option<u8> {
588 self.range.next_back().map(|i| self.data[i])
591 #[stable(feature = "rust1", since = "1.0.0")]
592 impl ExactSizeIterator for EscapeDefault {}
593 #[stable(feature = "fused", since = "1.26.0")]
594 impl FusedIterator for EscapeDefault {}
596 #[stable(feature = "std_debug", since = "1.16.0")]
597 impl fmt::Debug for EscapeDefault {
598 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
599 f.pad("EscapeDefault { .. }")
606 //! Note that most of these tests are not testing `AsciiExt` methods, but
607 //! test inherent ascii methods of char, u8, str and [u8]. `AsciiExt` is
608 //! just using those methods, though.
614 assert!(b"".is_ascii());
615 assert!(b"banana\0\x7F".is_ascii());
616 assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii()));
617 assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii());
618 assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii()));
619 assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii()));
621 assert!("".is_ascii());
622 assert!("banana\0\u{7F}".is_ascii());
623 assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii()));
624 assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
625 assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii()));
629 fn test_to_ascii_uppercase() {
630 assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL");
631 assert_eq!("hıKß".to_ascii_uppercase(), "HıKß");
634 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
636 assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(),
637 (from_u32(upper).unwrap()).to_string());
642 fn test_to_ascii_lowercase() {
643 assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl");
644 // Dotted capital I, Kelvin sign, Sharp S.
645 assert_eq!("HİKß".to_ascii_lowercase(), "hİKß");
648 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
650 assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(),
651 (from_u32(lower).unwrap()).to_string());
656 fn test_make_ascii_lower_case() {
658 ($from: expr, $to: expr) => {
661 x.make_ascii_lowercase();
673 test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89");
674 test!("HİKß".to_string(), "hİKß");
679 fn test_make_ascii_upper_case() {
681 ($from: expr, $to: expr) => {
684 x.make_ascii_uppercase();
696 test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9");
697 test!("hıKß".to_string(), "HıKß");
699 let mut x = "Hello".to_string();
700 x[..3].make_ascii_uppercase(); // Test IndexMut on String.
701 assert_eq!(x, "HELlo")
705 fn test_eq_ignore_ascii_case() {
706 assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
707 assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
708 // Dotted capital I, Kelvin sign, Sharp S.
709 assert!("HİKß".eq_ignore_ascii_case("hİKß"));
710 assert!(!"İ".eq_ignore_ascii_case("i"));
711 assert!(!"K".eq_ignore_ascii_case("k"));
712 assert!(!"ß".eq_ignore_ascii_case("s"));
715 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
717 assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case(
718 &from_u32(lower).unwrap().to_string()));
723 fn inference_works() {
724 let x = "a".to_string();
725 x.eq_ignore_ascii_case("A");
728 // Shorthands used by the is_ascii_* tests.
729 macro_rules! assert_all {
730 ($what:ident, $($str:tt),+) => {{
732 for b in $str.chars() {
734 panic!("expected {}({}) but it isn't",
735 stringify!($what), b);
738 for b in $str.as_bytes().iter() {
740 panic!("expected {}(0x{:02x})) but it isn't",
741 stringify!($what), b);
744 assert!($str.$what());
745 assert!($str.as_bytes().$what());
748 ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+))
750 macro_rules! assert_none {
751 ($what:ident, $($str:tt),+) => {{
753 for b in $str.chars() {
755 panic!("expected not-{}({}) but it is",
756 stringify!($what), b);
759 for b in $str.as_bytes().iter() {
761 panic!("expected not-{}(0x{:02x})) but it is",
762 stringify!($what), b);
767 ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+))
771 fn test_is_ascii_alphabetic() {
772 assert_all!(is_ascii_alphabetic,
774 "abcdefghijklmnopqrstuvwxyz",
775 "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
777 assert_none!(is_ascii_alphabetic,
779 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
781 "\x00\x01\x02\x03\x04\x05\x06\x07",
782 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
783 "\x10\x11\x12\x13\x14\x15\x16\x17",
784 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
790 fn test_is_ascii_uppercase() {
791 assert_all!(is_ascii_uppercase,
793 "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
795 assert_none!(is_ascii_uppercase,
796 "abcdefghijklmnopqrstuvwxyz",
798 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
800 "\x00\x01\x02\x03\x04\x05\x06\x07",
801 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
802 "\x10\x11\x12\x13\x14\x15\x16\x17",
803 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
809 fn test_is_ascii_lowercase() {
810 assert_all!(is_ascii_lowercase,
811 "abcdefghijklmnopqrstuvwxyz",
813 assert_none!(is_ascii_lowercase,
814 "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
816 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
818 "\x00\x01\x02\x03\x04\x05\x06\x07",
819 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
820 "\x10\x11\x12\x13\x14\x15\x16\x17",
821 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
827 fn test_is_ascii_alphanumeric() {
828 assert_all!(is_ascii_alphanumeric,
830 "abcdefghijklmnopqrstuvwxyz",
831 "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
834 assert_none!(is_ascii_alphanumeric,
835 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
837 "\x00\x01\x02\x03\x04\x05\x06\x07",
838 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
839 "\x10\x11\x12\x13\x14\x15\x16\x17",
840 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
846 fn test_is_ascii_digit() {
847 assert_all!(is_ascii_digit,
851 assert_none!(is_ascii_digit,
852 "abcdefghijklmnopqrstuvwxyz",
853 "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
854 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
856 "\x00\x01\x02\x03\x04\x05\x06\x07",
857 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
858 "\x10\x11\x12\x13\x14\x15\x16\x17",
859 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
865 fn test_is_ascii_hexdigit() {
866 assert_all!(is_ascii_hexdigit,
871 assert_none!(is_ascii_hexdigit,
872 "ghijklmnopqrstuvwxyz",
873 "GHIJKLMNOQPRSTUVWXYZ",
874 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
876 "\x00\x01\x02\x03\x04\x05\x06\x07",
877 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
878 "\x10\x11\x12\x13\x14\x15\x16\x17",
879 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
885 fn test_is_ascii_punctuation() {
886 assert_all!(is_ascii_punctuation,
888 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
890 assert_none!(is_ascii_punctuation,
891 "abcdefghijklmnopqrstuvwxyz",
892 "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
895 "\x00\x01\x02\x03\x04\x05\x06\x07",
896 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
897 "\x10\x11\x12\x13\x14\x15\x16\x17",
898 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
904 fn test_is_ascii_graphic() {
905 assert_all!(is_ascii_graphic,
907 "abcdefghijklmnopqrstuvwxyz",
908 "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
910 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
912 assert_none!(is_ascii_graphic,
914 "\x00\x01\x02\x03\x04\x05\x06\x07",
915 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
916 "\x10\x11\x12\x13\x14\x15\x16\x17",
917 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
923 fn test_is_ascii_whitespace() {
924 assert_all!(is_ascii_whitespace,
928 assert_none!(is_ascii_whitespace,
929 "abcdefghijklmnopqrstuvwxyz",
930 "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
932 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
933 "\x00\x01\x02\x03\x04\x05\x06\x07",
935 "\x10\x11\x12\x13\x14\x15\x16\x17",
936 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
942 fn test_is_ascii_control() {
943 assert_all!(is_ascii_control,
945 "\x00\x01\x02\x03\x04\x05\x06\x07",
946 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
947 "\x10\x11\x12\x13\x14\x15\x16\x17",
948 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
951 assert_none!(is_ascii_control,
952 "abcdefghijklmnopqrstuvwxyz",
953 "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
955 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",