1 #![cfg_attr(rustfmt, rustfmt_skip)]
2 
3 // #[allow(deprecated)] doesn't silence warnings on the method invocations,
4 // which would call the inherent methods if AsciiExt wasn't in scope.
5 #![cfg_attr(feature = "std", allow(deprecated))]
6 
7 #[cfg(feature = "quickcheck")]
8 use quickcheck::{Arbitrary, Gen};
9 
10 use core::mem;
11 use core::cmp::Ordering;
12 use core::{fmt, char};
13 #[cfg(feature = "std")]
14 use std::error::Error;
15 #[cfg(feature = "std")]
16 use std::ascii::AsciiExt;
17 
18 #[allow(non_camel_case_types)]
19 /// An ASCII character. It wraps a `u8`, with the highest bit always zero.
20 #[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
21 #[repr(u8)]
22 pub enum AsciiChar {
23     /// `'\0'`
24     Null = 0,
25     /// [Start Of Heading](http://en.wikipedia.org/wiki/Start_of_Heading)
26     SOH = 1,
27     /// [Start Of teXt](http://en.wikipedia.org/wiki/Start_of_Text)
28     SOX = 2,
29     /// [End of TeXt](http://en.wikipedia.org/wiki/End-of-Text_character)
30     ETX = 3,
31     /// [End Of Transmission](http://en.wikipedia.org/wiki/End-of-Transmission_character)
32     EOT = 4,
33     /// [Enquiry](http://en.wikipedia.org/wiki/Enquiry_character)
34     ENQ = 5,
35     /// [Acknowledgement](http://en.wikipedia.org/wiki/Acknowledge_character)
36     ACK = 6,
37     /// [bell / alarm / audible](http://en.wikipedia.org/wiki/Bell_character)
38     ///
39     /// `'\a'` is not recognized by Rust.
40     Bell = 7,
41     /// [Backspace](http://en.wikipedia.org/wiki/Backspace)
42     ///
43     /// `'\b'` is not recognized by Rust.
44     BackSpace = 8,
45     /// `'\t'`
46     Tab = 9,
47     /// `'\n'`
48     LineFeed = 10,
49     /// [Vertical tab](http://en.wikipedia.org/wiki/Vertical_Tab)
50     ///
51     /// `'\v'` is not recognized by Rust.
52     VT = 11,
53     /// [Form Feed](http://en.wikipedia.org/wiki/Form_Feed)
54     ///
55     /// `'\f'` is not recognized by Rust.
56     FF = 12,
57     /// `'\r'`
58     CarriageReturn = 13,
59     /// [Shift In](http://en.wikipedia.org/wiki/Shift_Out_and_Shift_In_characters)
60     SI = 14,
61     /// [Shift Out](http://en.wikipedia.org/wiki/Shift_Out_and_Shift_In_characters)
62     SO = 15,
63     /// [Data Link Escape](http://en.wikipedia.org/wiki/Data_Link_Escape)
64     DLE = 16,
65     /// [Device control 1, often XON](http://en.wikipedia.org/wiki/Device_Control_1)
66     DC1 = 17,
67     /// Device control 2
68     DC2 = 18,
69     /// Device control 3, Often XOFF
70     DC3 = 19,
71     /// Device control 4
72     DC4 = 20,
73     /// [Negative AcKnowledgement](http://en.wikipedia.org/wiki/Negative-acknowledge_character)
74     NAK = 21,
75     /// [Synchronous idle](http://en.wikipedia.org/wiki/Synchronous_Idle)
76     SYN = 22,
77     /// [End of Transmission Block](http://en.wikipedia.org/wiki/End-of-Transmission-Block_character)
78     ETB = 23,
79     /// [Cancel](http://en.wikipedia.org/wiki/Cancel_character)
80     CAN = 24,
81     /// [End of Medium](http://en.wikipedia.org/wiki/End_of_Medium)
82     EM = 25,
83     /// [Substitute](http://en.wikipedia.org/wiki/Substitute_character)
84     SUB = 26,
85     /// [Escape](http://en.wikipedia.org/wiki/Escape_character)
86     ///
87     /// `'\e'` is not recognized by Rust.
88     ESC = 27,
89     /// [File Separator](http://en.wikipedia.org/wiki/File_separator)
90     FS = 28,
91     /// [Group Separator](http://en.wikipedia.org/wiki/Group_separator)
92     GS = 29,
93     /// [Record Separator](http://en.wikipedia.org/wiki/Record_separator)
94     RS = 30,
95     /// [Unit Separator](http://en.wikipedia.org/wiki/Unit_separator)
96     US = 31,
97     /// `' '`
98     Space = 32,
99     /// `'!'`
100     Exclamation = 33,
101     /// `'"'`
102     Quotation = 34,
103     /// `'#'`
104     Hash = 35,
105     /// `'$'`
106     Dollar = 36,
107     /// `'%'`
108     Percent = 37,
109     /// `'&'`
110     Ampersand = 38,
111     /// `'\''`
112     Apostrophe = 39,
113     /// `'('`
114     ParenOpen = 40,
115     /// `')'`
116     ParenClose = 41,
117     /// `'*'`
118     Asterisk = 42,
119     /// `'+'`
120     Plus = 43,
121     /// `','`
122     Comma = 44,
123     /// `'-'`
124     Minus = 45,
125     /// `'.'`
126     Dot = 46,
127     /// `'/'`
128     Slash = 47,
129     /// `'0'`
130     _0 = 48,
131     /// `'1'`
132     _1 = 49,
133     /// `'2'`
134     _2 = 50,
135     /// `'3'`
136     _3 = 51,
137     /// `'4'`
138     _4 = 52,
139     /// `'5'`
140     _5 = 53,
141     /// `'6'`
142     _6 = 54,
143     /// `'7'`
144     _7 = 55,
145     /// `'8'`
146     _8 = 56,
147     /// `'9'`
148     _9 = 57,
149     /// `':'`
150     Colon = 58,
151     /// `';'`
152     Semicolon = 59,
153     /// `'<'`
154     LessThan = 60,
155     /// `'='`
156     Equal = 61,
157     /// `'>'`
158     GreaterThan = 62,
159     /// `'?'`
160     Question = 63,
161     /// `'@'`
162     At = 64,
163     /// `'A'`
164     A = 65,
165     /// `'B'`
166     B = 66,
167     /// `'C'`
168     C = 67,
169     /// `'D'`
170     D = 68,
171     /// `'E'`
172     E = 69,
173     /// `'F'`
174     F = 70,
175     /// `'G'`
176     G = 71,
177     /// `'H'`
178     H = 72,
179     /// `'I'`
180     I = 73,
181     /// `'J'`
182     J = 74,
183     /// `'K'`
184     K = 75,
185     /// `'L'`
186     L = 76,
187     /// `'M'`
188     M = 77,
189     /// `'N'`
190     N = 78,
191     /// `'O'`
192     O = 79,
193     /// `'P'`
194     P = 80,
195     /// `'Q'`
196     Q = 81,
197     /// `'R'`
198     R = 82,
199     /// `'S'`
200     S = 83,
201     /// `'T'`
202     T = 84,
203     /// `'U'`
204     U = 85,
205     /// `'V'`
206     V = 86,
207     /// `'W'`
208     W = 87,
209     /// `'X'`
210     X = 88,
211     /// `'Y'`
212     Y = 89,
213     /// `'Z'`
214     Z = 90,
215     /// `'['`
216     BracketOpen = 91,
217     /// `'\'`
218     BackSlash = 92,
219     /// `']'`
220     BracketClose = 93,
221     /// `'_'`
222     Caret = 94,
223     /// `'_'`
224     UnderScore = 95,
225     /// `'`'`
226     Grave = 96,
227     /// `'a'`
228     a = 97,
229     /// `'b'`
230     b = 98,
231     /// `'c'`
232     c = 99,
233     /// `'d'`
234     d = 100,
235     /// `'e'`
236     e = 101,
237     /// `'f'`
238     f = 102,
239     /// `'g'`
240     g = 103,
241     /// `'h'`
242     h = 104,
243     /// `'i'`
244     i = 105,
245     /// `'j'`
246     j = 106,
247     /// `'k'`
248     k = 107,
249     /// `'l'`
250     l = 108,
251     /// `'m'`
252     m = 109,
253     /// `'n'`
254     n = 110,
255     /// `'o'`
256     o = 111,
257     /// `'p'`
258     p = 112,
259     /// `'q'`
260     q = 113,
261     /// `'r'`
262     r = 114,
263     /// `'s'`
264     s = 115,
265     /// `'t'`
266     t = 116,
267     /// `'u'`
268     u = 117,
269     /// `'v'`
270     v = 118,
271     /// `'w'`
272     w = 119,
273     /// `'x'`
274     x = 120,
275     /// `'y'`
276     y = 121,
277     /// `'z'`
278     z = 122,
279     /// `'{'`
280     CurlyBraceOpen = 123,
281     /// `'|'`
282     VerticalBar = 124,
283     /// `'}'`
284     CurlyBraceClose = 125,
285     /// `'~'`
286     Tilde = 126,
287     /// [Delete](http://en.wikipedia.org/wiki/Delete_character)
288     DEL = 127,
289 }
290 
291 impl AsciiChar {
292     /// Constructs an ASCII character from a `u8`, `char` or other character type.
293     ///
294     /// # Failure
295     /// Returns `Err(())` if the character can't be ASCII encoded.
296     ///
297     /// # Example
298     /// ```
299     /// # use ascii::AsciiChar;
300     /// let a = AsciiChar::from('g').unwrap();
301     /// assert_eq!(a.as_char(), 'g');
302     /// ```
303     #[inline]
from<C: ToAsciiChar>(ch: C) -> Result<Self, ToAsciiCharError>304     pub fn from<C: ToAsciiChar>(ch: C) -> Result<Self, ToAsciiCharError> {
305         ch.to_ascii_char()
306     }
307 
308     /// Constructs an ASCII character from a `char` or `u8` without any checks.
309     #[inline]
from_unchecked<C: ToAsciiChar>(ch: C) -> Self310     pub unsafe fn from_unchecked<C: ToAsciiChar>(ch: C) -> Self {
311         ch.to_ascii_char_unchecked()
312     }
313 
314     /// Converts an ASCII character into a `u8`.
315     #[inline]
as_byte(self) -> u8316     pub fn as_byte(self) -> u8 {
317         self as u8
318     }
319 
320     /// Converts an ASCII character into a `char`.
321     #[inline]
as_char(self) -> char322     pub fn as_char(self) -> char {
323         self.as_byte() as char
324     }
325 
326     // the following methods are like ctype, and the implementation is inspired by musl
327 
328     /// Check if the character is a letter (a-z, A-Z)
329     #[inline]
is_alphabetic(self) -> bool330     pub fn is_alphabetic(self) -> bool {
331         let c = self.as_byte() | 0b010_0000; // Turns uppercase into lowercase.
332         c >= b'a' && c <= b'z'
333     }
334 
335     /// Check if the character is a number (0-9)
336     #[inline]
is_digit(self) -> bool337     pub fn is_digit(self) -> bool {
338         self >= AsciiChar::_0 && self <= AsciiChar::_9
339     }
340 
341     /// Check if the character is a letter or number
342     #[inline]
is_alphanumeric(self) -> bool343     pub fn is_alphanumeric(self) -> bool {
344         self.is_alphabetic() || self.is_digit()
345     }
346 
347     /// Check if the character is a space or horizontal tab
348     #[inline]
is_blank(self) -> bool349     pub fn is_blank(self) -> bool {
350         self == AsciiChar::Space || self == AsciiChar::Tab
351     }
352 
353     /// Check if the character is a ' ', '\t', '\n' or '\r'
354     #[inline]
is_whitespace(self) -> bool355     pub fn is_whitespace(self) -> bool {
356         self.is_blank() || self == AsciiChar::LineFeed || self == AsciiChar::CarriageReturn
357     }
358 
359     /// Check if the character is a control character
360     ///
361     /// # Examples
362     /// ```
363     /// use ascii::ToAsciiChar;
364     /// assert_eq!('\0'.to_ascii_char().unwrap().is_control(), true);
365     /// assert_eq!('n'.to_ascii_char().unwrap().is_control(), false);
366     /// assert_eq!(' '.to_ascii_char().unwrap().is_control(), false);
367     /// assert_eq!('\n'.to_ascii_char().unwrap().is_control(), true);
368     /// ```
369     #[inline]
is_control(self) -> bool370     pub fn is_control(self) -> bool {
371         self < AsciiChar::Space || self == AsciiChar::DEL
372     }
373 
374     /// Checks if the character is printable (except space)
375     ///
376     /// # Examples
377     /// ```
378     /// use ascii::ToAsciiChar;
379     /// assert_eq!('n'.to_ascii_char().unwrap().is_graph(), true);
380     /// assert_eq!(' '.to_ascii_char().unwrap().is_graph(), false);
381     /// assert_eq!('\n'.to_ascii_char().unwrap().is_graph(), false);
382     /// ```
383     #[inline]
is_graph(self) -> bool384     pub fn is_graph(self) -> bool {
385         self.as_byte().wrapping_sub(b' ' + 1) < 0x5E
386     }
387 
388     /// Checks if the character is printable (including space)
389     ///
390     /// # Examples
391     /// ```
392     /// use ascii::ToAsciiChar;
393     /// assert_eq!('n'.to_ascii_char().unwrap().is_print(), true);
394     /// assert_eq!(' '.to_ascii_char().unwrap().is_print(), true);
395     /// assert_eq!('\n'.to_ascii_char().unwrap().is_print(), false);
396     /// ```
397     #[inline]
is_print(self) -> bool398     pub fn is_print(self) -> bool {
399         self.as_byte().wrapping_sub(b' ') < 0x5F
400     }
401 
402     /// Checks if the character is alphabetic and lowercase
403     ///
404     /// # Examples
405     /// ```
406     /// use ascii::ToAsciiChar;
407     /// assert_eq!('a'.to_ascii_char().unwrap().is_lowercase(), true);
408     /// assert_eq!('A'.to_ascii_char().unwrap().is_lowercase(), false);
409     /// assert_eq!('@'.to_ascii_char().unwrap().is_lowercase(), false);
410     /// ```
411     #[inline]
is_lowercase(self) -> bool412     pub fn is_lowercase(self) -> bool {
413         self.as_byte().wrapping_sub(b'a') < 26
414     }
415 
416     /// Checks if the character is alphabetic and uppercase
417     ///
418     /// # Examples
419     /// ```
420     /// use ascii::ToAsciiChar;
421     /// assert_eq!('A'.to_ascii_char().unwrap().is_uppercase(), true);
422     /// assert_eq!('a'.to_ascii_char().unwrap().is_uppercase(), false);
423     /// assert_eq!('@'.to_ascii_char().unwrap().is_uppercase(), false);
424     /// ```
425     #[inline]
is_uppercase(self) -> bool426     pub fn is_uppercase(self) -> bool {
427         self.as_byte().wrapping_sub(b'A') < 26
428     }
429 
430     /// Checks if the character is punctuation
431     ///
432     /// # Examples
433     /// ```
434     /// use ascii::ToAsciiChar;
435     /// assert_eq!('n'.to_ascii_char().unwrap().is_punctuation(), false);
436     /// assert_eq!(' '.to_ascii_char().unwrap().is_punctuation(), false);
437     /// assert_eq!('_'.to_ascii_char().unwrap().is_punctuation(), true);
438     /// assert_eq!('~'.to_ascii_char().unwrap().is_punctuation(), true);
439     /// ```
440     #[inline]
is_punctuation(self) -> bool441     pub fn is_punctuation(self) -> bool {
442         self.is_graph() && !self.is_alphanumeric()
443     }
444 
445     /// Checks if the character is a valid hex digit
446     ///
447     /// # Examples
448     /// ```
449     /// use ascii::ToAsciiChar;
450     /// assert_eq!('5'.to_ascii_char().unwrap().is_hex(), true);
451     /// assert_eq!('a'.to_ascii_char().unwrap().is_hex(), true);
452     /// assert_eq!('F'.to_ascii_char().unwrap().is_hex(), true);
453     /// assert_eq!('G'.to_ascii_char().unwrap().is_hex(), false);
454     /// assert_eq!(' '.to_ascii_char().unwrap().is_hex(), false);
455     /// ```
456     #[inline]
is_hex(self) -> bool457     pub fn is_hex(self) -> bool {
458         self.is_digit() || (self.as_byte() | 0x20u8).wrapping_sub(b'a') < 6
459     }
460 
461     /// Unicode has printable versions of the ASCII control codes, like '␛'.
462     ///
463     /// This function is identical with `.as_char()`
464     /// for all values `.is_printable()` returns true for,
465     /// but replaces the control codes with those unicodes printable versions.
466     ///
467     /// # Examples
468     /// ```
469     /// # use ascii::ToAsciiChar;
470     /// assert_eq!('\0'.to_ascii_char().unwrap().as_printable_char(), '␀');
471     /// assert_eq!('\n'.to_ascii_char().unwrap().as_printable_char(), '␊');
472     /// assert_eq!(' '.to_ascii_char().unwrap().as_printable_char(), ' ');
473     /// assert_eq!('p'.to_ascii_char().unwrap().as_printable_char(), 'p');
474     /// ```
as_printable_char(self) -> char475     pub fn as_printable_char(self) -> char {
476         unsafe {
477             match self as u8 {
478                 b' '...b'~' => self.as_char(),
479                 127 => '␡',
480                 _ => char::from_u32_unchecked(self as u32 + '␀' as u32),
481             }
482         }
483     }
484 
485     /// Replaces letters `a` to `z` with `A` to `Z`
make_ascii_uppercase(&mut self)486     pub fn make_ascii_uppercase(&mut self) {
487         *self = self.to_ascii_uppercase()
488     }
489 
490     /// Replaces letters `A` to `Z` with `a` to `z`
make_ascii_lowercase(&mut self)491     pub fn make_ascii_lowercase(&mut self) {
492         *self = self.to_ascii_lowercase()
493     }
494 
495     /// Maps letters `a`...`z` to `A`...`Z` and returns everything else unchanged.
496     #[inline]
to_ascii_uppercase(&self) -> Self497     pub fn to_ascii_uppercase(&self) -> Self {
498         unsafe {
499             match *self as u8 {
500                 b'a'...b'z' => AsciiChar::from_unchecked(self.as_byte() - (b'a' - b'A')),
501                 _ => *self,
502             }
503         }
504     }
505 
506     /// Maps letters `A`...`Z` to `a`...`z` and returns everything else unchanged.
507     #[inline]
to_ascii_lowercase(&self) -> Self508     pub fn to_ascii_lowercase(&self) -> Self {
509         unsafe {
510             match *self as u8 {
511                 b'A'...b'Z' => AsciiChar::from_unchecked(self.as_byte() + (b'a' - b'A')),
512                 _ => *self,
513             }
514         }
515     }
516 
517     /// Compares two characters case-insensitively.
eq_ignore_ascii_case(&self, other: &Self) -> bool518     pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
519         self.to_ascii_lowercase() == other.to_ascii_lowercase()
520     }
521 }
522 
523 impl fmt::Display for AsciiChar {
524     #[inline]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result525     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
526         self.as_char().fmt(f)
527     }
528 }
529 
530 impl fmt::Debug for AsciiChar {
531     #[inline]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result532     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
533         self.as_char().fmt(f)
534     }
535 }
536 
537 #[cfg(feature = "std")]
538 impl AsciiExt for AsciiChar {
539     type Owned = AsciiChar;
540 
541     #[inline]
is_ascii(&self) -> bool542     fn is_ascii(&self) -> bool {
543         true
544     }
545 
546     #[inline]
to_ascii_uppercase(&self) -> AsciiChar547     fn to_ascii_uppercase(&self) -> AsciiChar {
548         unsafe {
549             self.as_byte()
550                 .to_ascii_uppercase()
551                 .to_ascii_char_unchecked()
552         }
553     }
554 
555     #[inline]
to_ascii_lowercase(&self) -> AsciiChar556     fn to_ascii_lowercase(&self) -> AsciiChar {
557         unsafe {
558             self.as_byte()
559                 .to_ascii_lowercase()
560                 .to_ascii_char_unchecked()
561         }
562     }
563 
eq_ignore_ascii_case(&self, other: &Self) -> bool564     fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
565         self.as_byte().eq_ignore_ascii_case(&other.as_byte())
566     }
567 
568     #[inline]
make_ascii_uppercase(&mut self)569     fn make_ascii_uppercase(&mut self) {
570         *self = self.to_ascii_uppercase();
571     }
572 
573     #[inline]
make_ascii_lowercase(&mut self)574     fn make_ascii_lowercase(&mut self) {
575         *self = self.to_ascii_lowercase();
576     }
577 }
578 
579 impl Default for AsciiChar {
default() -> AsciiChar580     fn default() -> AsciiChar {
581         AsciiChar::Null
582     }
583 }
584 
585 macro_rules! impl_into_partial_eq_ord {($wider:ty, $to_wider:expr) => {
586     impl From<AsciiChar> for $wider {
587         #[inline]
588         fn from(a: AsciiChar) -> $wider {
589             $to_wider(a)
590         }
591     }
592     impl PartialEq<$wider> for AsciiChar {
593         #[inline]
594         fn eq(&self, rhs: &$wider) -> bool {
595             $to_wider(*self) == *rhs
596         }
597     }
598     impl PartialEq<AsciiChar> for $wider {
599         #[inline]
600         fn eq(&self, rhs: &AsciiChar) -> bool {
601             *self == $to_wider(*rhs)
602         }
603     }
604     impl PartialOrd<$wider> for AsciiChar {
605         #[inline]
606         fn partial_cmp(&self, rhs: &$wider) -> Option<Ordering> {
607             $to_wider(*self).partial_cmp(rhs)
608         }
609     }
610     impl PartialOrd<AsciiChar> for $wider {
611         #[inline]
612         fn partial_cmp(&self, rhs: &AsciiChar) -> Option<Ordering> {
613             self.partial_cmp(&$to_wider(*rhs))
614         }
615     }
616 }}
617 impl_into_partial_eq_ord!{u8, AsciiChar::as_byte}
618 impl_into_partial_eq_ord!{char, AsciiChar::as_char}
619 
620 
621 /// Error returned by `ToAsciiChar`.
622 #[derive(Clone, Copy, PartialEq, Eq)]
623 pub struct ToAsciiCharError(());
624 
625 const ERRORMSG_CHAR: &'static str = "not an ASCII character";
626 
627 #[cfg(not(feature = "std"))]
628 impl ToAsciiCharError {
629     /// Returns a description for this error, like `std::error::Error::description`.
630     #[inline]
description(&self) -> &'static str631     pub fn description(&self) -> &'static str {
632         ERRORMSG_CHAR
633     }
634 }
635 
636 impl fmt::Debug for ToAsciiCharError {
fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result637     fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
638         write!(fmtr, "{}", ERRORMSG_CHAR)
639     }
640 }
641 
642 impl fmt::Display for ToAsciiCharError {
fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result643     fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
644         write!(fmtr, "{}", ERRORMSG_CHAR)
645     }
646 }
647 
648 #[cfg(feature = "std")]
649 impl Error for ToAsciiCharError {
650     #[inline]
description(&self) -> &'static str651     fn description(&self) -> &'static str {
652         ERRORMSG_CHAR
653     }
654 }
655 
656 /// Convert `char`, `u8` and other character types to `AsciiChar`.
657 pub trait ToAsciiChar {
658     /// Convert to `AsciiChar` without checking that it is an ASCII character.
to_ascii_char_unchecked(self) -> AsciiChar659     unsafe fn to_ascii_char_unchecked(self) -> AsciiChar;
660     /// Convert to `AsciiChar`.
to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>661     fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>;
662 }
663 
664 impl ToAsciiChar for AsciiChar {
665     #[inline]
to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>666     fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
667         Ok(self)
668     }
669     #[inline]
to_ascii_char_unchecked(self) -> AsciiChar670     unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
671         self
672     }
673 }
674 
675 impl ToAsciiChar for u8 {
676     #[inline]
to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>677     fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
678         (self as u32).to_ascii_char()
679     }
680     #[inline]
to_ascii_char_unchecked(self) -> AsciiChar681     unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
682         mem::transmute(self)
683     }
684 }
685 
686 impl ToAsciiChar for i8 {
687     #[inline]
to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>688     fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
689         (self as u32).to_ascii_char()
690     }
691     #[inline]
to_ascii_char_unchecked(self) -> AsciiChar692     unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
693         mem::transmute(self)
694     }
695 }
696 
697 impl ToAsciiChar for char {
698     #[inline]
to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>699     fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
700         (self as u32).to_ascii_char()
701     }
702     #[inline]
to_ascii_char_unchecked(self) -> AsciiChar703     unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
704         (self as u32).to_ascii_char_unchecked()
705     }
706 }
707 
708 impl ToAsciiChar for u32 {
to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>709     fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
710         unsafe {
711             match self {
712                 0..=127 => Ok(self.to_ascii_char_unchecked()),
713                 _ => Err(ToAsciiCharError(()))
714             }
715         }
716     }
717     #[inline]
to_ascii_char_unchecked(self) -> AsciiChar718     unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
719         (self as u8).to_ascii_char_unchecked()
720     }
721 }
722 
723 impl ToAsciiChar for u16 {
to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>724     fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
725         (self as u32).to_ascii_char()
726     }
727     #[inline]
to_ascii_char_unchecked(self) -> AsciiChar728     unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
729         (self as u8).to_ascii_char_unchecked()
730     }
731 }
732 
733 #[cfg(feature = "quickcheck")]
734 impl Arbitrary for AsciiChar {
arbitrary<G: Gen>(g: &mut G) -> Self735     fn arbitrary<G: Gen>(g: &mut G) -> Self {
736         let mode = g.gen_range(0, 100);
737         match mode {
738             0...14 => {
739                 // Control characters
740                 unsafe { AsciiChar::from_unchecked(g.gen_range(0, 0x1F) as u8) }
741             }
742             15...39 => {
743                 // Characters often used in programming languages
744                 *g.choose(&[
745                     AsciiChar::Space, AsciiChar::Tab, AsciiChar::LineFeed, AsciiChar::Tilde,
746                     AsciiChar::Grave, AsciiChar::Exclamation, AsciiChar::At, AsciiChar::Hash,
747                     AsciiChar::Dollar, AsciiChar::Percent, AsciiChar::Ampersand,
748                     AsciiChar::Asterisk, AsciiChar::ParenOpen, AsciiChar::ParenClose,
749                     AsciiChar::UnderScore, AsciiChar::Minus, AsciiChar::Equal, AsciiChar::Plus,
750                     AsciiChar::BracketOpen, AsciiChar::BracketClose, AsciiChar::CurlyBraceOpen,
751                     AsciiChar::CurlyBraceClose, AsciiChar::Colon, AsciiChar::Semicolon,
752                     AsciiChar::Apostrophe, AsciiChar::Quotation, AsciiChar::BackSlash,
753                     AsciiChar::VerticalBar, AsciiChar::Caret, AsciiChar::Comma, AsciiChar::LessThan,
754                     AsciiChar::GreaterThan, AsciiChar::Dot, AsciiChar::Slash, AsciiChar::Question,
755                     AsciiChar::_0, AsciiChar::_1, AsciiChar::_2, AsciiChar::_3, AsciiChar::_3,
756                     AsciiChar::_4 , AsciiChar::_6, AsciiChar::_7, AsciiChar::_8, AsciiChar::_9,
757                 ]).unwrap()
758             }
759             40...99 => {
760                 // Completely arbitrary characters
761                 unsafe { AsciiChar::from_unchecked(g.gen_range(0, 0x80) as u8) }
762             }
763             _ => unreachable!(),
764         }
765     }
766 
shrink(&self) -> Box<Iterator<Item = Self>>767     fn shrink(&self) -> Box<Iterator<Item = Self>> {
768         Box::new((*self as u8).shrink().filter_map(
769             |x| AsciiChar::from(x).ok(),
770         ))
771     }
772 }
773 
774 #[cfg(test)]
775 mod tests {
776     use super::{AsciiChar, ToAsciiChar, ToAsciiCharError};
777     use AsciiChar::*;
778 
779     #[test]
to_ascii_char()780     fn to_ascii_char() {
781         fn generic<C: ToAsciiChar>(ch: C) -> Result<AsciiChar, ToAsciiCharError> {
782             ch.to_ascii_char()
783         }
784         assert_eq!(generic(A), Ok(A));
785         assert_eq!(generic(b'A'), Ok(A));
786         assert_eq!(generic('A'), Ok(A));
787         assert!(generic(200u16).is_err());
788         assert!(generic('λ').is_err());
789     }
790 
791     #[test]
as_byte_and_char()792     fn as_byte_and_char() {
793         assert_eq!(A.as_byte(), b'A');
794         assert_eq!(A.as_char(), 'A');
795     }
796 
797     #[test]
is_digit()798     fn is_digit() {
799         assert_eq!('0'.to_ascii_char().unwrap().is_digit(), true);
800         assert_eq!('9'.to_ascii_char().unwrap().is_digit(), true);
801         assert_eq!('/'.to_ascii_char().unwrap().is_digit(), false);
802         assert_eq!(':'.to_ascii_char().unwrap().is_digit(), false);
803     }
804 
805     #[test]
is_control()806     fn is_control() {
807         assert_eq!(US.is_control(), true);
808         assert_eq!(DEL.is_control(), true);
809         assert_eq!(Space.is_control(), false);
810     }
811 
812     #[test]
cmp_wider()813     fn cmp_wider() {
814         assert_eq!(A, 'A');
815         assert_eq!(b'b', b);
816         assert!(a < 'z');
817     }
818 
819     #[test]
ascii_case()820     fn ascii_case() {
821         assert_eq!(At.to_ascii_lowercase(), At);
822         assert_eq!(At.to_ascii_uppercase(), At);
823         assert_eq!(A.to_ascii_lowercase(), a);
824         assert_eq!(A.to_ascii_uppercase(), A);
825         assert_eq!(a.to_ascii_lowercase(), a);
826         assert_eq!(a.to_ascii_uppercase(), A);
827 
828         assert!(LineFeed.eq_ignore_ascii_case(&LineFeed));
829         assert!(!LineFeed.eq_ignore_ascii_case(&CarriageReturn));
830         assert!(z.eq_ignore_ascii_case(&Z));
831         assert!(Z.eq_ignore_ascii_case(&z));
832         assert!(!Z.eq_ignore_ascii_case(&DEL));
833     }
834 
835     #[test]
836     #[cfg(feature = "std")]
ascii_ext()837     fn ascii_ext() {
838         #[allow(deprecated)]
839         use std::ascii::AsciiExt;
840         assert!(AsciiExt::is_ascii(&Null));
841         assert!(AsciiExt::is_ascii(&DEL));
842         assert!(AsciiExt::eq_ignore_ascii_case(&a, &A));
843         assert!(!AsciiExt::eq_ignore_ascii_case(&A, &At));
844         assert_eq!(AsciiExt::to_ascii_lowercase(&A), a);
845         assert_eq!(AsciiExt::to_ascii_uppercase(&A), A);
846         assert_eq!(AsciiExt::to_ascii_lowercase(&a), a);
847         assert_eq!(AsciiExt::to_ascii_uppercase(&a), A);
848         assert_eq!(AsciiExt::to_ascii_lowercase(&At), At);
849         assert_eq!(AsciiExt::to_ascii_uppercase(&At), At);
850         let mut mutable = (A,a);
851         AsciiExt::make_ascii_lowercase(&mut mutable.0);
852         AsciiExt::make_ascii_uppercase(&mut mutable.1);
853         assert_eq!(mutable.0, a);
854         assert_eq!(mutable.1, A);
855     }
856 
857     #[test]
858     #[cfg(feature = "std")]
fmt_ascii()859     fn fmt_ascii() {
860         assert_eq!(format!("{}", t), "t");
861         assert_eq!(format!("{:?}", t), "'t'");
862         assert_eq!(format!("{}", LineFeed), "\n");
863         assert_eq!(format!("{:?}", LineFeed), "'\\n'");
864     }
865 
866 }
867