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