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