]> git.lizzy.rs Git - rust.git/blob - src/libstd/ascii.rs
Make std::ascii::ASCII_{UPPER,LOWER}_MAP public.
[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::{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: &[u8, ..256]) -> 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: &[u8, ..256]) -> 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 pub static ASCII_LOWER_MAP: [u8, ..256] = [
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     b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
460     b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
461     b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
462     b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
463     b'@',
464
465           b'a', b'b', b'c', b'd', b'e', b'f', b'g',
466     b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
467     b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
468     b'x', b'y', b'z',
469
470                       b'[', b'\\', b']', b'^', b'_',
471     b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g',
472     b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
473     b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
474     b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f,
475     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
476     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
477     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
478     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
479     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
480     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
481     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
482     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
483     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
484     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
485     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
486     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
487     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
488     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
489     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
490     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
491 ];
492
493 pub static ASCII_UPPER_MAP: [u8, ..256] = [
494     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
495     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
496     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
497     0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
498     b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
499     b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
500     b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
501     b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
502     b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
503     b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
504     b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
505     b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
506     b'`',
507
508           b'A', b'B', b'C', b'D', b'E', b'F', b'G',
509     b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
510     b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
511     b'X', b'Y', b'Z',
512
513                       b'{', b'|', b'}', b'~', 0x7f,
514     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
515     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
516     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
517     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
518     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
519     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
520     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
521     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
522     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
523     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
524     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
525     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
526     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
527     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
528     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
529     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
530 ];
531
532
533 #[cfg(test)]
534 mod tests {
535     use prelude::*;
536     use super::*;
537     use char::from_u32;
538     use vec::Vec;
539     use str::StrSlice;
540
541     macro_rules! v2ascii (
542         ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
543         (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
544     )
545
546     macro_rules! vec2ascii (
547         ($($e:expr),*) => (Vec::from_slice([$(Ascii{chr:$e}),*]));
548     )
549
550     #[test]
551     fn test_ascii() {
552         assert_eq!(65u8.to_ascii().to_byte(), 65u8);
553         assert_eq!(65u8.to_ascii().to_char(), 'A');
554         assert_eq!('A'.to_ascii().to_char(), 'A');
555         assert_eq!('A'.to_ascii().to_byte(), 65u8);
556
557         assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
558         assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
559         assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
560         assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');
561
562         assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
563         assert_eq!('['.to_ascii().to_lower().to_char(), '[');
564         assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
565         assert_eq!('{'.to_ascii().to_upper().to_char(), '{');
566
567         assert!('0'.to_ascii().is_digit());
568         assert!('9'.to_ascii().is_digit());
569         assert!(!'/'.to_ascii().is_digit());
570         assert!(!':'.to_ascii().is_digit());
571
572         assert!((0x1fu8).to_ascii().is_control());
573         assert!(!' '.to_ascii().is_control());
574         assert!((0x7fu8).to_ascii().is_control());
575
576         assert!("banana".chars().all(|c| c.is_ascii()));
577         assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
578     }
579
580     #[test]
581     fn test_ascii_vec() {
582         let test = &[40u8, 32u8, 59u8];
583         assert_eq!(test.to_ascii(), v2ascii!([40, 32, 59]));
584         assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59]));
585         let v = vec![40u8, 32u8, 59u8];
586         assert_eq!(v.as_slice().to_ascii(), v2ascii!([40, 32, 59]));
587         assert_eq!("( ;".to_string().as_slice().to_ascii(), v2ascii!([40, 32, 59]));
588
589         assert_eq!("abCDef&?#".to_ascii().to_lower().into_string(), "abcdef&?#".to_string());
590         assert_eq!("abCDef&?#".to_ascii().to_upper().into_string(), "ABCDEF&?#".to_string());
591
592         assert_eq!("".to_ascii().to_lower().into_string(), "".to_string());
593         assert_eq!("YMCA".to_ascii().to_lower().into_string(), "ymca".to_string());
594         assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_string(), "ABCDEFXYZ:.;".to_string());
595
596         assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
597
598         assert!("".is_ascii());
599         assert!("a".is_ascii());
600         assert!(!"\u2009".is_ascii());
601
602     }
603
604     #[test]
605     fn test_ascii_vec_ng() {
606         assert_eq!("abCDef&?#".to_ascii().to_lower().into_string(), "abcdef&?#".to_string());
607         assert_eq!("abCDef&?#".to_ascii().to_upper().into_string(), "ABCDEF&?#".to_string());
608         assert_eq!("".to_ascii().to_lower().into_string(), "".to_string());
609         assert_eq!("YMCA".to_ascii().to_lower().into_string(), "ymca".to_string());
610         assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_string(), "ABCDEFXYZ:.;".to_string());
611     }
612
613     #[test]
614     fn test_owned_ascii_vec() {
615         assert_eq!(("( ;".to_string()).into_ascii(), vec2ascii![40, 32, 59]);
616         assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii(), vec2ascii![40, 32, 59]);
617     }
618
619     #[test]
620     fn test_ascii_as_str() {
621         let v = v2ascii!([40, 32, 59]);
622         assert_eq!(v.as_str_ascii(), "( ;");
623     }
624
625     #[test]
626     fn test_ascii_into_string() {
627         assert_eq!(vec2ascii![40, 32, 59].into_string(), "( ;".to_string());
628         assert_eq!(vec2ascii!(40, 32, 59).into_string(), "( ;".to_string());
629     }
630
631     #[test]
632     fn test_ascii_to_bytes() {
633         assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
634     }
635
636     #[test] #[should_fail]
637     fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }
638
639     #[test] #[should_fail]
640     fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }
641
642     #[test] #[should_fail]
643     fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }
644
645     #[test] #[should_fail]
646     fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
647
648     #[test]
649     fn test_opt() {
650         assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
651         assert_eq!(255u8.to_ascii_opt(), None);
652
653         assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
654         assert_eq!('λ'.to_ascii_opt(), None);
655
656         assert_eq!("zoä华".to_ascii_opt(), None);
657
658         let test1 = &[127u8, 128u8, 255u8];
659         assert_eq!((test1).to_ascii_opt(), None);
660
661         let v = [40u8, 32u8, 59u8];
662         let v2 = v2ascii!(&[40, 32, 59]);
663         assert_eq!(v.to_ascii_opt(), Some(v2));
664         let v = [127u8, 128u8, 255u8];
665         assert_eq!(v.to_ascii_opt(), None);
666
667         let v = "( ;";
668         let v2 = v2ascii!(&[40, 32, 59]);
669         assert_eq!(v.to_ascii_opt(), Some(v2));
670         assert_eq!("zoä华".to_ascii_opt(), None);
671
672         assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
673         assert_eq!((vec![127u8, 128u8, 255u8]).into_ascii_opt(), None);
674
675         assert_eq!(("( ;".to_string()).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
676         assert_eq!(("zoä华".to_string()).into_ascii_opt(), None);
677     }
678
679     #[test]
680     fn test_to_ascii_upper() {
681         assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), "URL()URL()URL()üRL".to_string());
682         assert_eq!("hıKß".to_ascii_upper(), "HıKß".to_string());
683
684         let mut i = 0;
685         while i <= 500 {
686             let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
687                         else { i };
688             assert_eq!((from_u32(i).unwrap()).to_string().as_slice().to_ascii_upper(),
689                        (from_u32(upper).unwrap()).to_string())
690             i += 1;
691         }
692     }
693
694     #[test]
695     fn test_to_ascii_lower() {
696         assert_eq!("url()URL()uRl()Ürl".to_ascii_lower(), "url()url()url()Ürl".to_string());
697         // Dotted capital I, Kelvin sign, Sharp S.
698         assert_eq!("HİKß".to_ascii_lower(), "hİKß".to_string());
699
700         let mut i = 0;
701         while i <= 500 {
702             let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
703                         else { i };
704             assert_eq!((from_u32(i).unwrap()).to_string().as_slice().to_ascii_lower(),
705                        (from_u32(lower).unwrap()).to_string())
706             i += 1;
707         }
708     }
709
710     #[test]
711     fn test_into_ascii_upper() {
712         assert_eq!(("url()URL()uRl()ürl".to_string()).into_ascii_upper(),
713                    "URL()URL()URL()üRL".to_string());
714         assert_eq!(("hıKß".to_string()).into_ascii_upper(), "HıKß".to_string());
715
716         let mut i = 0;
717         while i <= 500 {
718             let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
719                         else { i };
720             assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_upper(),
721                        (from_u32(upper).unwrap()).to_string())
722             i += 1;
723         }
724     }
725
726     #[test]
727     fn test_into_ascii_lower() {
728         assert_eq!(("url()URL()uRl()Ürl".to_string()).into_ascii_lower(),
729                    "url()url()url()Ürl".to_string());
730         // Dotted capital I, Kelvin sign, Sharp S.
731         assert_eq!(("HİKß".to_string()).into_ascii_lower(), "hİKß".to_string());
732
733         let mut i = 0;
734         while i <= 500 {
735             let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
736                         else { i };
737             assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_lower(),
738                        (from_u32(lower).unwrap()).to_string())
739             i += 1;
740         }
741     }
742
743     #[test]
744     fn test_eq_ignore_ascii_case() {
745         assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
746         assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
747         // Dotted capital I, Kelvin sign, Sharp S.
748         assert!("HİKß".eq_ignore_ascii_case("hİKß"));
749         assert!(!"İ".eq_ignore_ascii_case("i"));
750         assert!(!"K".eq_ignore_ascii_case("k"));
751         assert!(!"ß".eq_ignore_ascii_case("s"));
752
753         let mut i = 0;
754         while i <= 500 {
755             let c = i;
756             let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 }
757                         else { c };
758             assert!((from_u32(i).unwrap()).to_string().as_slice().eq_ignore_ascii_case(
759                     (from_u32(lower).unwrap()).to_string().as_slice()));
760             i += 1;
761         }
762     }
763
764     #[test]
765     fn test_to_string() {
766         let s = Ascii{ chr: 't' as u8 }.to_string();
767         assert_eq!(s, "t".to_string());
768     }
769
770     #[test]
771     fn test_show() {
772         let c = Ascii { chr: 't' as u8 };
773         assert_eq!(format!("{}", c), "t".to_string());
774     }
775 }