|
5 | 5 |
|
6 | 6 | use crate::fmt::{self, Write};
|
7 | 7 | use crate::mem::transmute;
|
| 8 | +use crate::ops::{Add, AddAssign}; |
8 | 9 |
|
9 | 10 | /// One of the 128 Unicode characters from U+0000 through U+007F,
|
10 | 11 | /// often known as the [ASCII] subset.
|
@@ -471,50 +472,6 @@ impl AsciiChar {
|
471 | 472 | unsafe { transmute(b) }
|
472 | 473 | }
|
473 | 474 |
|
474 |
| - /// When passed the *number* `0`, `1`, …, `9`, returns the *character* |
475 |
| - /// `'0'`, `'1'`, …, `'9'` respectively. |
476 |
| - /// |
477 |
| - /// If `d >= 10`, returns `None`. |
478 |
| - #[unstable(feature = "ascii_char", issue = "110998")] |
479 |
| - #[inline] |
480 |
| - pub const fn digit(d: u8) -> Option<Self> { |
481 |
| - if d < 10 { |
482 |
| - // SAFETY: Just checked it's in-range. |
483 |
| - Some(unsafe { Self::digit_unchecked(d) }) |
484 |
| - } else { |
485 |
| - None |
486 |
| - } |
487 |
| - } |
488 |
| - |
489 |
| - /// When passed the *number* `0`, `1`, …, `9`, returns the *character* |
490 |
| - /// `'0'`, `'1'`, …, `'9'` respectively, without checking that it's in-range. |
491 |
| - /// |
492 |
| - /// # Safety |
493 |
| - /// |
494 |
| - /// This is immediate UB if called with `d > 64`. |
495 |
| - /// |
496 |
| - /// If `d >= 10` and `d <= 64`, this is allowed to return any value or panic. |
497 |
| - /// Notably, it should not be expected to return hex digits, or any other |
498 |
| - /// reasonable extension of the decimal digits. |
499 |
| - /// |
500 |
| - /// (This lose safety condition is intended to simplify soundness proofs |
501 |
| - /// when writing code using this method, since the implementation doesn't |
502 |
| - /// need something really specific, not to make those other arguments do |
503 |
| - /// something useful. It might be tightened before stabilization.) |
504 |
| - #[unstable(feature = "ascii_char", issue = "110998")] |
505 |
| - #[inline] |
506 |
| - pub const unsafe fn digit_unchecked(d: u8) -> Self { |
507 |
| - debug_assert!(d < 10); |
508 |
| - |
509 |
| - // SAFETY: `'0'` through `'9'` are U+00030 through U+0039, |
510 |
| - // so because `d` must be 64 or less the addition can return at most |
511 |
| - // 112 (0x70), which doesn't overflow and is within the ASCII range. |
512 |
| - unsafe { |
513 |
| - let byte = b'0'.unchecked_add(d); |
514 |
| - Self::from_u8_unchecked(byte) |
515 |
| - } |
516 |
| - } |
517 |
| - |
518 | 475 | /// Gets this ASCII character as a byte.
|
519 | 476 | #[unstable(feature = "ascii_char", issue = "110998")]
|
520 | 477 | #[inline]
|
@@ -557,6 +514,22 @@ impl [AsciiChar] {
|
557 | 514 | }
|
558 | 515 | }
|
559 | 516 |
|
| 517 | +#[unstable(feature = "ascii_char", issue = "110998")] |
| 518 | +impl From<AsciiChar> for u8 { |
| 519 | + #[inline] |
| 520 | + fn from(chr: AsciiChar) -> Self { |
| 521 | + chr as u8 |
| 522 | + } |
| 523 | +} |
| 524 | + |
| 525 | +#[unstable(feature = "ascii_char", issue = "110998")] |
| 526 | +impl From<AsciiChar> for char { |
| 527 | + #[inline] |
| 528 | + fn from(chr: AsciiChar) -> Self { |
| 529 | + chr as u8 as char |
| 530 | + } |
| 531 | +} |
| 532 | + |
560 | 533 | #[unstable(feature = "ascii_char", issue = "110998")]
|
561 | 534 | impl fmt::Display for AsciiChar {
|
562 | 535 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
@@ -600,3 +573,59 @@ impl fmt::Debug for AsciiChar {
|
600 | 573 | f.write_char('\'')
|
601 | 574 | }
|
602 | 575 | }
|
| 576 | + |
| 577 | +#[unstable(feature = "ascii_char", issue = "110998")] |
| 578 | +impl Add<u8> for AsciiChar { |
| 579 | + type Output = AsciiChar; |
| 580 | + |
| 581 | + /// Calculates sum of the ASCII value and given offset. |
| 582 | + /// |
| 583 | + /// In debug builds, panics if result is greater than largest ASCII value. |
| 584 | + /// |
| 585 | + /// In release builds wraps the value (i.e. masks out the most significant |
| 586 | + /// bit) so the output is a valid ASCII character. |
| 587 | + /// |
| 588 | + /// ``` |
| 589 | + /// #![feature(ascii_char, ascii_char_variants)] |
| 590 | + /// use core::ascii::Char; |
| 591 | + /// |
| 592 | + /// assert_eq!(Char::Digit8, Char::Digit0 + 8); |
| 593 | + /// ``` |
| 594 | + #[inline] |
| 595 | + fn add(self, rhs: u8) -> Self::Output { |
| 596 | + add_impl(self, rhs) |
| 597 | + } |
| 598 | +} |
| 599 | + |
| 600 | +#[unstable(feature = "ascii_char", issue = "110998")] |
| 601 | +impl Add<AsciiChar> for u8 { |
| 602 | + type Output = AsciiChar; |
| 603 | + |
| 604 | + #[inline] |
| 605 | + fn add(self, rhs: AsciiChar) -> Self::Output { |
| 606 | + add_impl(rhs, self) |
| 607 | + } |
| 608 | +} |
| 609 | + |
| 610 | +#[unstable(feature = "ascii_char", issue = "110998")] |
| 611 | +impl AddAssign<u8> for AsciiChar { |
| 612 | + #[inline] |
| 613 | + fn add_assign(&mut self, rhs: u8) { |
| 614 | + *self = add_impl(*self, rhs) |
| 615 | + } |
| 616 | +} |
| 617 | + |
| 618 | +forward_ref_binop! { impl Add, add for AsciiChar, u8 } |
| 619 | +forward_ref_binop! { impl Add, add for u8, AsciiChar } |
| 620 | +forward_ref_op_assign! { impl AddAssign, add_assign for AsciiChar, u8 } |
| 621 | + |
| 622 | +#[inline] |
| 623 | +fn add_impl(chr: AsciiChar, rhs: u8) -> AsciiChar { |
| 624 | + let sum = u16::from(u8::from(chr)) + u16::from(rhs); |
| 625 | + if !cfg!(debug_assertions) || sum < 128 { |
| 626 | + // SAFETY: `& 127` limits the sum to a valid ASCII value. |
| 627 | + unsafe { AsciiChar::from_u8_unchecked((sum as u8) & 127) } |
| 628 | + } else { |
| 629 | + panic!("{} + {} overflows ASCII value", u8::from(chr), rhs) |
| 630 | + } |
| 631 | +} |
0 commit comments