Skip to main content

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