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