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