(index<- ) ./libstd/ascii.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
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::{StrAllocating, 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 { 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 as uint]}
47 }
48
49 /// Convert to uppercase.
50 #[inline]
51 pub fn to_upper(self) -> Ascii {
52 Ascii{chr: ASCII_UPPER_MAP[self.chr as uint]}
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 as uint] == ASCII_LOWER_MAP[other.chr as uint]
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) -> Vec<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<Vec<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) -> Vec<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) -> Vec<Ascii> {
248 cast::transmute(Vec::from_slice(self.as_slice()))
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) -> Vec<Ascii> {
260 let v: ~[u8] = cast::transmute(self);
261 v.into_ascii_nocheck()
262 }
263 }
264
265 impl OwnedAsciiCast for Vec<u8> {
266 #[inline]
267 fn is_ascii(&self) -> bool {
268 self.as_slice().is_ascii()
269 }
270
271 #[inline]
272 unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
273 cast::transmute(self)
274 }
275 }
276
277 /// Trait for converting an ascii type to a string. Needed to convert
278 /// `&[Ascii]` to `&str`.
279 pub trait AsciiStr {
280 /// Convert to a string.
281 fn as_str_ascii<'a>(&'a self) -> &'a str;
282
283 /// Convert to vector representing a lower cased ascii string.
284 fn to_lower(&self) -> Vec<Ascii>;
285
286 /// Convert to vector representing a upper cased ascii string.
287 fn to_upper(&self) -> Vec<Ascii>;
288
289 /// Compares two Ascii strings ignoring case.
290 fn eq_ignore_case(self, other: &[Ascii]) -> bool;
291 }
292
293 impl<'a> AsciiStr for &'a [Ascii] {
294 #[inline]
295 fn as_str_ascii<'a>(&'a self) -> &'a str {
296 unsafe { cast::transmute(*self) }
297 }
298
299 #[inline]
300 fn to_lower(&self) -> Vec<Ascii> {
301 self.iter().map(|a| a.to_lower()).collect()
302 }
303
304 #[inline]
305 fn to_upper(&self) -> Vec<Ascii> {
306 self.iter().map(|a| a.to_upper()).collect()
307 }
308
309 #[inline]
310 fn eq_ignore_case(self, other: &[Ascii]) -> bool {
311 self.iter().zip(other.iter()).all(|(&a, &b)| a.eq_ignore_case(b))
312 }
313 }
314
315 impl IntoStr for ~[Ascii] {
316 #[inline]
317 fn into_str(self) -> ~str {
318 unsafe { cast::transmute(self) }
319 }
320 }
321
322 impl IntoStr for Vec<Ascii> {
323 #[inline]
324 fn into_str(self) -> ~str {
325 unsafe {
326 let s: &str = cast::transmute(self.as_slice());
327 s.to_owned()
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 { cast::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) -> ~str;
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) -> ~str;
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) -> ~str;
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) -> ~str;
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) -> ~str {
378 unsafe { str_copy_map_bytes(*self, ASCII_UPPER_MAP) }
379 }
380
381 #[inline]
382 fn to_ascii_lower(&self) -> ~str {
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 ~str {
398 #[inline]
399 fn into_ascii_upper(self) -> ~str {
400 unsafe { str_map_bytes(self, ASCII_UPPER_MAP) }
401 }
402
403 #[inline]
404 fn into_ascii_lower(self) -> ~str {
405 unsafe { str_map_bytes(self, ASCII_LOWER_MAP) }
406 }
407 }
408
409 #[inline]
410 unsafe fn str_map_bytes(string: ~str, map: &'static [u8]) -> ~str {
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::raw::from_utf8_owned(bytes)
418 }
419
420 #[inline]
421 unsafe fn str_copy_map_bytes(string: &str, map: &'static [u8]) -> ~str {
422 let mut s = string.to_owned();
423 for b in str::raw::as_owned_vec(&mut s).mut_iter() {
424 *b = map[*b as uint];
425 }
426 s
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]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
556 let v = "( ;".to_owned(); assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
557
558 assert_eq!("abCDef&?#".to_ascii().to_lower().into_str(), "abcdef&?#".to_owned());
559 assert_eq!("abCDef&?#".to_ascii().to_upper().into_str(), "ABCDEF&?#".to_owned());
560
561 assert_eq!("".to_ascii().to_lower().into_str(), "".to_owned());
562 assert_eq!("YMCA".to_ascii().to_lower().into_str(), "ymca".to_owned());
563 assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_str(), "ABCDEFXYZ:.;".to_owned());
564
565 assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
566
567 assert!("".is_ascii());
568 assert!("a".is_ascii());
569 assert!(!"\u2009".is_ascii());
570
571 }
572
573 #[test]
574 fn test_ascii_vec_ng() {
575 assert_eq!("abCDef&?#".to_ascii().to_lower().into_str(), "abcdef&?#".to_owned());
576 assert_eq!("abCDef&?#".to_ascii().to_upper().into_str(), "ABCDEF&?#".to_owned());
577 assert_eq!("".to_ascii().to_lower().into_str(), "".to_owned());
578 assert_eq!("YMCA".to_ascii().to_lower().into_str(), "ymca".to_owned());
579 assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_str(), "ABCDEFXYZ:.;".to_owned());
580 }
581
582 #[test]
583 fn test_owned_ascii_vec() {
584 assert_eq!(("( ;".to_owned()).into_ascii(), vec2ascii![40, 32, 59]);
585 assert_eq!((box [40u8, 32u8, 59u8]).into_ascii(), vec2ascii![40, 32, 59]);
586 }
587
588 #[test]
589 fn test_ascii_as_str() {
590 let v = v2ascii!([40, 32, 59]);
591 assert_eq!(v.as_str_ascii(), "( ;");
592 }
593
594 #[test]
595 fn test_ascii_into_str() {
596 assert_eq!(vec2ascii![40, 32, 59].into_str(), "( ;".to_owned());
597 assert_eq!(vec2ascii!(40, 32, 59).into_str(), "( ;".to_owned());
598 }
599
600 #[test]
601 fn test_ascii_to_bytes() {
602 assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
603 }
604
605 #[test] #[should_fail]
606 fn test_ascii_vec_fail_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii(); }
607
608 #[test] #[should_fail]
609 fn test_ascii_vec_fail_str_slice() { "zoäå".to_ascii(); }
610
611 #[test] #[should_fail]
612 fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }
613
614 #[test] #[should_fail]
615 fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
616
617 #[test]
618 fn test_opt() {
619 assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
620 assert_eq!(255u8.to_ascii_opt(), None);
621
622 assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
623 assert_eq!('λ'.to_ascii_opt(), None);
624
625 assert_eq!("zoäå".to_ascii_opt(), None);
626
627 let test1 = &[127u8, 128u8, 255u8];
628 assert_eq!((test1).to_ascii_opt(), None);
629
630 let v = [40u8, 32u8, 59u8];
631 let v2 = v2ascii!(&[40, 32, 59]);
632 assert_eq!(v.to_ascii_opt(), Some(v2));
633 let v = [127u8, 128u8, 255u8];
634 assert_eq!(v.to_ascii_opt(), None);
635
636 let v = "( ;";
637 let v2 = v2ascii!(&[40, 32, 59]);
638 assert_eq!(v.to_ascii_opt(), Some(v2));
639 assert_eq!("zoäå".to_ascii_opt(), None);
640
641 assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
642 assert_eq!((vec![127u8, 128u8, 255u8]).into_ascii_opt(), None);
643
644 assert_eq!(("( ;".to_owned()).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
645 assert_eq!(("zoäå".to_owned()).into_ascii_opt(), None);
646 }
647
648 #[test]
649 fn test_to_ascii_upper() {
650 assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), "URL()URL()URL()üRL".to_owned());
651 assert_eq!("hıâªÃ".to_ascii_upper(), "HıâªÃ".to_owned());
652
653 let mut i = 0;
654 while i <= 500 {
655 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
656 else { i };
657 assert_eq!(from_char(from_u32(i).unwrap()).to_ascii_upper(),
658 from_char(from_u32(upper).unwrap()))
659 i += 1;
660 }
661 }
662
663 #[test]
664 fn test_to_ascii_lower() {
665 assert_eq!("url()URL()uRl()Ãrl".to_ascii_lower(), "url()url()url()Ãrl".to_owned());
666 // Dotted capital I, Kelvin sign, Sharp S.
667 assert_eq!("HÄ°âªÃ".to_ascii_lower(), "hÄ°âªÃ".to_owned());
668
669 let mut i = 0;
670 while i <= 500 {
671 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
672 else { i };
673 assert_eq!(from_char(from_u32(i).unwrap()).to_ascii_lower(),
674 from_char(from_u32(lower).unwrap()))
675 i += 1;
676 }
677 }
678
679 #[test]
680 fn test_into_ascii_upper() {
681 assert_eq!(("url()URL()uRl()ürl".to_owned()).into_ascii_upper(),
682 "URL()URL()URL()üRL".to_owned());
683 assert_eq!(("hıâªÃ".to_owned()).into_ascii_upper(), "HıâªÃ".to_owned());
684
685 let mut i = 0;
686 while i <= 500 {
687 let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
688 else { i };
689 assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_upper(),
690 from_char(from_u32(upper).unwrap()))
691 i += 1;
692 }
693 }
694
695 #[test]
696 fn test_into_ascii_lower() {
697 assert_eq!(("url()URL()uRl()Ãrl".to_owned()).into_ascii_lower(),
698 "url()url()url()Ãrl".to_owned());
699 // Dotted capital I, Kelvin sign, Sharp S.
700 assert_eq!(("HÄ°âªÃ".to_owned()).into_ascii_lower(), "hÄ°âªÃ".to_owned());
701
702 let mut i = 0;
703 while i <= 500 {
704 let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
705 else { i };
706 assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_lower(),
707 from_char(from_u32(lower).unwrap()))
708 i += 1;
709 }
710 }
711
712 #[test]
713 fn test_eq_ignore_ascii_case() {
714 assert!("url()URL()uRl()Ãrl".eq_ignore_ascii_case("url()url()url()Ãrl"));
715 assert!(!"Ãrl".eq_ignore_ascii_case("ürl"));
716 // Dotted capital I, Kelvin sign, Sharp S.
717 assert!("HÄ°âªÃ".eq_ignore_ascii_case("hÄ°âªÃ"));
718 assert!(!"Ä°".eq_ignore_ascii_case("i"));
719 assert!(!"âª".eq_ignore_ascii_case("k"));
720 assert!(!"Ã".eq_ignore_ascii_case("s"));
721
722 let mut i = 0;
723 while i <= 500 {
724 let c = i;
725 let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 }
726 else { c };
727 assert!(from_char(from_u32(i).unwrap()).
728 eq_ignore_ascii_case(from_char(from_u32(lower).unwrap())));
729 i += 1;
730 }
731 }
732
733 #[test]
734 fn test_to_str() {
735 let s = Ascii{ chr: 't' as u8 }.to_str();
736 assert_eq!(s, "t".to_owned());
737 }
738
739 #[test]
740 fn test_show() {
741 let c = Ascii { chr: 't' as u8 };
742 assert_eq!(format!("{}", c), "t".to_owned());
743 }
744 }