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