]> git.lizzy.rs Git - rust.git/blob - src/libstd/ascii.rs
Add a doctest for the std::string::as_string method.
[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 #![unstable = "unsure about placement and naming"]
16 #![allow(deprecated)]
17
18 use core::kinds::Sized;
19 use fmt;
20 use iter::IteratorExt;
21 use mem;
22 use option::Option;
23 use option::Option::{Some, None};
24 use slice::{SlicePrelude, AsSlice};
25 use str::{Str, StrPrelude};
26 use string::{String, IntoString};
27 use vec::Vec;
28
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 }
32
33 impl Ascii {
34     /// Converts an ascii character into a `u8`.
35     #[inline]
36     #[unstable = "recently renamed"]
37     pub fn as_byte(&self) -> u8 {
38         self.chr
39     }
40
41     /// Deprecated: use `as_byte` isntead.
42     #[deprecated = "use as_byte"]
43     pub fn to_byte(self) -> u8 {
44         self.as_byte()
45     }
46
47     /// Converts an ascii character into a `char`.
48     #[inline]
49     #[unstable = "recently renamed"]
50     pub fn as_char(&self) -> char {
51         self.chr as char
52     }
53
54     /// Deprecated: use `as_char` isntead.
55     #[deprecated = "use as_char"]
56     pub fn to_char(self) -> char {
57         self.as_char()
58     }
59
60     /// Convert to lowercase.
61     #[inline]
62     #[stable]
63     pub fn to_lowercase(&self) -> Ascii {
64         Ascii{chr: ASCII_LOWER_MAP[self.chr as uint]}
65     }
66
67     /// Convert to uppercase.
68     #[inline]
69     #[stable]
70     pub fn to_uppercase(&self) -> Ascii {
71         Ascii{chr: ASCII_UPPER_MAP[self.chr as uint]}
72     }
73
74     /// Compares two ascii characters of equality, ignoring case.
75     #[inline]
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]
79     }
80
81     // the following methods are like ctype, and the implementation is inspired by musl
82
83     /// Check if the character is a letter (a-z, A-Z)
84     #[inline]
85     #[stable]
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     #[unstable = "may be renamed"]
93     pub fn is_digit(&self) -> bool {
94         self.chr >= 0x30 && self.chr <= 0x39
95     }
96
97     /// Check if the character is a letter or number
98     #[inline]
99     #[stable]
100     pub fn is_alphanumeric(&self) -> bool {
101         self.is_alphabetic() || self.is_digit()
102     }
103
104     /// Check if the character is a space or horizontal tab
105     #[inline]
106     #[experimental = "likely to be removed"]
107     pub fn is_blank(&self) -> bool {
108         self.chr == b' ' || self.chr == b'\t'
109     }
110
111     /// Check if the character is a control character
112     #[inline]
113     #[stable]
114     pub fn is_control(&self) -> bool {
115         self.chr < 0x20 || self.chr == 0x7F
116     }
117
118     /// Checks if the character is printable (except space)
119     #[inline]
120     #[experimental = "unsure about naming, or whether this is needed"]
121     pub fn is_graph(&self) -> bool {
122         (self.chr - 0x21) < 0x5E
123     }
124
125     /// Checks if the character is printable (including space)
126     #[inline]
127     #[unstable = "unsure about naming"]
128     pub fn is_print(&self) -> bool {
129         (self.chr - 0x20) < 0x5F
130     }
131
132     /// Checks if the character is alphabetic and lowercase
133     #[inline]
134     #[stable]
135     pub fn is_lowercase(&self) -> bool {
136         (self.chr - b'a') < 26
137     }
138
139     /// Checks if the character is alphabetic and uppercase
140     #[inline]
141     #[stable]
142     pub fn is_uppercase(&self) -> bool {
143         (self.chr - b'A') < 26
144     }
145
146     /// Checks if the character is punctuation
147     #[inline]
148     #[stable]
149     pub fn is_punctuation(&self) -> bool {
150         self.is_graph() && !self.is_alphanumeric()
151     }
152
153     /// Checks if the character is a valid hex digit
154     #[inline]
155     #[stable]
156     pub fn is_hex(&self) -> bool {
157         self.is_digit() || ((self.chr | 32u8) - b'a') < 6
158     }
159 }
160
161 impl<'a> fmt::Show for Ascii {
162     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163         (self.chr as char).fmt(f)
164     }
165 }
166
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.
171     #[inline]
172     fn to_ascii(&self) -> T {
173         assert!(self.is_ascii());
174         unsafe {self.to_ascii_nocheck()}
175     }
176
177     /// Convert to an ascii type, return None on non-ASCII input.
178     #[inline]
179     fn to_ascii_opt(&self) -> Option<T> {
180         if self.is_ascii() {
181             Some(unsafe { self.to_ascii_nocheck() })
182         } else {
183             None
184         }
185     }
186
187     /// Convert to an ascii type, not doing any range asserts
188     unsafe fn to_ascii_nocheck(&self) -> T;
189
190     /// Check if convertible to ascii
191     fn is_ascii(&self) -> bool;
192 }
193
194 #[experimental = "may be replaced by generic conversion traits"]
195 impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] {
196     #[inline]
197     unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
198         mem::transmute(*self)
199     }
200
201     #[inline]
202     fn is_ascii(&self) -> bool {
203         for b in self.iter() {
204             if !b.is_ascii() { return false; }
205         }
206         true
207     }
208 }
209
210 #[experimental = "may be replaced by generic conversion traits"]
211 impl<'a> AsciiCast<&'a [Ascii]> for &'a str {
212     #[inline]
213     unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
214         mem::transmute(*self)
215     }
216
217     #[inline]
218     fn is_ascii(&self) -> bool {
219         self.bytes().all(|b| b.is_ascii())
220     }
221 }
222
223 #[experimental = "may be replaced by generic conversion traits"]
224 impl AsciiCast<Ascii> for u8 {
225     #[inline]
226     unsafe fn to_ascii_nocheck(&self) -> Ascii {
227         Ascii{ chr: *self }
228     }
229
230     #[inline]
231     fn is_ascii(&self) -> bool {
232         *self & 128 == 0u8
233     }
234 }
235
236 #[experimental = "may be replaced by generic conversion traits"]
237 impl AsciiCast<Ascii> for char {
238     #[inline]
239     unsafe fn to_ascii_nocheck(&self) -> Ascii {
240         Ascii{ chr: *self as u8 }
241     }
242
243     #[inline]
244     fn is_ascii(&self) -> bool {
245         *self as u32 - ('\x7F' as u32 & *self as u32) == 0
246     }
247 }
248
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;
254
255     /// Take ownership and cast to an ascii vector.
256     /// # Panics
257     ///
258     /// Panic on non-ASCII input.
259     #[inline]
260     fn into_ascii(self) -> Vec<Ascii> {
261         assert!(self.is_ascii());
262         unsafe {self.into_ascii_nocheck()}
263     }
264
265     /// Take ownership and cast to an ascii vector. Return None on non-ASCII input.
266     #[inline]
267     fn into_ascii_opt(self) -> Option<Vec<Ascii>> {
268         if self.is_ascii() {
269             Some(unsafe { self.into_ascii_nocheck() })
270         } else {
271             None
272         }
273     }
274
275     /// Take ownership and cast to an ascii vector.
276     /// Does not perform validation checks.
277     unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
278 }
279
280 #[experimental = "may be replaced by generic conversion traits"]
281 impl OwnedAsciiCast for String {
282     #[inline]
283     fn is_ascii(&self) -> bool {
284         self.as_slice().is_ascii()
285     }
286
287     #[inline]
288     unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
289         self.into_bytes().into_ascii_nocheck()
290     }
291 }
292
293 #[experimental = "may be replaced by generic conversion traits"]
294 impl OwnedAsciiCast for Vec<u8> {
295     #[inline]
296     fn is_ascii(&self) -> bool {
297         self.as_slice().is_ascii()
298     }
299
300     #[inline]
301     unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
302         let v = Vec::from_raw_parts(self.as_ptr() as *mut Ascii,
303                                     self.len(),
304                                     self.capacity());
305
306         // We forget `self` to avoid freeing it at the end of the scope
307         // Otherwise, the returned `Vec` would point to freed memory
308         mem::forget(self);
309         v
310     }
311 }
312
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;
319
320     /// Deprecated: use `to_lowercase`
321     #[deprecated="renamed `to_lowercase`"]
322     fn to_lower(&self) -> Vec<Ascii>;
323
324     /// Convert to vector representing a lower cased ascii string.
325     #[deprecated = "use iterators instead"]
326     fn to_lowercase(&self) -> Vec<Ascii>;
327
328     /// Deprecated: use `to_uppercase`
329     #[deprecated="renamed `to_uppercase`"]
330     fn to_upper(&self) -> Vec<Ascii>;
331
332     /// Convert to vector representing a upper cased ascii string.
333     #[deprecated = "use iterators instead"]
334     fn to_uppercase(&self) -> Vec<Ascii>;
335
336     /// Compares two Ascii strings ignoring case.
337     #[deprecated = "use iterators instead"]
338     fn eq_ignore_case(&self, other: &[Ascii]) -> bool;
339 }
340
341 #[experimental = "may be replaced by generic conversion traits"]
342 impl AsciiStr for [Ascii] {
343     #[inline]
344     fn as_str_ascii<'a>(&'a self) -> &'a str {
345         unsafe { mem::transmute(self) }
346     }
347
348     #[inline]
349     fn to_lower(&self) -> Vec<Ascii> {
350       self.to_lowercase()
351     }
352
353     #[inline]
354     fn to_lowercase(&self) -> Vec<Ascii> {
355         self.iter().map(|a| a.to_lowercase()).collect()
356     }
357
358     #[inline]
359     fn to_upper(&self) -> Vec<Ascii> {
360       self.to_uppercase()
361     }
362
363     #[inline]
364     fn to_uppercase(&self) -> Vec<Ascii> {
365         self.iter().map(|a| a.to_uppercase()).collect()
366     }
367
368     #[inline]
369     fn eq_ignore_case(&self, other: &[Ascii]) -> bool {
370         self.iter().zip(other.iter()).all(|(&a, &b)| a.eq_ignore_case(b))
371     }
372 }
373
374 impl IntoString for Vec<Ascii> {
375     #[inline]
376     fn into_string(self) -> String {
377         unsafe { String::from_utf8_unchecked(self.into_bytes()) }
378     }
379 }
380
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>;
386 }
387
388 #[experimental = "may be replaced by generic conversion traits"]
389 impl IntoBytes for Vec<Ascii> {
390     fn into_bytes(self) -> Vec<u8> {
391         unsafe {
392             let v = Vec::from_raw_parts(self.as_ptr() as *mut u8,
393                                         self.len(),
394                                         self.capacity());
395
396             // We forget `self` to avoid freeing it at the end of the scope
397             // Otherwise, the returned `Vec` would point to freed memory
398             mem::forget(self);
399             v
400         }
401     }
402 }
403
404
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;
412
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;
417 }
418
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;
426
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;
431
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;
436 }
437
438 #[experimental = "would prefer to do this in a more general way"]
439 impl AsciiExt<String> for str {
440     #[inline]
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()) }
444     }
445
446     #[inline]
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()) }
450     }
451
452     #[inline]
453     fn eq_ignore_ascii_case(&self, other: &str) -> bool {
454         self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
455     }
456 }
457
458 #[experimental = "would prefer to do this in a more general way"]
459 impl OwnedAsciiExt for String {
460     #[inline]
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()) }
464     }
465
466     #[inline]
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()) }
470     }
471 }
472
473 #[experimental = "would prefer to do this in a more general way"]
474 impl AsciiExt<Vec<u8>> for [u8] {
475     #[inline]
476     fn to_ascii_upper(&self) -> Vec<u8> {
477         self.iter().map(|&byte| ASCII_UPPER_MAP[byte as uint]).collect()
478     }
479
480     #[inline]
481     fn to_ascii_lower(&self) -> Vec<u8> {
482         self.iter().map(|&byte| ASCII_LOWER_MAP[byte as uint]).collect()
483     }
484
485     #[inline]
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]
492             })
493     }
494 }
495
496 #[experimental = "would prefer to do this in a more general way"]
497 impl OwnedAsciiExt for Vec<u8> {
498     #[inline]
499     fn into_ascii_upper(mut self) -> Vec<u8> {
500         for byte in self.iter_mut() {
501             *byte = ASCII_UPPER_MAP[*byte as uint];
502         }
503         self
504     }
505
506     #[inline]
507     fn into_ascii_lower(mut self) -> Vec<u8> {
508         for byte in self.iter_mut() {
509             *byte = ASCII_LOWER_MAP[*byte as uint];
510         }
511         self
512     }
513 }
514
515 /// Returns a 'default' ASCII and C++11-like literal escape of a `u8`
516 ///
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:
520 ///
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|) {
528     match c {
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); }
536         _ => {
537             f(b'\\');
538             f(b'x');
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)),
543                 }
544             }
545         }
546     }
547 }
548
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'?',
558     b'@',
559
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',
563     b'x', b'y', b'z',
564
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,
586 ];
587
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'_',
601     b'`',
602
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',
606     b'X', b'Y', b'Z',
607
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,
625 ];
626
627
628 #[cfg(test)]
629 mod tests {
630     use prelude::*;
631     use super::*;
632     use char::from_u32;
633     use str::StrPrelude;
634
635     macro_rules! v2ascii (
636         ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
637         (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
638     )
639
640     macro_rules! vec2ascii (
641         ($($e:expr),*) => ([$(Ascii{chr:$e}),*].to_vec());
642     )
643
644     #[test]
645     fn test_ascii() {
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);
650
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');
655
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(), '{');
660
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());
665
666         assert!((0x1fu8).to_ascii().is_control());
667         assert!(!' '.to_ascii().is_control());
668         assert!((0x7fu8).to_ascii().is_control());
669
670         assert!("banana".chars().all(|c| c.is_ascii()));
671         assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
672     }
673
674     #[test]
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);
683
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());
686
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());
691
692         assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
693
694         assert!("".is_ascii());
695         assert!("a".is_ascii());
696         assert!(!"\u2009".is_ascii());
697
698     }
699
700     #[test]
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());
708     }
709
710     #[test]
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]);
714     }
715
716     #[test]
717     fn test_ascii_as_str() {
718         let v = v2ascii!([40, 32, 59]);
719         assert_eq!(v.as_str_ascii(), "( ;");
720     }
721
722     #[test]
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());
726     }
727
728     #[test]
729     fn test_ascii_to_bytes() {
730         assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
731     }
732
733     #[test] #[should_fail]
734     fn test_ascii_vec_panic_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }
735
736     #[test] #[should_fail]
737     fn test_ascii_vec_panic_str_slice() { "zoä华".to_ascii(); }
738
739     #[test] #[should_fail]
740     fn test_ascii_panic_u8_slice() { 255u8.to_ascii(); }
741
742     #[test] #[should_fail]
743     fn test_ascii_panic_char_slice() { 'λ'.to_ascii(); }
744
745     #[test]
746     fn test_opt() {
747         assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
748         assert_eq!(255u8.to_ascii_opt(), None);
749
750         assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
751         assert_eq!('λ'.to_ascii_opt(), None);
752
753         assert_eq!("zoä华".to_ascii_opt(), None);
754
755         let test1 = &[127u8, 128u8, 255u8];
756         assert_eq!((test1).to_ascii_opt(), None);
757
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);
763
764         let v = "( ;";
765         assert_eq!(v.to_ascii_opt(), Some(v2));
766         assert_eq!("zoä华".to_ascii_opt(), None);
767
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);
770
771         assert_eq!(("( ;".to_string()).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
772         assert_eq!(("zoä华".to_string()).into_ascii_opt(), None);
773     }
774
775     #[test]
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());
779
780         let mut i = 0;
781         while i <= 500 {
782             let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
783                         else { i };
784             assert_eq!((from_u32(i).unwrap()).to_string().as_slice().to_ascii_upper(),
785                        (from_u32(upper).unwrap()).to_string())
786             i += 1;
787         }
788     }
789
790     #[test]
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());
795
796         let mut i = 0;
797         while i <= 500 {
798             let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
799                         else { i };
800             assert_eq!((from_u32(i).unwrap()).to_string().as_slice().to_ascii_lower(),
801                        (from_u32(lower).unwrap()).to_string())
802             i += 1;
803         }
804     }
805
806     #[test]
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());
811
812         let mut i = 0;
813         while i <= 500 {
814             let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
815                         else { i };
816             assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_upper(),
817                        (from_u32(upper).unwrap()).to_string())
818             i += 1;
819         }
820     }
821
822     #[test]
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());
828
829         let mut i = 0;
830         while i <= 500 {
831             let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
832                         else { i };
833             assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_lower(),
834                        (from_u32(lower).unwrap()).to_string())
835             i += 1;
836         }
837     }
838
839     #[test]
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"));
848
849         let mut i = 0;
850         while i <= 500 {
851             let c = i;
852             let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 }
853                         else { c };
854             assert!((from_u32(i).unwrap()).to_string().as_slice().eq_ignore_ascii_case(
855                     (from_u32(lower).unwrap()).to_string().as_slice()));
856             i += 1;
857         }
858     }
859
860     #[test]
861     fn test_to_string() {
862         let s = Ascii{ chr: b't' }.to_string();
863         assert_eq!(s, "t".to_string());
864     }
865
866     #[test]
867     fn test_show() {
868         let c = Ascii { chr: b't' };
869         assert_eq!(format!("{}", c), "t".to_string());
870     }
871 }