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