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
15 #![unstable = "unsure about placement and naming"]
18 use core::kinds::Sized;
20 use iter::IteratorExt;
23 use option::Option::{Some, None};
24 use slice::{SlicePrelude, AsSlice};
25 use str::{Str, StrPrelude};
26 use string::{String, IntoString};
29 /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
30 #[deriving(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
31 pub struct Ascii { chr: u8 }
34 /// Converts an ascii character into a `u8`.
36 #[unstable = "recently renamed"]
37 pub fn as_byte(&self) -> u8 {
41 /// Deprecated: use `as_byte` isntead.
42 #[deprecated = "use as_byte"]
43 pub fn to_byte(self) -> u8 {
47 /// Converts an ascii character into a `char`.
49 #[unstable = "recently renamed"]
50 pub fn as_char(&self) -> char {
54 /// Deprecated: use `as_char` isntead.
55 #[deprecated = "use as_char"]
56 pub fn to_char(self) -> char {
60 /// Convert to lowercase.
63 pub fn to_lowercase(&self) -> Ascii {
64 Ascii{chr: ASCII_LOWER_MAP[self.chr as uint]}
67 /// Convert to uppercase.
70 pub fn to_uppercase(&self) -> Ascii {
71 Ascii{chr: ASCII_UPPER_MAP[self.chr as uint]}
74 /// Compares two ascii characters of equality, ignoring case.
76 #[deprecated = "normalize with to_lowercase"]
77 pub fn eq_ignore_case(self, other: Ascii) -> bool {
78 ASCII_LOWER_MAP[self.chr as uint] == ASCII_LOWER_MAP[other.chr as uint]
81 // the following methods are like ctype, and the implementation is inspired by musl
83 /// Check if the character is a letter (a-z, A-Z)
86 pub fn is_alphabetic(&self) -> bool {
87 (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
90 /// Check if the character is a number (0-9)
92 #[unstable = "may be renamed"]
93 pub fn is_digit(&self) -> bool {
94 self.chr >= 0x30 && self.chr <= 0x39
97 /// Check if the character is a letter or number
100 pub fn is_alphanumeric(&self) -> bool {
101 self.is_alphabetic() || self.is_digit()
104 /// Check if the character is a space or horizontal tab
106 #[experimental = "likely to be removed"]
107 pub fn is_blank(&self) -> bool {
108 self.chr == b' ' || self.chr == b'\t'
111 /// Check if the character is a control character
114 pub fn is_control(&self) -> bool {
115 self.chr < 0x20 || self.chr == 0x7F
118 /// Checks if the character is printable (except space)
120 #[experimental = "unsure about naming, or whether this is needed"]
121 pub fn is_graph(&self) -> bool {
122 (self.chr - 0x21) < 0x5E
125 /// Checks if the character is printable (including space)
127 #[unstable = "unsure about naming"]
128 pub fn is_print(&self) -> bool {
129 (self.chr - 0x20) < 0x5F
132 /// Checks if the character is alphabetic and lowercase
135 pub fn is_lowercase(&self) -> bool {
136 (self.chr - b'a') < 26
139 /// Checks if the character is alphabetic and uppercase
142 pub fn is_uppercase(&self) -> bool {
143 (self.chr - b'A') < 26
146 /// Checks if the character is punctuation
149 pub fn is_punctuation(&self) -> bool {
150 self.is_graph() && !self.is_alphanumeric()
153 /// Checks if the character is a valid hex digit
156 pub fn is_hex(&self) -> bool {
157 self.is_digit() || ((self.chr | 32u8) - b'a') < 6
161 impl<'a> fmt::Show for Ascii {
162 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163 (self.chr as char).fmt(f)
167 /// Trait for converting into an ascii type.
168 #[experimental = "may be replaced by generic conversion traits"]
169 pub trait AsciiCast<T> {
170 /// Convert to an ascii type, panic on non-ASCII input.
172 fn to_ascii(&self) -> T {
173 assert!(self.is_ascii());
174 unsafe {self.to_ascii_nocheck()}
177 /// Convert to an ascii type, return None on non-ASCII input.
179 fn to_ascii_opt(&self) -> Option<T> {
181 Some(unsafe { self.to_ascii_nocheck() })
187 /// Convert to an ascii type, not doing any range asserts
188 unsafe fn to_ascii_nocheck(&self) -> T;
190 /// Check if convertible to ascii
191 fn is_ascii(&self) -> bool;
194 #[experimental = "may be replaced by generic conversion traits"]
195 impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] {
197 unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
198 mem::transmute(*self)
202 fn is_ascii(&self) -> bool {
203 for b in self.iter() {
204 if !b.is_ascii() { return false; }
210 #[experimental = "may be replaced by generic conversion traits"]
211 impl<'a> AsciiCast<&'a [Ascii]> for &'a str {
213 unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
214 mem::transmute(*self)
218 fn is_ascii(&self) -> bool {
219 self.bytes().all(|b| b.is_ascii())
223 #[experimental = "may be replaced by generic conversion traits"]
224 impl AsciiCast<Ascii> for u8 {
226 unsafe fn to_ascii_nocheck(&self) -> Ascii {
231 fn is_ascii(&self) -> bool {
236 #[experimental = "may be replaced by generic conversion traits"]
237 impl AsciiCast<Ascii> for char {
239 unsafe fn to_ascii_nocheck(&self) -> Ascii {
240 Ascii{ chr: *self as u8 }
244 fn is_ascii(&self) -> bool {
245 *self as u32 - ('\x7F' as u32 & *self as u32) == 0
249 /// Trait for copyless casting to an ascii vector.
250 #[experimental = "may be replaced by generic conversion traits"]
251 pub trait OwnedAsciiCast {
252 /// Check if convertible to ascii
253 fn is_ascii(&self) -> bool;
255 /// Take ownership and cast to an ascii vector.
258 /// Panic on non-ASCII input.
260 fn into_ascii(self) -> Vec<Ascii> {
261 assert!(self.is_ascii());
262 unsafe {self.into_ascii_nocheck()}
265 /// Take ownership and cast to an ascii vector. Return None on non-ASCII input.
267 fn into_ascii_opt(self) -> Option<Vec<Ascii>> {
269 Some(unsafe { self.into_ascii_nocheck() })
275 /// Take ownership and cast to an ascii vector.
276 /// Does not perform validation checks.
277 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
280 #[experimental = "may be replaced by generic conversion traits"]
281 impl OwnedAsciiCast for String {
283 fn is_ascii(&self) -> bool {
284 self.as_slice().is_ascii()
288 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
289 self.into_bytes().into_ascii_nocheck()
293 #[experimental = "may be replaced by generic conversion traits"]
294 impl OwnedAsciiCast for Vec<u8> {
296 fn is_ascii(&self) -> bool {
297 self.as_slice().is_ascii()
301 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
302 let v = Vec::from_raw_parts(self.as_ptr() as *mut Ascii,
306 // We forget `self` to avoid freeing it at the end of the scope
307 // Otherwise, the returned `Vec` would point to freed memory
313 /// Trait for converting an ascii type to a string. Needed to convert
314 /// `&[Ascii]` to `&str`.
315 #[experimental = "may be replaced by generic conversion traits"]
316 pub trait AsciiStr for Sized? {
317 /// Convert to a string.
318 fn as_str_ascii<'a>(&'a self) -> &'a str;
320 /// Deprecated: use `to_lowercase`
321 #[deprecated="renamed `to_lowercase`"]
322 fn to_lower(&self) -> Vec<Ascii>;
324 /// Convert to vector representing a lower cased ascii string.
325 #[deprecated = "use iterators instead"]
326 fn to_lowercase(&self) -> Vec<Ascii>;
328 /// Deprecated: use `to_uppercase`
329 #[deprecated="renamed `to_uppercase`"]
330 fn to_upper(&self) -> Vec<Ascii>;
332 /// Convert to vector representing a upper cased ascii string.
333 #[deprecated = "use iterators instead"]
334 fn to_uppercase(&self) -> Vec<Ascii>;
336 /// Compares two Ascii strings ignoring case.
337 #[deprecated = "use iterators instead"]
338 fn eq_ignore_case(&self, other: &[Ascii]) -> bool;
341 #[experimental = "may be replaced by generic conversion traits"]
342 impl AsciiStr for [Ascii] {
344 fn as_str_ascii<'a>(&'a self) -> &'a str {
345 unsafe { mem::transmute(self) }
349 fn to_lower(&self) -> Vec<Ascii> {
354 fn to_lowercase(&self) -> Vec<Ascii> {
355 self.iter().map(|a| a.to_lowercase()).collect()
359 fn to_upper(&self) -> Vec<Ascii> {
364 fn to_uppercase(&self) -> Vec<Ascii> {
365 self.iter().map(|a| a.to_uppercase()).collect()
369 fn eq_ignore_case(&self, other: &[Ascii]) -> bool {
370 self.iter().zip(other.iter()).all(|(&a, &b)| a.eq_ignore_case(b))
374 impl IntoString for Vec<Ascii> {
376 fn into_string(self) -> String {
377 unsafe { String::from_utf8_unchecked(self.into_bytes()) }
381 /// Trait to convert to an owned byte vector by consuming self
382 #[experimental = "may be replaced by generic conversion traits"]
383 pub trait IntoBytes {
384 /// Converts to an owned byte vector by consuming self
385 fn into_bytes(self) -> Vec<u8>;
388 #[experimental = "may be replaced by generic conversion traits"]
389 impl IntoBytes for Vec<Ascii> {
390 fn into_bytes(self) -> Vec<u8> {
392 let v = Vec::from_raw_parts(self.as_ptr() as *mut u8,
396 // We forget `self` to avoid freeing it at the end of the scope
397 // Otherwise, the returned `Vec` would point to freed memory
405 /// Extension methods for ASCII-subset only operations on owned strings
406 #[experimental = "would prefer to do this in a more general way"]
407 pub trait OwnedAsciiExt {
408 /// Convert the string to ASCII upper case:
409 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
410 /// but non-ASCII letters are unchanged.
411 fn into_ascii_upper(self) -> Self;
413 /// Convert the string to ASCII lower case:
414 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
415 /// but non-ASCII letters are unchanged.
416 fn into_ascii_lower(self) -> Self;
419 /// Extension methods for ASCII-subset only operations on string slices
420 #[experimental = "would prefer to do this in a more general way"]
421 pub trait AsciiExt<T> for Sized? {
422 /// Makes a copy of the string in ASCII upper case:
423 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
424 /// but non-ASCII letters are unchanged.
425 fn to_ascii_upper(&self) -> T;
427 /// Makes a copy of the string in ASCII lower case:
428 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
429 /// but non-ASCII letters are unchanged.
430 fn to_ascii_lower(&self) -> T;
432 /// Check that two strings are an ASCII case-insensitive match.
433 /// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
434 /// but without allocating and copying temporary strings.
435 fn eq_ignore_ascii_case(&self, other: &Self) -> bool;
438 #[experimental = "would prefer to do this in a more general way"]
439 impl AsciiExt<String> for str {
441 fn to_ascii_upper(&self) -> String {
442 // Vec<u8>::to_ascii_upper() preserves the UTF-8 invariant.
443 unsafe { String::from_utf8_unchecked(self.as_bytes().to_ascii_upper()) }
447 fn to_ascii_lower(&self) -> String {
448 // Vec<u8>::to_ascii_lower() preserves the UTF-8 invariant.
449 unsafe { String::from_utf8_unchecked(self.as_bytes().to_ascii_lower()) }
453 fn eq_ignore_ascii_case(&self, other: &str) -> bool {
454 self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
458 #[experimental = "would prefer to do this in a more general way"]
459 impl OwnedAsciiExt for String {
461 fn into_ascii_upper(self) -> String {
462 // Vec<u8>::into_ascii_upper() preserves the UTF-8 invariant.
463 unsafe { String::from_utf8_unchecked(self.into_bytes().into_ascii_upper()) }
467 fn into_ascii_lower(self) -> String {
468 // Vec<u8>::into_ascii_lower() preserves the UTF-8 invariant.
469 unsafe { String::from_utf8_unchecked(self.into_bytes().into_ascii_lower()) }
473 #[experimental = "would prefer to do this in a more general way"]
474 impl AsciiExt<Vec<u8>> for [u8] {
476 fn to_ascii_upper(&self) -> Vec<u8> {
477 self.iter().map(|&byte| ASCII_UPPER_MAP[byte as uint]).collect()
481 fn to_ascii_lower(&self) -> Vec<u8> {
482 self.iter().map(|&byte| ASCII_LOWER_MAP[byte as uint]).collect()
486 fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
487 self.len() == other.len() &&
488 self.iter().zip(other.iter()).all(
489 |(byte_self, byte_other)| {
490 ASCII_LOWER_MAP[*byte_self as uint] ==
491 ASCII_LOWER_MAP[*byte_other as uint]
496 #[experimental = "would prefer to do this in a more general way"]
497 impl OwnedAsciiExt for Vec<u8> {
499 fn into_ascii_upper(mut self) -> Vec<u8> {
500 for byte in self.iter_mut() {
501 *byte = ASCII_UPPER_MAP[*byte as uint];
507 fn into_ascii_lower(mut self) -> Vec<u8> {
508 for byte in self.iter_mut() {
509 *byte = ASCII_LOWER_MAP[*byte as uint];
515 /// Returns a 'default' ASCII and C++11-like literal escape of a `u8`
517 /// The default is chosen with a bias toward producing literals that are
518 /// legal in a variety of languages, including C++11 and similar C-family
519 /// languages. The exact rules are:
521 /// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
522 /// - Single-quote, double-quote and backslash chars are backslash-escaped.
523 /// - Any other chars in the range [0x20,0x7e] are not escaped.
524 /// - Any other chars are given hex escapes.
525 /// - Unicode escapes are never generated by this function.
526 #[unstable = "needs to be updated to use an iterator"]
527 pub fn escape_default(c: u8, f: |u8|) {
529 b'\t' => { f(b'\\'); f(b't'); }
530 b'\r' => { f(b'\\'); f(b'r'); }
531 b'\n' => { f(b'\\'); f(b'n'); }
532 b'\\' => { f(b'\\'); f(b'\\'); }
533 b'\'' => { f(b'\\'); f(b'\''); }
534 b'"' => { f(b'\\'); f(b'"'); }
535 b'\x20' ... b'\x7e' => { f(c); }
539 for &offset in [4u, 0u].iter() {
540 match ((c as i32) >> offset) & 0xf {
541 i @ 0 ... 9 => f(b'0' + (i as u8)),
542 i => f(b'a' + (i as u8 - 10)),
549 static ASCII_LOWER_MAP: [u8, ..256] = [
550 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
551 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
552 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
553 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
554 b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
555 b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
556 b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
557 b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
560 b'a', b'b', b'c', b'd', b'e', b'f', b'g',
561 b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
562 b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
565 b'[', b'\\', b']', b'^', b'_',
566 b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g',
567 b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
568 b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
569 b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f,
570 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
571 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
572 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
573 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
574 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
575 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
576 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
577 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
578 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
579 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
580 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
581 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
582 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
583 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
584 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
585 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
588 static ASCII_UPPER_MAP: [u8, ..256] = [
589 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
590 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
591 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
592 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
593 b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
594 b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
595 b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
596 b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
597 b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
598 b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
599 b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
600 b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
603 b'A', b'B', b'C', b'D', b'E', b'F', b'G',
604 b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
605 b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
608 b'{', b'|', b'}', b'~', 0x7f,
609 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
610 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
611 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
612 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
613 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
614 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
615 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
616 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
617 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
618 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
619 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
620 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
621 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
622 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
623 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
624 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
635 macro_rules! v2ascii (
636 ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
637 (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
640 macro_rules! vec2ascii (
641 ($($e:expr),*) => ([$(Ascii{chr:$e}),*].to_vec());
646 assert_eq!(65u8.to_ascii().to_byte(), 65u8);
647 assert_eq!(65u8.to_ascii().to_char(), 'A');
648 assert_eq!('A'.to_ascii().to_char(), 'A');
649 assert_eq!('A'.to_ascii().to_byte(), 65u8);
651 assert_eq!('A'.to_ascii().to_lowercase().to_char(), 'a');
652 assert_eq!('Z'.to_ascii().to_lowercase().to_char(), 'z');
653 assert_eq!('a'.to_ascii().to_uppercase().to_char(), 'A');
654 assert_eq!('z'.to_ascii().to_uppercase().to_char(), 'Z');
656 assert_eq!('@'.to_ascii().to_lowercase().to_char(), '@');
657 assert_eq!('['.to_ascii().to_lowercase().to_char(), '[');
658 assert_eq!('`'.to_ascii().to_uppercase().to_char(), '`');
659 assert_eq!('{'.to_ascii().to_uppercase().to_char(), '{');
661 assert!('0'.to_ascii().is_digit());
662 assert!('9'.to_ascii().is_digit());
663 assert!(!'/'.to_ascii().is_digit());
664 assert!(!':'.to_ascii().is_digit());
666 assert!((0x1fu8).to_ascii().is_control());
667 assert!(!' '.to_ascii().is_control());
668 assert!((0x7fu8).to_ascii().is_control());
670 assert!("banana".chars().all(|c| c.is_ascii()));
671 assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
675 fn test_ascii_vec() {
676 let test = &[40u8, 32u8, 59u8];
677 let b: &[_] = v2ascii!([40, 32, 59]);
678 assert_eq!(test.to_ascii(), b);
679 assert_eq!("( ;".to_ascii(), b);
680 let v = vec![40u8, 32u8, 59u8];
681 assert_eq!(v.as_slice().to_ascii(), b);
682 assert_eq!("( ;".to_string().as_slice().to_ascii(), b);
684 assert_eq!("abCDef&?#".to_ascii().to_lowercase().into_string(), "abcdef&?#".to_string());
685 assert_eq!("abCDef&?#".to_ascii().to_uppercase().into_string(), "ABCDEF&?#".to_string());
687 assert_eq!("".to_ascii().to_lowercase().into_string(), "".to_string());
688 assert_eq!("YMCA".to_ascii().to_lowercase().into_string(), "ymca".to_string());
689 let mixed = "abcDEFxyz:.;".to_ascii();
690 assert_eq!(mixed.to_uppercase().into_string(), "ABCDEFXYZ:.;".to_string());
692 assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
694 assert!("".is_ascii());
695 assert!("a".is_ascii());
696 assert!(!"\u2009".is_ascii());
701 fn test_ascii_vec_ng() {
702 assert_eq!("abCDef&?#".to_ascii().to_lowercase().into_string(), "abcdef&?#".to_string());
703 assert_eq!("abCDef&?#".to_ascii().to_uppercase().into_string(), "ABCDEF&?#".to_string());
704 assert_eq!("".to_ascii().to_lowercase().into_string(), "".to_string());
705 assert_eq!("YMCA".to_ascii().to_lowercase().into_string(), "ymca".to_string());
706 let mixed = "abcDEFxyz:.;".to_ascii();
707 assert_eq!(mixed.to_uppercase().into_string(), "ABCDEFXYZ:.;".to_string());
711 fn test_owned_ascii_vec() {
712 assert_eq!(("( ;".to_string()).into_ascii(), vec2ascii![40, 32, 59]);
713 assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii(), vec2ascii![40, 32, 59]);
717 fn test_ascii_as_str() {
718 let v = v2ascii!([40, 32, 59]);
719 assert_eq!(v.as_str_ascii(), "( ;");
723 fn test_ascii_into_string() {
724 assert_eq!(vec2ascii![40, 32, 59].into_string(), "( ;".to_string());
725 assert_eq!(vec2ascii!(40, 32, 59).into_string(), "( ;".to_string());
729 fn test_ascii_to_bytes() {
730 assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
733 #[test] #[should_fail]
734 fn test_ascii_vec_panic_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii(); }
736 #[test] #[should_fail]
737 fn test_ascii_vec_panic_str_slice() { "zoä华".to_ascii(); }
739 #[test] #[should_fail]
740 fn test_ascii_panic_u8_slice() { 255u8.to_ascii(); }
742 #[test] #[should_fail]
743 fn test_ascii_panic_char_slice() { 'λ'.to_ascii(); }
747 assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
748 assert_eq!(255u8.to_ascii_opt(), None);
750 assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
751 assert_eq!('λ'.to_ascii_opt(), None);
753 assert_eq!("zoä华".to_ascii_opt(), None);
755 let test1 = &[127u8, 128u8, 255u8];
756 assert_eq!((test1).to_ascii_opt(), None);
758 let v = [40u8, 32u8, 59u8];
759 let v2: &[_] = v2ascii!(&[40, 32, 59]);
760 assert_eq!(v.to_ascii_opt(), Some(v2));
761 let v = [127u8, 128u8, 255u8];
762 assert_eq!(v.to_ascii_opt(), None);
765 assert_eq!(v.to_ascii_opt(), Some(v2));
766 assert_eq!("zoä华".to_ascii_opt(), None);
768 assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
769 assert_eq!((vec![127u8, 128u8, 255u8]).into_ascii_opt(), None);
771 assert_eq!(("( ;".to_string()).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
772 assert_eq!(("zoä华".to_string()).into_ascii_opt(), None);
776 fn test_to_ascii_upper() {
777 assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), "URL()URL()URL()üRL".to_string());
778 assert_eq!("hıKß".to_ascii_upper(), "HıKß".to_string());
782 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
784 assert_eq!((from_u32(i).unwrap()).to_string().as_slice().to_ascii_upper(),
785 (from_u32(upper).unwrap()).to_string())
791 fn test_to_ascii_lower() {
792 assert_eq!("url()URL()uRl()Ürl".to_ascii_lower(), "url()url()url()Ürl".to_string());
793 // Dotted capital I, Kelvin sign, Sharp S.
794 assert_eq!("HİKß".to_ascii_lower(), "hİKß".to_string());
798 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
800 assert_eq!((from_u32(i).unwrap()).to_string().as_slice().to_ascii_lower(),
801 (from_u32(lower).unwrap()).to_string())
807 fn test_into_ascii_upper() {
808 assert_eq!(("url()URL()uRl()ürl".to_string()).into_ascii_upper(),
809 "URL()URL()URL()üRL".to_string());
810 assert_eq!(("hıKß".to_string()).into_ascii_upper(), "HıKß".to_string());
814 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
816 assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_upper(),
817 (from_u32(upper).unwrap()).to_string())
823 fn test_into_ascii_lower() {
824 assert_eq!(("url()URL()uRl()Ürl".to_string()).into_ascii_lower(),
825 "url()url()url()Ürl".to_string());
826 // Dotted capital I, Kelvin sign, Sharp S.
827 assert_eq!(("HİKß".to_string()).into_ascii_lower(), "hİKß".to_string());
831 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
833 assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_lower(),
834 (from_u32(lower).unwrap()).to_string())
840 fn test_eq_ignore_ascii_case() {
841 assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
842 assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
843 // Dotted capital I, Kelvin sign, Sharp S.
844 assert!("HİKß".eq_ignore_ascii_case("hİKß"));
845 assert!(!"İ".eq_ignore_ascii_case("i"));
846 assert!(!"K".eq_ignore_ascii_case("k"));
847 assert!(!"ß".eq_ignore_ascii_case("s"));
852 let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 }
854 assert!((from_u32(i).unwrap()).to_string().as_slice().eq_ignore_ascii_case(
855 (from_u32(lower).unwrap()).to_string().as_slice()));
861 fn test_to_string() {
862 let s = Ascii{ chr: b't' }.to_string();
863 assert_eq!(s, "t".to_string());
868 let c = Ascii { chr: b't' };
869 assert_eq!(format!("{}", c), "t".to_string());