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