core/ascii/
ascii_char.rs

1//! This uses the name `AsciiChar`, even though it's not exposed that way right now,
2//! because it avoids a whole bunch of "are you sure you didn't mean `char`?"
3//! suggestions from rustc if you get anything slightly wrong in here, and overall
4//! helps with clarity as we're also referring to `char` intentionally in here.
5
6use crate::mem::transmute;
7use crate::{assert_unsafe_precondition, fmt};
8
9/// One of the 128 Unicode characters from U+0000 through U+007F,
10/// often known as the [ASCII] subset.
11///
12/// Officially, this is the first [block] in Unicode, _Basic Latin_.
13/// For details, see the [*C0 Controls and Basic Latin*][chart] code chart.
14///
15/// This block was based on older 7-bit character code standards such as
16/// ANSI X3.4-1977, ISO 646-1973, and [NIST FIPS 1-2].
17///
18/// # When to use this
19///
20/// The main advantage of this subset is that it's always valid UTF-8.  As such,
21/// the `&[ascii::Char]` -> `&str` conversion function (as well as other related
22/// ones) are O(1): *no* runtime checks are needed.
23///
24/// If you're consuming strings, you should usually handle Unicode and thus
25/// accept `str`s, not limit yourself to `ascii::Char`s.
26///
27/// However, certain formats are intentionally designed to produce ASCII-only
28/// output in order to be 8-bit-clean.  In those cases, it can be simpler and
29/// faster to generate `ascii::Char`s instead of dealing with the variable width
30/// properties of general UTF-8 encoded strings, while still allowing the result
31/// to be used freely with other Rust things that deal in general `str`s.
32///
33/// For example, a UUID library might offer a way to produce the string
34/// representation of a UUID as an `[ascii::Char; 36]` to avoid memory
35/// allocation yet still allow it to be used as UTF-8 via `as_str` without
36/// paying for validation (or needing `unsafe` code) the way it would if it
37/// were provided as a `[u8; 36]`.
38///
39/// # Layout
40///
41/// This type is guaranteed to have a size and alignment of 1 byte.
42///
43/// # Names
44///
45/// The variants on this type are [Unicode names][NamesList] of the characters
46/// in upper camel case, with a few tweaks:
47/// - For `<control>` characters, the primary alias name is used.
48/// - `LATIN` is dropped, as this block has no non-latin letters.
49/// - `LETTER` is dropped, as `CAPITAL`/`SMALL` suffices in this block.
50/// - `DIGIT`s use a single digit rather than writing out `ZERO`, `ONE`, etc.
51///
52/// [ASCII]: https://www.unicode.org/glossary/index.html#ASCII
53/// [block]: https://www.unicode.org/glossary/index.html#block
54/// [chart]: https://www.unicode.org/charts/PDF/U0000.pdf
55/// [NIST FIPS 1-2]: https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub1-2-1977.pdf
56/// [NamesList]: https://www.unicode.org/Public/15.0.0/ucd/NamesList.txt
57#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
58#[unstable(feature = "ascii_char", issue = "110998")]
59#[repr(u8)]
60pub enum AsciiChar {
61    /// U+0000 (The default variant)
62    #[unstable(feature = "ascii_char_variants", issue = "110998")]
63    Null = 0,
64    /// U+0001
65    #[unstable(feature = "ascii_char_variants", issue = "110998")]
66    StartOfHeading = 1,
67    /// U+0002
68    #[unstable(feature = "ascii_char_variants", issue = "110998")]
69    StartOfText = 2,
70    /// U+0003
71    #[unstable(feature = "ascii_char_variants", issue = "110998")]
72    EndOfText = 3,
73    /// U+0004
74    #[unstable(feature = "ascii_char_variants", issue = "110998")]
75    EndOfTransmission = 4,
76    /// U+0005
77    #[unstable(feature = "ascii_char_variants", issue = "110998")]
78    Enquiry = 5,
79    /// U+0006
80    #[unstable(feature = "ascii_char_variants", issue = "110998")]
81    Acknowledge = 6,
82    /// U+0007
83    #[unstable(feature = "ascii_char_variants", issue = "110998")]
84    Bell = 7,
85    /// U+0008
86    #[unstable(feature = "ascii_char_variants", issue = "110998")]
87    Backspace = 8,
88    /// U+0009
89    #[unstable(feature = "ascii_char_variants", issue = "110998")]
90    CharacterTabulation = 9,
91    /// U+000A
92    #[unstable(feature = "ascii_char_variants", issue = "110998")]
93    LineFeed = 10,
94    /// U+000B
95    #[unstable(feature = "ascii_char_variants", issue = "110998")]
96    LineTabulation = 11,
97    /// U+000C
98    #[unstable(feature = "ascii_char_variants", issue = "110998")]
99    FormFeed = 12,
100    /// U+000D
101    #[unstable(feature = "ascii_char_variants", issue = "110998")]
102    CarriageReturn = 13,
103    /// U+000E
104    #[unstable(feature = "ascii_char_variants", issue = "110998")]
105    ShiftOut = 14,
106    /// U+000F
107    #[unstable(feature = "ascii_char_variants", issue = "110998")]
108    ShiftIn = 15,
109    /// U+0010
110    #[unstable(feature = "ascii_char_variants", issue = "110998")]
111    DataLinkEscape = 16,
112    /// U+0011
113    #[unstable(feature = "ascii_char_variants", issue = "110998")]
114    DeviceControlOne = 17,
115    /// U+0012
116    #[unstable(feature = "ascii_char_variants", issue = "110998")]
117    DeviceControlTwo = 18,
118    /// U+0013
119    #[unstable(feature = "ascii_char_variants", issue = "110998")]
120    DeviceControlThree = 19,
121    /// U+0014
122    #[unstable(feature = "ascii_char_variants", issue = "110998")]
123    DeviceControlFour = 20,
124    /// U+0015
125    #[unstable(feature = "ascii_char_variants", issue = "110998")]
126    NegativeAcknowledge = 21,
127    /// U+0016
128    #[unstable(feature = "ascii_char_variants", issue = "110998")]
129    SynchronousIdle = 22,
130    /// U+0017
131    #[unstable(feature = "ascii_char_variants", issue = "110998")]
132    EndOfTransmissionBlock = 23,
133    /// U+0018
134    #[unstable(feature = "ascii_char_variants", issue = "110998")]
135    Cancel = 24,
136    /// U+0019
137    #[unstable(feature = "ascii_char_variants", issue = "110998")]
138    EndOfMedium = 25,
139    /// U+001A
140    #[unstable(feature = "ascii_char_variants", issue = "110998")]
141    Substitute = 26,
142    /// U+001B
143    #[unstable(feature = "ascii_char_variants", issue = "110998")]
144    Escape = 27,
145    /// U+001C
146    #[unstable(feature = "ascii_char_variants", issue = "110998")]
147    InformationSeparatorFour = 28,
148    /// U+001D
149    #[unstable(feature = "ascii_char_variants", issue = "110998")]
150    InformationSeparatorThree = 29,
151    /// U+001E
152    #[unstable(feature = "ascii_char_variants", issue = "110998")]
153    InformationSeparatorTwo = 30,
154    /// U+001F
155    #[unstable(feature = "ascii_char_variants", issue = "110998")]
156    InformationSeparatorOne = 31,
157    /// U+0020
158    #[unstable(feature = "ascii_char_variants", issue = "110998")]
159    Space = 32,
160    /// U+0021
161    #[unstable(feature = "ascii_char_variants", issue = "110998")]
162    ExclamationMark = 33,
163    /// U+0022
164    #[unstable(feature = "ascii_char_variants", issue = "110998")]
165    QuotationMark = 34,
166    /// U+0023
167    #[unstable(feature = "ascii_char_variants", issue = "110998")]
168    NumberSign = 35,
169    /// U+0024
170    #[unstable(feature = "ascii_char_variants", issue = "110998")]
171    DollarSign = 36,
172    /// U+0025
173    #[unstable(feature = "ascii_char_variants", issue = "110998")]
174    PercentSign = 37,
175    /// U+0026
176    #[unstable(feature = "ascii_char_variants", issue = "110998")]
177    Ampersand = 38,
178    /// U+0027
179    #[unstable(feature = "ascii_char_variants", issue = "110998")]
180    Apostrophe = 39,
181    /// U+0028
182    #[unstable(feature = "ascii_char_variants", issue = "110998")]
183    LeftParenthesis = 40,
184    /// U+0029
185    #[unstable(feature = "ascii_char_variants", issue = "110998")]
186    RightParenthesis = 41,
187    /// U+002A
188    #[unstable(feature = "ascii_char_variants", issue = "110998")]
189    Asterisk = 42,
190    /// U+002B
191    #[unstable(feature = "ascii_char_variants", issue = "110998")]
192    PlusSign = 43,
193    /// U+002C
194    #[unstable(feature = "ascii_char_variants", issue = "110998")]
195    Comma = 44,
196    /// U+002D
197    #[unstable(feature = "ascii_char_variants", issue = "110998")]
198    HyphenMinus = 45,
199    /// U+002E
200    #[unstable(feature = "ascii_char_variants", issue = "110998")]
201    FullStop = 46,
202    /// U+002F
203    #[unstable(feature = "ascii_char_variants", issue = "110998")]
204    Solidus = 47,
205    /// U+0030
206    #[unstable(feature = "ascii_char_variants", issue = "110998")]
207    Digit0 = 48,
208    /// U+0031
209    #[unstable(feature = "ascii_char_variants", issue = "110998")]
210    Digit1 = 49,
211    /// U+0032
212    #[unstable(feature = "ascii_char_variants", issue = "110998")]
213    Digit2 = 50,
214    /// U+0033
215    #[unstable(feature = "ascii_char_variants", issue = "110998")]
216    Digit3 = 51,
217    /// U+0034
218    #[unstable(feature = "ascii_char_variants", issue = "110998")]
219    Digit4 = 52,
220    /// U+0035
221    #[unstable(feature = "ascii_char_variants", issue = "110998")]
222    Digit5 = 53,
223    /// U+0036
224    #[unstable(feature = "ascii_char_variants", issue = "110998")]
225    Digit6 = 54,
226    /// U+0037
227    #[unstable(feature = "ascii_char_variants", issue = "110998")]
228    Digit7 = 55,
229    /// U+0038
230    #[unstable(feature = "ascii_char_variants", issue = "110998")]
231    Digit8 = 56,
232    /// U+0039
233    #[unstable(feature = "ascii_char_variants", issue = "110998")]
234    Digit9 = 57,
235    /// U+003A
236    #[unstable(feature = "ascii_char_variants", issue = "110998")]
237    Colon = 58,
238    /// U+003B
239    #[unstable(feature = "ascii_char_variants", issue = "110998")]
240    Semicolon = 59,
241    /// U+003C
242    #[unstable(feature = "ascii_char_variants", issue = "110998")]
243    LessThanSign = 60,
244    /// U+003D
245    #[unstable(feature = "ascii_char_variants", issue = "110998")]
246    EqualsSign = 61,
247    /// U+003E
248    #[unstable(feature = "ascii_char_variants", issue = "110998")]
249    GreaterThanSign = 62,
250    /// U+003F
251    #[unstable(feature = "ascii_char_variants", issue = "110998")]
252    QuestionMark = 63,
253    /// U+0040
254    #[unstable(feature = "ascii_char_variants", issue = "110998")]
255    CommercialAt = 64,
256    /// U+0041
257    #[unstable(feature = "ascii_char_variants", issue = "110998")]
258    CapitalA = 65,
259    /// U+0042
260    #[unstable(feature = "ascii_char_variants", issue = "110998")]
261    CapitalB = 66,
262    /// U+0043
263    #[unstable(feature = "ascii_char_variants", issue = "110998")]
264    CapitalC = 67,
265    /// U+0044
266    #[unstable(feature = "ascii_char_variants", issue = "110998")]
267    CapitalD = 68,
268    /// U+0045
269    #[unstable(feature = "ascii_char_variants", issue = "110998")]
270    CapitalE = 69,
271    /// U+0046
272    #[unstable(feature = "ascii_char_variants", issue = "110998")]
273    CapitalF = 70,
274    /// U+0047
275    #[unstable(feature = "ascii_char_variants", issue = "110998")]
276    CapitalG = 71,
277    /// U+0048
278    #[unstable(feature = "ascii_char_variants", issue = "110998")]
279    CapitalH = 72,
280    /// U+0049
281    #[unstable(feature = "ascii_char_variants", issue = "110998")]
282    CapitalI = 73,
283    /// U+004A
284    #[unstable(feature = "ascii_char_variants", issue = "110998")]
285    CapitalJ = 74,
286    /// U+004B
287    #[unstable(feature = "ascii_char_variants", issue = "110998")]
288    CapitalK = 75,
289    /// U+004C
290    #[unstable(feature = "ascii_char_variants", issue = "110998")]
291    CapitalL = 76,
292    /// U+004D
293    #[unstable(feature = "ascii_char_variants", issue = "110998")]
294    CapitalM = 77,
295    /// U+004E
296    #[unstable(feature = "ascii_char_variants", issue = "110998")]
297    CapitalN = 78,
298    /// U+004F
299    #[unstable(feature = "ascii_char_variants", issue = "110998")]
300    CapitalO = 79,
301    /// U+0050
302    #[unstable(feature = "ascii_char_variants", issue = "110998")]
303    CapitalP = 80,
304    /// U+0051
305    #[unstable(feature = "ascii_char_variants", issue = "110998")]
306    CapitalQ = 81,
307    /// U+0052
308    #[unstable(feature = "ascii_char_variants", issue = "110998")]
309    CapitalR = 82,
310    /// U+0053
311    #[unstable(feature = "ascii_char_variants", issue = "110998")]
312    CapitalS = 83,
313    /// U+0054
314    #[unstable(feature = "ascii_char_variants", issue = "110998")]
315    CapitalT = 84,
316    /// U+0055
317    #[unstable(feature = "ascii_char_variants", issue = "110998")]
318    CapitalU = 85,
319    /// U+0056
320    #[unstable(feature = "ascii_char_variants", issue = "110998")]
321    CapitalV = 86,
322    /// U+0057
323    #[unstable(feature = "ascii_char_variants", issue = "110998")]
324    CapitalW = 87,
325    /// U+0058
326    #[unstable(feature = "ascii_char_variants", issue = "110998")]
327    CapitalX = 88,
328    /// U+0059
329    #[unstable(feature = "ascii_char_variants", issue = "110998")]
330    CapitalY = 89,
331    /// U+005A
332    #[unstable(feature = "ascii_char_variants", issue = "110998")]
333    CapitalZ = 90,
334    /// U+005B
335    #[unstable(feature = "ascii_char_variants", issue = "110998")]
336    LeftSquareBracket = 91,
337    /// U+005C
338    #[unstable(feature = "ascii_char_variants", issue = "110998")]
339    ReverseSolidus = 92,
340    /// U+005D
341    #[unstable(feature = "ascii_char_variants", issue = "110998")]
342    RightSquareBracket = 93,
343    /// U+005E
344    #[unstable(feature = "ascii_char_variants", issue = "110998")]
345    CircumflexAccent = 94,
346    /// U+005F
347    #[unstable(feature = "ascii_char_variants", issue = "110998")]
348    LowLine = 95,
349    /// U+0060
350    #[unstable(feature = "ascii_char_variants", issue = "110998")]
351    GraveAccent = 96,
352    /// U+0061
353    #[unstable(feature = "ascii_char_variants", issue = "110998")]
354    SmallA = 97,
355    /// U+0062
356    #[unstable(feature = "ascii_char_variants", issue = "110998")]
357    SmallB = 98,
358    /// U+0063
359    #[unstable(feature = "ascii_char_variants", issue = "110998")]
360    SmallC = 99,
361    /// U+0064
362    #[unstable(feature = "ascii_char_variants", issue = "110998")]
363    SmallD = 100,
364    /// U+0065
365    #[unstable(feature = "ascii_char_variants", issue = "110998")]
366    SmallE = 101,
367    /// U+0066
368    #[unstable(feature = "ascii_char_variants", issue = "110998")]
369    SmallF = 102,
370    /// U+0067
371    #[unstable(feature = "ascii_char_variants", issue = "110998")]
372    SmallG = 103,
373    /// U+0068
374    #[unstable(feature = "ascii_char_variants", issue = "110998")]
375    SmallH = 104,
376    /// U+0069
377    #[unstable(feature = "ascii_char_variants", issue = "110998")]
378    SmallI = 105,
379    /// U+006A
380    #[unstable(feature = "ascii_char_variants", issue = "110998")]
381    SmallJ = 106,
382    /// U+006B
383    #[unstable(feature = "ascii_char_variants", issue = "110998")]
384    SmallK = 107,
385    /// U+006C
386    #[unstable(feature = "ascii_char_variants", issue = "110998")]
387    SmallL = 108,
388    /// U+006D
389    #[unstable(feature = "ascii_char_variants", issue = "110998")]
390    SmallM = 109,
391    /// U+006E
392    #[unstable(feature = "ascii_char_variants", issue = "110998")]
393    SmallN = 110,
394    /// U+006F
395    #[unstable(feature = "ascii_char_variants", issue = "110998")]
396    SmallO = 111,
397    /// U+0070
398    #[unstable(feature = "ascii_char_variants", issue = "110998")]
399    SmallP = 112,
400    /// U+0071
401    #[unstable(feature = "ascii_char_variants", issue = "110998")]
402    SmallQ = 113,
403    /// U+0072
404    #[unstable(feature = "ascii_char_variants", issue = "110998")]
405    SmallR = 114,
406    /// U+0073
407    #[unstable(feature = "ascii_char_variants", issue = "110998")]
408    SmallS = 115,
409    /// U+0074
410    #[unstable(feature = "ascii_char_variants", issue = "110998")]
411    SmallT = 116,
412    /// U+0075
413    #[unstable(feature = "ascii_char_variants", issue = "110998")]
414    SmallU = 117,
415    /// U+0076
416    #[unstable(feature = "ascii_char_variants", issue = "110998")]
417    SmallV = 118,
418    /// U+0077
419    #[unstable(feature = "ascii_char_variants", issue = "110998")]
420    SmallW = 119,
421    /// U+0078
422    #[unstable(feature = "ascii_char_variants", issue = "110998")]
423    SmallX = 120,
424    /// U+0079
425    #[unstable(feature = "ascii_char_variants", issue = "110998")]
426    SmallY = 121,
427    /// U+007A
428    #[unstable(feature = "ascii_char_variants", issue = "110998")]
429    SmallZ = 122,
430    /// U+007B
431    #[unstable(feature = "ascii_char_variants", issue = "110998")]
432    LeftCurlyBracket = 123,
433    /// U+007C
434    #[unstable(feature = "ascii_char_variants", issue = "110998")]
435    VerticalLine = 124,
436    /// U+007D
437    #[unstable(feature = "ascii_char_variants", issue = "110998")]
438    RightCurlyBracket = 125,
439    /// U+007E
440    #[unstable(feature = "ascii_char_variants", issue = "110998")]
441    Tilde = 126,
442    /// U+007F
443    #[unstable(feature = "ascii_char_variants", issue = "110998")]
444    Delete = 127,
445}
446
447impl AsciiChar {
448    /// The character with the lowest ASCII code.
449    #[unstable(feature = "ascii_char", issue = "110998")]
450    pub const MIN: Self = Self::Null;
451
452    /// The character with the highest ASCII code.
453    #[unstable(feature = "ascii_char", issue = "110998")]
454    pub const MAX: Self = Self::Delete;
455
456    /// Creates an ASCII character from the byte `b`,
457    /// or returns `None` if it's too large.
458    #[unstable(feature = "ascii_char", issue = "110998")]
459    #[inline]
460    pub const fn from_u8(b: u8) -> Option<Self> {
461        if b <= 127 {
462            // SAFETY: Just checked that `b` is in-range
463            Some(unsafe { Self::from_u8_unchecked(b) })
464        } else {
465            None
466        }
467    }
468
469    /// Creates an ASCII character from the byte `b`,
470    /// without checking whether it's valid.
471    ///
472    /// # Safety
473    ///
474    /// `b` must be in `0..=127`, or else this is UB.
475    #[unstable(feature = "ascii_char", issue = "110998")]
476    #[inline]
477    pub const unsafe fn from_u8_unchecked(b: u8) -> Self {
478        // SAFETY: Our safety precondition is that `b` is in-range.
479        unsafe { transmute(b) }
480    }
481
482    /// When passed the *number* `0`, `1`, …, `9`, returns the *character*
483    /// `'0'`, `'1'`, …, `'9'` respectively.
484    ///
485    /// If `d >= 10`, returns `None`.
486    #[unstable(feature = "ascii_char", issue = "110998")]
487    #[inline]
488    pub const fn digit(d: u8) -> Option<Self> {
489        if d < 10 {
490            // SAFETY: Just checked it's in-range.
491            Some(unsafe { Self::digit_unchecked(d) })
492        } else {
493            None
494        }
495    }
496
497    /// When passed the *number* `0`, `1`, …, `9`, returns the *character*
498    /// `'0'`, `'1'`, …, `'9'` respectively, without checking that it's in-range.
499    ///
500    /// # Safety
501    ///
502    /// This is immediate UB if called with `d > 64`.
503    ///
504    /// If `d >= 10` and `d <= 64`, this is allowed to return any value or panic.
505    /// Notably, it should not be expected to return hex digits, or any other
506    /// reasonable extension of the decimal digits.
507    ///
508    /// (This loose safety condition is intended to simplify soundness proofs
509    /// when writing code using this method, since the implementation doesn't
510    /// need something really specific, not to make those other arguments do
511    /// something useful. It might be tightened before stabilization.)
512    #[unstable(feature = "ascii_char", issue = "110998")]
513    #[inline]
514    #[track_caller]
515    pub const unsafe fn digit_unchecked(d: u8) -> Self {
516        assert_unsafe_precondition!(
517            check_language_ub,
518            "`ascii::Char::digit_unchecked` input cannot exceed 9.",
519            (d: u8 = d) => d < 10
520        );
521
522        // SAFETY: `'0'` through `'9'` are U+00030 through U+0039,
523        // so because `d` must be 64 or less the addition can return at most
524        // 112 (0x70), which doesn't overflow and is within the ASCII range.
525        unsafe {
526            let byte = b'0'.unchecked_add(d);
527            Self::from_u8_unchecked(byte)
528        }
529    }
530
531    /// Gets this ASCII character as a byte.
532    #[unstable(feature = "ascii_char", issue = "110998")]
533    #[inline]
534    pub const fn to_u8(self) -> u8 {
535        self as u8
536    }
537
538    /// Gets this ASCII character as a `char` Unicode Scalar Value.
539    #[unstable(feature = "ascii_char", issue = "110998")]
540    #[inline]
541    pub const fn to_char(self) -> char {
542        self as u8 as char
543    }
544
545    /// Views this ASCII character as a one-code-unit UTF-8 `str`.
546    #[unstable(feature = "ascii_char", issue = "110998")]
547    #[inline]
548    pub const fn as_str(&self) -> &str {
549        crate::slice::from_ref(self).as_str()
550    }
551
552    /// Makes a copy of the value in its upper case equivalent.
553    ///
554    /// Letters 'a' to 'z' are mapped to 'A' to 'Z'.
555    ///
556    /// To uppercase the value in-place, use [`make_uppercase`].
557    ///
558    /// # Examples
559    ///
560    /// ```
561    /// #![feature(ascii_char, ascii_char_variants)]
562    /// use std::ascii;
563    ///
564    /// let lowercase_a = ascii::Char::SmallA;
565    ///
566    /// assert_eq!(
567    ///     ascii::Char::CapitalA,
568    ///     lowercase_a.to_uppercase(),
569    /// );
570    /// ```
571    ///
572    /// [`make_uppercase`]: Self::make_uppercase
573    #[must_use = "to uppercase the value in-place, use `make_uppercase()`"]
574    #[unstable(feature = "ascii_char", issue = "110998")]
575    #[inline]
576    pub const fn to_uppercase(self) -> Self {
577        let uppercase_byte = self.to_u8().to_ascii_uppercase();
578        // SAFETY: Toggling the 6th bit won't convert ASCII to non-ASCII.
579        unsafe { Self::from_u8_unchecked(uppercase_byte) }
580    }
581
582    /// Makes a copy of the value in its lower case equivalent.
583    ///
584    /// Letters 'A' to 'Z' are mapped to 'a' to 'z'.
585    ///
586    /// To lowercase the value in-place, use [`make_lowercase`].
587    ///
588    /// # Examples
589    ///
590    /// ```
591    /// #![feature(ascii_char, ascii_char_variants)]
592    /// use std::ascii;
593    ///
594    /// let uppercase_a = ascii::Char::CapitalA;
595    ///
596    /// assert_eq!(
597    ///     ascii::Char::SmallA,
598    ///     uppercase_a.to_lowercase(),
599    /// );
600    /// ```
601    ///
602    /// [`make_lowercase`]: Self::make_lowercase
603    #[must_use = "to lowercase the value in-place, use `make_lowercase()`"]
604    #[unstable(feature = "ascii_char", issue = "110998")]
605    #[inline]
606    pub const fn to_lowercase(self) -> Self {
607        let lowercase_byte = self.to_u8().to_ascii_lowercase();
608        // SAFETY: Setting the 6th bit won't convert ASCII to non-ASCII.
609        unsafe { Self::from_u8_unchecked(lowercase_byte) }
610    }
611
612    /// Checks that two values are a case-insensitive match.
613    ///
614    /// This is equivalent to `to_lowercase(a) == to_lowercase(b)`.
615    ///
616    /// # Examples
617    ///
618    /// ```
619    /// #![feature(ascii_char, ascii_char_variants)]
620    /// use std::ascii;
621    ///
622    /// let lowercase_a = ascii::Char::SmallA;
623    /// let uppercase_a = ascii::Char::CapitalA;
624    ///
625    /// assert!(lowercase_a.eq_ignore_case(uppercase_a));
626    /// ```
627    #[unstable(feature = "ascii_char", issue = "110998")]
628    #[inline]
629    pub const fn eq_ignore_case(self, other: Self) -> bool {
630        // FIXME(const-hack) `arg.to_u8().to_ascii_lowercase()` -> `arg.to_lowercase()`
631        // once `PartialEq` is const for `Self`.
632        self.to_u8().to_ascii_lowercase() == other.to_u8().to_ascii_lowercase()
633    }
634
635    /// Converts this value to its upper case equivalent in-place.
636    ///
637    /// Letters 'a' to 'z' are mapped to 'A' to 'Z'.
638    ///
639    /// To return a new uppercased value without modifying the existing one, use
640    /// [`to_uppercase`].
641    ///
642    /// # Examples
643    ///
644    /// ```
645    /// #![feature(ascii_char, ascii_char_variants)]
646    /// use std::ascii;
647    ///
648    /// let mut letter_a = ascii::Char::SmallA;
649    ///
650    /// letter_a.make_uppercase();
651    ///
652    /// assert_eq!(ascii::Char::CapitalA, letter_a);
653    /// ```
654    ///
655    /// [`to_uppercase`]: Self::to_uppercase
656    #[unstable(feature = "ascii_char", issue = "110998")]
657    #[inline]
658    pub const fn make_uppercase(&mut self) {
659        *self = self.to_uppercase();
660    }
661
662    /// Converts this value to its lower case equivalent in-place.
663    ///
664    /// Letters 'A' to 'Z' are mapped to 'a' to 'z'.
665    ///
666    /// To return a new lowercased value without modifying the existing one, use
667    /// [`to_lowercase`].
668    ///
669    /// # Examples
670    ///
671    /// ```
672    /// #![feature(ascii_char, ascii_char_variants)]
673    /// use std::ascii;
674    ///
675    /// let mut letter_a = ascii::Char::CapitalA;
676    ///
677    /// letter_a.make_lowercase();
678    ///
679    /// assert_eq!(ascii::Char::SmallA, letter_a);
680    /// ```
681    ///
682    /// [`to_lowercase`]: Self::to_lowercase
683    #[unstable(feature = "ascii_char", issue = "110998")]
684    #[inline]
685    pub const fn make_lowercase(&mut self) {
686        *self = self.to_lowercase();
687    }
688
689    /// Checks if the value is an alphabetic character:
690    ///
691    /// - 0x41 'A' ..= 0x5A 'Z', or
692    /// - 0x61 'a' ..= 0x7A 'z'.
693    ///
694    /// # Examples
695    ///
696    /// ```
697    /// #![feature(ascii_char, ascii_char_variants)]
698    /// use std::ascii;
699    ///
700    /// let uppercase_a = ascii::Char::CapitalA;
701    /// let uppercase_g = ascii::Char::CapitalG;
702    /// let a = ascii::Char::SmallA;
703    /// let g = ascii::Char::SmallG;
704    /// let zero = ascii::Char::Digit0;
705    /// let percent = ascii::Char::PercentSign;
706    /// let space = ascii::Char::Space;
707    /// let lf = ascii::Char::LineFeed;
708    /// let esc = ascii::Char::Escape;
709    ///
710    /// assert!(uppercase_a.is_alphabetic());
711    /// assert!(uppercase_g.is_alphabetic());
712    /// assert!(a.is_alphabetic());
713    /// assert!(g.is_alphabetic());
714    /// assert!(!zero.is_alphabetic());
715    /// assert!(!percent.is_alphabetic());
716    /// assert!(!space.is_alphabetic());
717    /// assert!(!lf.is_alphabetic());
718    /// assert!(!esc.is_alphabetic());
719    /// ```
720    #[must_use]
721    #[unstable(feature = "ascii_char", issue = "110998")]
722    #[inline]
723    pub const fn is_alphabetic(self) -> bool {
724        self.to_u8().is_ascii_alphabetic()
725    }
726
727    /// Checks if the value is an uppercase character:
728    /// 0x41 'A' ..= 0x5A 'Z'.
729    ///
730    /// # Examples
731    ///
732    /// ```
733    /// #![feature(ascii_char, ascii_char_variants)]
734    /// use std::ascii;
735    ///
736    /// let uppercase_a = ascii::Char::CapitalA;
737    /// let uppercase_g = ascii::Char::CapitalG;
738    /// let a = ascii::Char::SmallA;
739    /// let g = ascii::Char::SmallG;
740    /// let zero = ascii::Char::Digit0;
741    /// let percent = ascii::Char::PercentSign;
742    /// let space = ascii::Char::Space;
743    /// let lf = ascii::Char::LineFeed;
744    /// let esc = ascii::Char::Escape;
745    ///
746    /// assert!(uppercase_a.is_uppercase());
747    /// assert!(uppercase_g.is_uppercase());
748    /// assert!(!a.is_uppercase());
749    /// assert!(!g.is_uppercase());
750    /// assert!(!zero.is_uppercase());
751    /// assert!(!percent.is_uppercase());
752    /// assert!(!space.is_uppercase());
753    /// assert!(!lf.is_uppercase());
754    /// assert!(!esc.is_uppercase());
755    /// ```
756    #[must_use]
757    #[unstable(feature = "ascii_char", issue = "110998")]
758    #[inline]
759    pub const fn is_uppercase(self) -> bool {
760        self.to_u8().is_ascii_uppercase()
761    }
762
763    /// Checks if the value is a lowercase character:
764    /// 0x61 'a' ..= 0x7A 'z'.
765    ///
766    /// # Examples
767    ///
768    /// ```
769    /// #![feature(ascii_char, ascii_char_variants)]
770    /// use std::ascii;
771    ///
772    /// let uppercase_a = ascii::Char::CapitalA;
773    /// let uppercase_g = ascii::Char::CapitalG;
774    /// let a = ascii::Char::SmallA;
775    /// let g = ascii::Char::SmallG;
776    /// let zero = ascii::Char::Digit0;
777    /// let percent = ascii::Char::PercentSign;
778    /// let space = ascii::Char::Space;
779    /// let lf = ascii::Char::LineFeed;
780    /// let esc = ascii::Char::Escape;
781    ///
782    /// assert!(!uppercase_a.is_lowercase());
783    /// assert!(!uppercase_g.is_lowercase());
784    /// assert!(a.is_lowercase());
785    /// assert!(g.is_lowercase());
786    /// assert!(!zero.is_lowercase());
787    /// assert!(!percent.is_lowercase());
788    /// assert!(!space.is_lowercase());
789    /// assert!(!lf.is_lowercase());
790    /// assert!(!esc.is_lowercase());
791    /// ```
792    #[must_use]
793    #[unstable(feature = "ascii_char", issue = "110998")]
794    #[inline]
795    pub const fn is_lowercase(self) -> bool {
796        self.to_u8().is_ascii_lowercase()
797    }
798
799    /// Checks if the value is an alphanumeric character:
800    ///
801    /// - 0x41 'A' ..= 0x5A 'Z', or
802    /// - 0x61 'a' ..= 0x7A 'z', or
803    /// - 0x30 '0' ..= 0x39 '9'.
804    ///
805    /// # Examples
806    ///
807    /// ```
808    /// #![feature(ascii_char, ascii_char_variants)]
809    /// use std::ascii;
810    ///
811    /// let uppercase_a = ascii::Char::CapitalA;
812    /// let uppercase_g = ascii::Char::CapitalG;
813    /// let a = ascii::Char::SmallA;
814    /// let g = ascii::Char::SmallG;
815    /// let zero = ascii::Char::Digit0;
816    /// let percent = ascii::Char::PercentSign;
817    /// let space = ascii::Char::Space;
818    /// let lf = ascii::Char::LineFeed;
819    /// let esc = ascii::Char::Escape;
820    ///
821    /// assert!(uppercase_a.is_alphanumeric());
822    /// assert!(uppercase_g.is_alphanumeric());
823    /// assert!(a.is_alphanumeric());
824    /// assert!(g.is_alphanumeric());
825    /// assert!(zero.is_alphanumeric());
826    /// assert!(!percent.is_alphanumeric());
827    /// assert!(!space.is_alphanumeric());
828    /// assert!(!lf.is_alphanumeric());
829    /// assert!(!esc.is_alphanumeric());
830    /// ```
831    #[must_use]
832    #[unstable(feature = "ascii_char", issue = "110998")]
833    #[inline]
834    pub const fn is_alphanumeric(self) -> bool {
835        self.to_u8().is_ascii_alphanumeric()
836    }
837
838    /// Checks if the value is a decimal digit:
839    /// 0x30 '0' ..= 0x39 '9'.
840    ///
841    /// # Examples
842    ///
843    /// ```
844    /// #![feature(ascii_char, ascii_char_variants)]
845    /// use std::ascii;
846    ///
847    /// let uppercase_a = ascii::Char::CapitalA;
848    /// let uppercase_g = ascii::Char::CapitalG;
849    /// let a = ascii::Char::SmallA;
850    /// let g = ascii::Char::SmallG;
851    /// let zero = ascii::Char::Digit0;
852    /// let percent = ascii::Char::PercentSign;
853    /// let space = ascii::Char::Space;
854    /// let lf = ascii::Char::LineFeed;
855    /// let esc = ascii::Char::Escape;
856    ///
857    /// assert!(!uppercase_a.is_digit());
858    /// assert!(!uppercase_g.is_digit());
859    /// assert!(!a.is_digit());
860    /// assert!(!g.is_digit());
861    /// assert!(zero.is_digit());
862    /// assert!(!percent.is_digit());
863    /// assert!(!space.is_digit());
864    /// assert!(!lf.is_digit());
865    /// assert!(!esc.is_digit());
866    /// ```
867    #[must_use]
868    #[unstable(feature = "ascii_char", issue = "110998")]
869    #[inline]
870    pub const fn is_digit(self) -> bool {
871        self.to_u8().is_ascii_digit()
872    }
873
874    /// Checks if the value is an octal digit:
875    /// 0x30 '0' ..= 0x37 '7'.
876    ///
877    /// # Examples
878    ///
879    /// ```
880    /// #![feature(ascii_char, ascii_char_variants, is_ascii_octdigit)]
881    ///
882    /// use std::ascii;
883    ///
884    /// let uppercase_a = ascii::Char::CapitalA;
885    /// let a = ascii::Char::SmallA;
886    /// let zero = ascii::Char::Digit0;
887    /// let seven = ascii::Char::Digit7;
888    /// let eight = ascii::Char::Digit8;
889    /// let percent = ascii::Char::PercentSign;
890    /// let lf = ascii::Char::LineFeed;
891    /// let esc = ascii::Char::Escape;
892    ///
893    /// assert!(!uppercase_a.is_octdigit());
894    /// assert!(!a.is_octdigit());
895    /// assert!(zero.is_octdigit());
896    /// assert!(seven.is_octdigit());
897    /// assert!(!eight.is_octdigit());
898    /// assert!(!percent.is_octdigit());
899    /// assert!(!lf.is_octdigit());
900    /// assert!(!esc.is_octdigit());
901    /// ```
902    #[must_use]
903    // This is blocked on two unstable features. Please ensure both are
904    // stabilized before marking this method as stable.
905    #[unstable(feature = "ascii_char", issue = "110998")]
906    // #[unstable(feature = "is_ascii_octdigit", issue = "101288")]
907    #[inline]
908    pub const fn is_octdigit(self) -> bool {
909        self.to_u8().is_ascii_octdigit()
910    }
911
912    /// Checks if the value is a hexadecimal digit:
913    ///
914    /// - 0x30 '0' ..= 0x39 '9', or
915    /// - 0x41 'A' ..= 0x46 'F', or
916    /// - 0x61 'a' ..= 0x66 'f'.
917    ///
918    /// # Examples
919    ///
920    /// ```
921    /// #![feature(ascii_char, ascii_char_variants)]
922    /// use std::ascii;
923    ///
924    /// let uppercase_a = ascii::Char::CapitalA;
925    /// let uppercase_g = ascii::Char::CapitalG;
926    /// let a = ascii::Char::SmallA;
927    /// let g = ascii::Char::SmallG;
928    /// let zero = ascii::Char::Digit0;
929    /// let percent = ascii::Char::PercentSign;
930    /// let space = ascii::Char::Space;
931    /// let lf = ascii::Char::LineFeed;
932    /// let esc = ascii::Char::Escape;
933    ///
934    /// assert!(uppercase_a.is_hexdigit());
935    /// assert!(!uppercase_g.is_hexdigit());
936    /// assert!(a.is_hexdigit());
937    /// assert!(!g.is_hexdigit());
938    /// assert!(zero.is_hexdigit());
939    /// assert!(!percent.is_hexdigit());
940    /// assert!(!space.is_hexdigit());
941    /// assert!(!lf.is_hexdigit());
942    /// assert!(!esc.is_hexdigit());
943    /// ```
944    #[must_use]
945    #[unstable(feature = "ascii_char", issue = "110998")]
946    #[inline]
947    pub const fn is_hexdigit(self) -> bool {
948        self.to_u8().is_ascii_hexdigit()
949    }
950
951    /// Checks if the value is a punctuation character:
952    ///
953    /// - 0x21 ..= 0x2F `! " # $ % & ' ( ) * + , - . /`, or
954    /// - 0x3A ..= 0x40 `: ; < = > ? @`, or
955    /// - 0x5B ..= 0x60 `` [ \ ] ^ _ ` ``, or
956    /// - 0x7B ..= 0x7E `{ | } ~`
957    ///
958    /// # Examples
959    ///
960    /// ```
961    /// #![feature(ascii_char, ascii_char_variants)]
962    /// use std::ascii;
963    ///
964    /// let uppercase_a = ascii::Char::CapitalA;
965    /// let uppercase_g = ascii::Char::CapitalG;
966    /// let a = ascii::Char::SmallA;
967    /// let g = ascii::Char::SmallG;
968    /// let zero = ascii::Char::Digit0;
969    /// let percent = ascii::Char::PercentSign;
970    /// let space = ascii::Char::Space;
971    /// let lf = ascii::Char::LineFeed;
972    /// let esc = ascii::Char::Escape;
973    ///
974    /// assert!(!uppercase_a.is_punctuation());
975    /// assert!(!uppercase_g.is_punctuation());
976    /// assert!(!a.is_punctuation());
977    /// assert!(!g.is_punctuation());
978    /// assert!(!zero.is_punctuation());
979    /// assert!(percent.is_punctuation());
980    /// assert!(!space.is_punctuation());
981    /// assert!(!lf.is_punctuation());
982    /// assert!(!esc.is_punctuation());
983    /// ```
984    #[must_use]
985    #[unstable(feature = "ascii_char", issue = "110998")]
986    #[inline]
987    pub const fn is_punctuation(self) -> bool {
988        self.to_u8().is_ascii_punctuation()
989    }
990
991    /// Checks if the value is a graphic character:
992    /// 0x21 '!' ..= 0x7E '~'.
993    ///
994    /// # Examples
995    ///
996    /// ```
997    /// #![feature(ascii_char, ascii_char_variants)]
998    /// use std::ascii;
999    ///
1000    /// let uppercase_a = ascii::Char::CapitalA;
1001    /// let uppercase_g = ascii::Char::CapitalG;
1002    /// let a = ascii::Char::SmallA;
1003    /// let g = ascii::Char::SmallG;
1004    /// let zero = ascii::Char::Digit0;
1005    /// let percent = ascii::Char::PercentSign;
1006    /// let space = ascii::Char::Space;
1007    /// let lf = ascii::Char::LineFeed;
1008    /// let esc = ascii::Char::Escape;
1009    ///
1010    /// assert!(uppercase_a.is_graphic());
1011    /// assert!(uppercase_g.is_graphic());
1012    /// assert!(a.is_graphic());
1013    /// assert!(g.is_graphic());
1014    /// assert!(zero.is_graphic());
1015    /// assert!(percent.is_graphic());
1016    /// assert!(!space.is_graphic());
1017    /// assert!(!lf.is_graphic());
1018    /// assert!(!esc.is_graphic());
1019    /// ```
1020    #[must_use]
1021    #[unstable(feature = "ascii_char", issue = "110998")]
1022    #[inline]
1023    pub const fn is_graphic(self) -> bool {
1024        self.to_u8().is_ascii_graphic()
1025    }
1026
1027    /// Checks if the value is a whitespace character:
1028    /// 0x20 SPACE, 0x09 HORIZONTAL TAB, 0x0A LINE FEED,
1029    /// 0x0C FORM FEED, or 0x0D CARRIAGE RETURN.
1030    ///
1031    /// Rust uses the WhatWG Infra Standard's [definition of ASCII
1032    /// whitespace][infra-aw]. There are several other definitions in
1033    /// wide use. For instance, [the POSIX locale][pct] includes
1034    /// 0x0B VERTICAL TAB as well as all the above characters,
1035    /// but—from the very same specification—[the default rule for
1036    /// "field splitting" in the Bourne shell][bfs] considers *only*
1037    /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
1038    ///
1039    /// If you are writing a program that will process an existing
1040    /// file format, check what that format's definition of whitespace is
1041    /// before using this function.
1042    ///
1043    /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
1044    /// [pct]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
1045    /// [bfs]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
1046    ///
1047    /// # Examples
1048    ///
1049    /// ```
1050    /// #![feature(ascii_char, ascii_char_variants)]
1051    /// use std::ascii;
1052    ///
1053    /// let uppercase_a = ascii::Char::CapitalA;
1054    /// let uppercase_g = ascii::Char::CapitalG;
1055    /// let a = ascii::Char::SmallA;
1056    /// let g = ascii::Char::SmallG;
1057    /// let zero = ascii::Char::Digit0;
1058    /// let percent = ascii::Char::PercentSign;
1059    /// let space = ascii::Char::Space;
1060    /// let lf = ascii::Char::LineFeed;
1061    /// let esc = ascii::Char::Escape;
1062    ///
1063    /// assert!(!uppercase_a.is_whitespace());
1064    /// assert!(!uppercase_g.is_whitespace());
1065    /// assert!(!a.is_whitespace());
1066    /// assert!(!g.is_whitespace());
1067    /// assert!(!zero.is_whitespace());
1068    /// assert!(!percent.is_whitespace());
1069    /// assert!(space.is_whitespace());
1070    /// assert!(lf.is_whitespace());
1071    /// assert!(!esc.is_whitespace());
1072    /// ```
1073    #[must_use]
1074    #[unstable(feature = "ascii_char", issue = "110998")]
1075    #[inline]
1076    pub const fn is_whitespace(self) -> bool {
1077        self.to_u8().is_ascii_whitespace()
1078    }
1079
1080    /// Checks if the value is a control character:
1081    /// 0x00 NUL ..= 0x1F UNIT SEPARATOR, or 0x7F DELETE.
1082    /// Note that most whitespace characters are control
1083    /// characters, but SPACE is not.
1084    ///
1085    /// # Examples
1086    ///
1087    /// ```
1088    /// #![feature(ascii_char, ascii_char_variants)]
1089    /// use std::ascii;
1090    ///
1091    /// let uppercase_a = ascii::Char::CapitalA;
1092    /// let uppercase_g = ascii::Char::CapitalG;
1093    /// let a = ascii::Char::SmallA;
1094    /// let g = ascii::Char::SmallG;
1095    /// let zero = ascii::Char::Digit0;
1096    /// let percent = ascii::Char::PercentSign;
1097    /// let space = ascii::Char::Space;
1098    /// let lf = ascii::Char::LineFeed;
1099    /// let esc = ascii::Char::Escape;
1100    ///
1101    /// assert!(!uppercase_a.is_control());
1102    /// assert!(!uppercase_g.is_control());
1103    /// assert!(!a.is_control());
1104    /// assert!(!g.is_control());
1105    /// assert!(!zero.is_control());
1106    /// assert!(!percent.is_control());
1107    /// assert!(!space.is_control());
1108    /// assert!(lf.is_control());
1109    /// assert!(esc.is_control());
1110    /// ```
1111    #[must_use]
1112    #[unstable(feature = "ascii_char", issue = "110998")]
1113    #[inline]
1114    pub const fn is_control(self) -> bool {
1115        self.to_u8().is_ascii_control()
1116    }
1117
1118    /// Returns an iterator that produces an escaped version of a
1119    /// character.
1120    ///
1121    /// The behavior is identical to
1122    /// [`ascii::escape_default`](crate::ascii::escape_default).
1123    ///
1124    /// # Examples
1125    ///
1126    /// ```
1127    /// #![feature(ascii_char, ascii_char_variants)]
1128    /// use std::ascii;
1129    ///
1130    /// let zero = ascii::Char::Digit0;
1131    /// let tab = ascii::Char::CharacterTabulation;
1132    /// let cr = ascii::Char::CarriageReturn;
1133    /// let lf = ascii::Char::LineFeed;
1134    /// let apostrophe = ascii::Char::Apostrophe;
1135    /// let double_quote = ascii::Char::QuotationMark;
1136    /// let backslash = ascii::Char::ReverseSolidus;
1137    ///
1138    /// assert_eq!("0", zero.escape_ascii().to_string());
1139    /// assert_eq!("\\t", tab.escape_ascii().to_string());
1140    /// assert_eq!("\\r", cr.escape_ascii().to_string());
1141    /// assert_eq!("\\n", lf.escape_ascii().to_string());
1142    /// assert_eq!("\\'", apostrophe.escape_ascii().to_string());
1143    /// assert_eq!("\\\"", double_quote.escape_ascii().to_string());
1144    /// assert_eq!("\\\\", backslash.escape_ascii().to_string());
1145    /// ```
1146    #[must_use = "this returns the escaped character as an iterator, \
1147                  without modifying the original"]
1148    #[unstable(feature = "ascii_char", issue = "110998")]
1149    #[inline]
1150    pub fn escape_ascii(self) -> super::EscapeDefault {
1151        super::escape_default(self.to_u8())
1152    }
1153}
1154
1155macro_rules! into_int_impl {
1156    ($($ty:ty)*) => {
1157        $(
1158            #[unstable(feature = "ascii_char", issue = "110998")]
1159            #[rustc_const_unstable(feature = "const_try", issue = "74935")]
1160            impl const From<AsciiChar> for $ty {
1161                #[inline]
1162                fn from(chr: AsciiChar) -> $ty {
1163                    chr as u8 as $ty
1164                }
1165            }
1166        )*
1167    }
1168}
1169
1170into_int_impl!(u8 u16 u32 u64 u128 char);
1171
1172impl [AsciiChar] {
1173    /// Views this slice of ASCII characters as a UTF-8 `str`.
1174    #[unstable(feature = "ascii_char", issue = "110998")]
1175    #[inline]
1176    pub const fn as_str(&self) -> &str {
1177        let ascii_ptr: *const Self = self;
1178        let str_ptr = ascii_ptr as *const str;
1179        // SAFETY: Each ASCII codepoint in UTF-8 is encoded as one single-byte
1180        // code unit having the same value as the ASCII byte.
1181        unsafe { &*str_ptr }
1182    }
1183
1184    /// Views this slice of ASCII characters as a slice of `u8` bytes.
1185    #[unstable(feature = "ascii_char", issue = "110998")]
1186    #[inline]
1187    pub const fn as_bytes(&self) -> &[u8] {
1188        self.as_str().as_bytes()
1189    }
1190}
1191
1192#[unstable(feature = "ascii_char", issue = "110998")]
1193impl fmt::Display for AsciiChar {
1194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1195        <str as fmt::Display>::fmt(self.as_str(), f)
1196    }
1197}
1198
1199#[unstable(feature = "ascii_char", issue = "110998")]
1200impl fmt::Debug for AsciiChar {
1201    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1202        use AsciiChar::{Apostrophe, Null, ReverseSolidus as Backslash};
1203
1204        fn backslash(a: AsciiChar) -> ([AsciiChar; 6], usize) {
1205            ([Apostrophe, Backslash, a, Apostrophe, Null, Null], 4)
1206        }
1207
1208        let (buf, len) = match self {
1209            AsciiChar::Null => backslash(AsciiChar::Digit0),
1210            AsciiChar::CharacterTabulation => backslash(AsciiChar::SmallT),
1211            AsciiChar::CarriageReturn => backslash(AsciiChar::SmallR),
1212            AsciiChar::LineFeed => backslash(AsciiChar::SmallN),
1213            AsciiChar::ReverseSolidus => backslash(AsciiChar::ReverseSolidus),
1214            AsciiChar::Apostrophe => backslash(AsciiChar::Apostrophe),
1215            _ if self.to_u8().is_ascii_control() => {
1216                const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap();
1217
1218                let byte = self.to_u8();
1219                let hi = HEX_DIGITS[usize::from(byte >> 4)];
1220                let lo = HEX_DIGITS[usize::from(byte & 0xf)];
1221                ([Apostrophe, Backslash, AsciiChar::SmallX, hi, lo, Apostrophe], 6)
1222            }
1223            _ => ([Apostrophe, *self, Apostrophe, Null, Null, Null], 3),
1224        };
1225
1226        f.write_str(buf[..len].as_str())
1227    }
1228}