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