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