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