]> git.lizzy.rs Git - rust.git/blob - src/libstd/ascii.rs
b9c86e2b23586b49b22ad845e677b90ba79002ea
[rust.git] / src / libstd / ascii.rs
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.
4 //
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.
10
11 //! Operations on ASCII strings and characters
12
13 #![experimental]
14
15 use collections::Collection;
16 use fmt;
17 use iter::Iterator;
18 use mem;
19 use option::{Option, Some, None};
20 use slice::{ImmutableVector, MutableVector, Vector};
21 use str::{OwnedStr, Str, StrAllocating, StrSlice};
22 use string::String;
23 use to_str::{IntoStr};
24 use vec::Vec;
25
26 /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
27 #[deriving(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
28 pub struct Ascii { chr: u8 }
29
30 impl Ascii {
31     /// Converts an ascii character into a `u8`.
32     #[inline]
33     pub fn to_byte(self) -> u8 {
34         self.chr
35     }
36
37     /// Converts an ascii character into a `char`.
38     #[inline]
39     pub fn to_char(self) -> char {
40         self.chr as char
41     }
42
43     #[inline]
44     #[allow(missing_doc)]
45     #[deprecated="renamed to `to_lowercase`"]
46     pub fn to_lower(self) -> Ascii {
47         self.to_lowercase()
48     }
49
50     /// Convert to lowercase.
51     #[inline]
52     pub fn to_lowercase(self) -> Ascii {
53         Ascii{chr: ASCII_LOWER_MAP[self.chr as uint]}
54     }
55
56     #[inline]
57     #[allow(missing_doc)]
58     #[deprecated="renamed to `to_uppercase`"]
59     pub fn to_upper(self) -> Ascii {
60         self.to_uppercase()
61     }
62
63     /// Convert to uppercase.
64     #[inline]
65     pub fn to_uppercase(self) -> Ascii {
66         Ascii{chr: ASCII_UPPER_MAP[self.chr as uint]}
67     }
68
69     /// Compares two ascii characters of equality, ignoring case.
70     #[inline]
71     pub fn eq_ignore_case(self, other: Ascii) -> bool {
72         ASCII_LOWER_MAP[self.chr as uint] == ASCII_LOWER_MAP[other.chr as uint]
73     }
74
75     // the following methods are like ctype, and the implementation is inspired by musl
76
77     #[inline]
78     #[allow(missing_doc)]
79     #[deprecated="renamed to `is_alphabetic`"]
80     pub fn is_alpha(&self) -> bool {
81         self.is_alphabetic()
82     }
83
84     /// Check if the character is a letter (a-z, A-Z)
85     #[inline]
86     pub fn is_alphabetic(&self) -> bool {
87         (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
88     }
89
90     /// Check if the character is a number (0-9)
91     #[inline]
92     pub fn is_digit(&self) -> bool {
93         self.chr >= 0x30 && self.chr <= 0x39
94     }
95
96     #[inline]
97     #[allow(missing_doc)]
98     #[deprecated="renamed to `is_alphanumeric`"]
99     pub fn is_alnum(&self) -> bool {
100         self.is_alphanumeric()
101     }
102
103     /// Check if the character is a letter or number
104     #[inline]
105     pub fn is_alphanumeric(&self) -> bool {
106         self.is_alpha() || self.is_digit()
107     }
108
109     /// Check if the character is a space or horizontal tab
110     #[inline]
111     pub fn is_blank(&self) -> bool {
112         self.chr == ' ' as u8 || self.chr == '\t' as u8
113     }
114
115     /// Check if the character is a control character
116     #[inline]
117     pub fn is_control(&self) -> bool {
118         self.chr < 0x20 || self.chr == 0x7F
119     }
120
121     /// Checks if the character is printable (except space)
122     #[inline]
123     pub fn is_graph(&self) -> bool {
124         (self.chr - 0x21) < 0x5E
125     }
126
127     /// Checks if the character is printable (including space)
128     #[inline]
129     pub fn is_print(&self) -> bool {
130         (self.chr - 0x20) < 0x5F
131     }
132
133     #[inline]
134     #[allow(missing_doc)]
135     #[deprecated="renamed to `is_lowercase`"]
136     pub fn is_lower(&self) -> bool {
137         self.is_lowercase()
138     }
139
140     /// Checks if the character is lowercase
141     #[inline]
142     pub fn is_lowercase(&self) -> bool {
143         (self.chr - 'a' as u8) < 26
144     }
145
146     #[inline]
147     #[allow(missing_doc)]
148     #[deprecated="renamed to `is_uppercase`"]
149     pub fn is_upper(&self) -> bool {
150         self.is_uppercase()
151     }
152
153     /// Checks if the character is uppercase
154     #[inline]
155     pub fn is_uppercase(&self) -> bool {
156         (self.chr - 'A' as u8) < 26
157     }
158
159     /// Checks if the character is punctuation
160     #[inline]
161     pub fn is_punctuation(&self) -> bool {
162         self.is_graph() && !self.is_alnum()
163     }
164
165     /// Checks if the character is a valid hex digit
166     #[inline]
167     pub fn is_hex(&self) -> bool {
168         self.is_digit() || ((self.chr | 32u8) - 'a' as u8) < 6
169     }
170 }
171
172 impl<'a> fmt::Show for Ascii {
173     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174         (self.chr as char).fmt(f)
175     }
176 }
177
178 /// Trait for converting into an ascii type.
179 pub trait AsciiCast<T> {
180     /// Convert to an ascii type, fail on non-ASCII input.
181     #[inline]
182     fn to_ascii(&self) -> T {
183         assert!(self.is_ascii());
184         unsafe {self.to_ascii_nocheck()}
185     }
186
187     /// Convert to an ascii type, return None on non-ASCII input.
188     #[inline]
189     fn to_ascii_opt(&self) -> Option<T> {
190         if self.is_ascii() {
191             Some(unsafe { self.to_ascii_nocheck() })
192         } else {
193             None
194         }
195     }
196
197     /// Convert to an ascii type, not doing any range asserts
198     unsafe fn to_ascii_nocheck(&self) -> T;
199
200     /// Check if convertible to ascii
201     fn is_ascii(&self) -> bool;
202 }
203
204 impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] {
205     #[inline]
206     unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
207         mem::transmute(*self)
208     }
209
210     #[inline]
211     fn is_ascii(&self) -> bool {
212         for b in self.iter() {
213             if !b.is_ascii() { return false; }
214         }
215         true
216     }
217 }
218
219 impl<'a> AsciiCast<&'a [Ascii]> for &'a str {
220     #[inline]
221     unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
222         mem::transmute(*self)
223     }
224
225     #[inline]
226     fn is_ascii(&self) -> bool {
227         self.bytes().all(|b| b.is_ascii())
228     }
229 }
230
231 impl AsciiCast<Ascii> for u8 {
232     #[inline]
233     unsafe fn to_ascii_nocheck(&self) -> Ascii {
234         Ascii{ chr: *self }
235     }
236
237     #[inline]
238     fn is_ascii(&self) -> bool {
239         *self & 128 == 0u8
240     }
241 }
242
243 impl AsciiCast<Ascii> for char {
244     #[inline]
245     unsafe fn to_ascii_nocheck(&self) -> Ascii {
246         Ascii{ chr: *self as u8 }
247     }
248
249     #[inline]
250     fn is_ascii(&self) -> bool {
251         *self as u32 - ('\x7F' as u32 & *self as u32) == 0
252     }
253 }
254
255 /// Trait for copyless casting to an ascii vector.
256 pub trait OwnedAsciiCast {
257     /// Check if convertible to ascii
258     fn is_ascii(&self) -> bool;
259
260     /// Take ownership and cast to an ascii vector. Fail on non-ASCII input.
261     #[inline]
262     fn into_ascii(self) -> Vec<Ascii> {
263         assert!(self.is_ascii());
264         unsafe {self.into_ascii_nocheck()}
265     }
266
267     /// Take ownership and cast to an ascii vector. Return None on non-ASCII input.
268     #[inline]
269     fn into_ascii_opt(self) -> Option<Vec<Ascii>> {
270         if self.is_ascii() {
271             Some(unsafe { self.into_ascii_nocheck() })
272         } else {
273             None
274         }
275     }
276
277     /// Take ownership and cast to an ascii vector.
278     /// Does not perform validation checks.
279     unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
280 }
281
282 impl OwnedAsciiCast for String {
283     #[inline]
284     fn is_ascii(&self) -> bool {
285         self.as_slice().is_ascii()
286     }
287
288     #[inline]
289     unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
290         let v: Vec<u8> = mem::transmute(self);
291         v.into_ascii_nocheck()
292     }
293 }
294
295 impl OwnedAsciiCast for Vec<u8> {
296     #[inline]
297     fn is_ascii(&self) -> bool {
298         self.as_slice().is_ascii()
299     }
300
301     #[inline]
302     unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
303         mem::transmute(self)
304     }
305 }
306
307 /// Trait for converting an ascii type to a string. Needed to convert
308 /// `&[Ascii]` to `&str`.
309 pub trait AsciiStr {
310     /// Convert to a string.
311     fn as_str_ascii<'a>(&'a self) -> &'a str;
312
313     /// Convert to vector representing a lower cased ascii string.
314     fn to_lower(&self) -> Vec<Ascii>;
315
316     /// Convert to vector representing a upper cased ascii string.
317     fn to_upper(&self) -> Vec<Ascii>;
318
319     /// Compares two Ascii strings ignoring case.
320     fn eq_ignore_case(self, other: &[Ascii]) -> bool;
321 }
322
323 impl<'a> AsciiStr for &'a [Ascii] {
324     #[inline]
325     fn as_str_ascii<'a>(&'a self) -> &'a str {
326         unsafe { mem::transmute(*self) }
327     }
328
329     #[inline]
330     fn to_lower(&self) -> Vec<Ascii> {
331         self.iter().map(|a| a.to_lower()).collect()
332     }
333
334     #[inline]
335     fn to_upper(&self) -> Vec<Ascii> {
336         self.iter().map(|a| a.to_upper()).collect()
337     }
338
339     #[inline]
340     fn eq_ignore_case(self, other: &[Ascii]) -> bool {
341         self.iter().zip(other.iter()).all(|(&a, &b)| a.eq_ignore_case(b))
342     }
343 }
344
345 impl IntoStr for Vec<Ascii> {
346     #[inline]
347     fn into_string(self) -> String {
348         unsafe {
349             let s: &str = mem::transmute(self.as_slice());
350             String::from_str(s)
351         }
352     }
353 }
354
355 /// Trait to convert to an owned byte vector by consuming self
356 pub trait IntoBytes {
357     /// Converts to an owned byte vector by consuming self
358     fn into_bytes(self) -> Vec<u8>;
359 }
360
361 impl IntoBytes for Vec<Ascii> {
362     fn into_bytes(self) -> Vec<u8> {
363         unsafe { mem::transmute(self) }
364     }
365 }
366
367 /// Extension methods for ASCII-subset only operations on owned strings
368 pub trait OwnedStrAsciiExt {
369     /// Convert the string to ASCII upper case:
370     /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
371     /// but non-ASCII letters are unchanged.
372     fn into_ascii_upper(self) -> String;
373
374     /// Convert the string to ASCII lower case:
375     /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
376     /// but non-ASCII letters are unchanged.
377     fn into_ascii_lower(self) -> String;
378 }
379
380 /// Extension methods for ASCII-subset only operations on string slices
381 pub trait StrAsciiExt {
382     /// Makes a copy of the string in ASCII upper case:
383     /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
384     /// but non-ASCII letters are unchanged.
385     fn to_ascii_upper(&self) -> String;
386
387     /// Makes a copy of the string in ASCII lower case:
388     /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
389     /// but non-ASCII letters are unchanged.
390     fn to_ascii_lower(&self) -> String;
391
392     /// Check that two strings are an ASCII case-insensitive match.
393     /// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
394     /// but without allocating and copying temporary strings.
395     fn eq_ignore_ascii_case(&self, other: &str) -> bool;
396 }
397
398 impl<'a> StrAsciiExt for &'a str {
399     #[inline]
400     fn to_ascii_upper(&self) -> String {
401         unsafe { str_copy_map_bytes(*self, ASCII_UPPER_MAP) }
402     }
403
404     #[inline]
405     fn to_ascii_lower(&self) -> String {
406         unsafe { str_copy_map_bytes(*self, ASCII_LOWER_MAP) }
407     }
408
409     #[inline]
410     fn eq_ignore_ascii_case(&self, other: &str) -> bool {
411         self.len() == other.len() &&
412             self.as_bytes().iter().zip(other.as_bytes().iter()).all(
413             |(byte_self, byte_other)| {
414                 ASCII_LOWER_MAP[*byte_self as uint] ==
415                     ASCII_LOWER_MAP[*byte_other as uint]
416             })
417     }
418 }
419
420 impl OwnedStrAsciiExt for String {
421     #[inline]
422     fn into_ascii_upper(self) -> String {
423         unsafe { str_map_bytes(self, ASCII_UPPER_MAP) }
424     }
425
426     #[inline]
427     fn into_ascii_lower(self) -> String {
428         unsafe { str_map_bytes(self, ASCII_LOWER_MAP) }
429     }
430 }
431
432 #[inline]
433 unsafe fn str_map_bytes(string: String, map: &'static [u8]) -> String {
434     let mut bytes = string.into_bytes();
435
436     for b in bytes.mut_iter() {
437         *b = map[*b as uint];
438     }
439
440     String::from_utf8(bytes).unwrap()
441 }
442
443 #[inline]
444 unsafe fn str_copy_map_bytes(string: &str, map: &'static [u8]) -> String {
445     let mut s = String::from_str(string);
446     for b in s.as_mut_bytes().mut_iter() {
447         *b = map[*b as uint];
448     }
449     s.into_string()
450 }
451
452 static ASCII_LOWER_MAP: &'static [u8] = &[
453     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
454     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
455     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
456     0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
457     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
458     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
459     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
460     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
461     0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
462     0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
463     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
464     0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
465     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
466     0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
467     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
468     0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
469     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
470     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
471     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
472     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
473     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
474     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
475     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
476     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
477     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
478     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
479     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
480     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
481     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
482     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
483     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
484     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
485 ];
486
487 static ASCII_UPPER_MAP: &'static [u8] = &[
488     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
489     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
490     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
491     0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
492     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
493     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
494     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
495     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
496     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
497     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
498     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
499     0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
500     0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
501     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
502     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
503     0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
504     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
505     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
506     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
507     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
508     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
509     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
510     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
511     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
512     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
513     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
514     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
515     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
516     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
517     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
518     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
519     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
520 ];
521
522
523 #[cfg(test)]
524 mod tests {
525     use prelude::*;
526     use super::*;
527     use char::from_u32;
528     use vec::Vec;
529     use str::StrSlice;
530
531     macro_rules! v2ascii (
532         ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
533         (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
534     )
535
536     macro_rules! vec2ascii (
537         ($($e:expr),*) => (Vec::from_slice([$(Ascii{chr:$e}),*]));
538     )
539
540     #[test]
541     fn test_ascii() {
542         assert_eq!(65u8.to_ascii().to_byte(), 65u8);
543         assert_eq!(65u8.to_ascii().to_char(), 'A');
544         assert_eq!('A'.to_ascii().to_char(), 'A');
545         assert_eq!('A'.to_ascii().to_byte(), 65u8);
546
547         assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
548         assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
549         assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
550         assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');
551
552         assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
553         assert_eq!('['.to_ascii().to_lower().to_char(), '[');
554         assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
555         assert_eq!('{'.to_ascii().to_upper().to_char(), '{');
556
557         assert!('0'.to_ascii().is_digit());
558         assert!('9'.to_ascii().is_digit());
559         assert!(!'/'.to_ascii().is_digit());
560         assert!(!':'.to_ascii().is_digit());
561
562         assert!((0x1fu8).to_ascii().is_control());
563         assert!(!' '.to_ascii().is_control());
564         assert!((0x7fu8).to_ascii().is_control());
565
566         assert!("banana".chars().all(|c| c.is_ascii()));
567         assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
568     }
569
570     #[test]
571     fn test_ascii_vec() {
572         let test = &[40u8, 32u8, 59u8];
573         assert_eq!(test.to_ascii(), v2ascii!([40, 32, 59]));
574         assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59]));
575         let v = vec![40u8, 32u8, 59u8];
576         assert_eq!(v.as_slice().to_ascii(), v2ascii!([40, 32, 59]));
577         assert_eq!("( ;".to_string().as_slice().to_ascii(), v2ascii!([40, 32, 59]));
578
579         assert_eq!("abCDef&?#".to_ascii().to_lower().into_string(), "abcdef&?#".to_string());
580         assert_eq!("abCDef&?#".to_ascii().to_upper().into_string(), "ABCDEF&?#".to_string());
581
582         assert_eq!("".to_ascii().to_lower().into_string(), "".to_string());
583         assert_eq!("YMCA".to_ascii().to_lower().into_string(), "ymca".to_string());
584         assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_string(), "ABCDEFXYZ:.;".to_string());
585
586         assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
587
588         assert!("".is_ascii());
589         assert!("a".is_ascii());
590         assert!(!"\u2009".is_ascii());
591
592     }
593
594     #[test]
595     fn test_ascii_vec_ng() {
596         assert_eq!("abCDef&?#".to_ascii().to_lower().into_string(), "abcdef&?#".to_string());
597         assert_eq!("abCDef&?#".to_ascii().to_upper().into_string(), "ABCDEF&?#".to_string());
598         assert_eq!("".to_ascii().to_lower().into_string(), "".to_string());
599         assert_eq!("YMCA".to_ascii().to_lower().into_string(), "ymca".to_string());
600         assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_string(), "ABCDEFXYZ:.;".to_string());
601     }
602
603     #[test]
604     fn test_owned_ascii_vec() {
605         assert_eq!(("( ;".to_string()).into_ascii(), vec2ascii![40, 32, 59]);
606         assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii(), vec2ascii![40, 32, 59]);
607     }
608
609     #[test]
610     fn test_ascii_as_str() {
611         let v = v2ascii!([40, 32, 59]);
612         assert_eq!(v.as_str_ascii(), "( ;");
613     }
614
615     #[test]
616     fn test_ascii_into_string() {
617         assert_eq!(vec2ascii![40, 32, 59].into_string(), "( ;".to_string());
618         assert_eq!(vec2ascii!(40, 32, 59).into_string(), "( ;".to_string());
619     }
620
621     #[test]
622     fn test_ascii_to_bytes() {
623         assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
624     }
625
626     #[test] #[should_fail]
627     fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }
628
629     #[test] #[should_fail]
630     fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }
631
632     #[test] #[should_fail]
633     fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }
634
635     #[test] #[should_fail]
636     fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
637
638     #[test]
639     fn test_opt() {
640         assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
641         assert_eq!(255u8.to_ascii_opt(), None);
642
643         assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
644         assert_eq!('λ'.to_ascii_opt(), None);
645
646         assert_eq!("zoä华".to_ascii_opt(), None);
647
648         let test1 = &[127u8, 128u8, 255u8];
649         assert_eq!((test1).to_ascii_opt(), None);
650
651         let v = [40u8, 32u8, 59u8];
652         let v2 = v2ascii!(&[40, 32, 59]);
653         assert_eq!(v.to_ascii_opt(), Some(v2));
654         let v = [127u8, 128u8, 255u8];
655         assert_eq!(v.to_ascii_opt(), None);
656
657         let v = "( ;";
658         let v2 = v2ascii!(&[40, 32, 59]);
659         assert_eq!(v.to_ascii_opt(), Some(v2));
660         assert_eq!("zoä华".to_ascii_opt(), None);
661
662         assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
663         assert_eq!((vec![127u8, 128u8, 255u8]).into_ascii_opt(), None);
664
665         assert_eq!(("( ;".to_string()).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
666         assert_eq!(("zoä华".to_string()).into_ascii_opt(), None);
667     }
668
669     #[test]
670     fn test_to_ascii_upper() {
671         assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), "URL()URL()URL()üRL".to_string());
672         assert_eq!("hıKß".to_ascii_upper(), "HıKß".to_string());
673
674         let mut i = 0;
675         while i <= 500 {
676             let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
677                         else { i };
678             assert_eq!((from_u32(i).unwrap()).to_string().as_slice().to_ascii_upper(),
679                        (from_u32(upper).unwrap()).to_string())
680             i += 1;
681         }
682     }
683
684     #[test]
685     fn test_to_ascii_lower() {
686         assert_eq!("url()URL()uRl()Ürl".to_ascii_lower(), "url()url()url()Ürl".to_string());
687         // Dotted capital I, Kelvin sign, Sharp S.
688         assert_eq!("HİKß".to_ascii_lower(), "hİKß".to_string());
689
690         let mut i = 0;
691         while i <= 500 {
692             let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
693                         else { i };
694             assert_eq!((from_u32(i).unwrap()).to_string().as_slice().to_ascii_lower(),
695                        (from_u32(lower).unwrap()).to_string())
696             i += 1;
697         }
698     }
699
700     #[test]
701     fn test_into_ascii_upper() {
702         assert_eq!(("url()URL()uRl()ürl".to_string()).into_ascii_upper(),
703                    "URL()URL()URL()üRL".to_string());
704         assert_eq!(("hıKß".to_string()).into_ascii_upper(), "HıKß".to_string());
705
706         let mut i = 0;
707         while i <= 500 {
708             let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
709                         else { i };
710             assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_upper(),
711                        (from_u32(upper).unwrap()).to_string())
712             i += 1;
713         }
714     }
715
716     #[test]
717     fn test_into_ascii_lower() {
718         assert_eq!(("url()URL()uRl()Ürl".to_string()).into_ascii_lower(),
719                    "url()url()url()Ürl".to_string());
720         // Dotted capital I, Kelvin sign, Sharp S.
721         assert_eq!(("HİKß".to_string()).into_ascii_lower(), "hİKß".to_string());
722
723         let mut i = 0;
724         while i <= 500 {
725             let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
726                         else { i };
727             assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_lower(),
728                        (from_u32(lower).unwrap()).to_string())
729             i += 1;
730         }
731     }
732
733     #[test]
734     fn test_eq_ignore_ascii_case() {
735         assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
736         assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
737         // Dotted capital I, Kelvin sign, Sharp S.
738         assert!("HİKß".eq_ignore_ascii_case("hİKß"));
739         assert!(!"İ".eq_ignore_ascii_case("i"));
740         assert!(!"K".eq_ignore_ascii_case("k"));
741         assert!(!"ß".eq_ignore_ascii_case("s"));
742
743         let mut i = 0;
744         while i <= 500 {
745             let c = i;
746             let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 }
747                         else { c };
748             assert!((from_u32(i).unwrap()).to_string().as_slice().eq_ignore_ascii_case(
749                     (from_u32(lower).unwrap()).to_string().as_slice()));
750             i += 1;
751         }
752     }
753
754     #[test]
755     fn test_to_string() {
756         let s = Ascii{ chr: 't' as u8 }.to_string();
757         assert_eq!(s, "t".to_string());
758     }
759
760     #[test]
761     fn test_show() {
762         let c = Ascii { chr: 't' as u8 };
763         assert_eq!(format!("{}", c), "t".to_string());
764     }
765 }