-
Notifications
You must be signed in to change notification settings - Fork 13.3k
core: add core::ascii::Char::from_digit #118963
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
//! suggestions from rustc if you get anything slightly wrong in here, and overall | ||
//! helps with clarity as we're also referring to `char` intentionally in here. | ||
|
||
use crate::fmt::{self, Write}; | ||
use crate::fmt; | ||
use crate::mem::transmute; | ||
|
||
/// One of the 128 Unicode characters from U+0000 through U+007F, | ||
|
@@ -474,7 +474,8 @@ impl AsciiChar { | |
/// When passed the *number* `0`, `1`, …, `9`, returns the *character* | ||
/// `'0'`, `'1'`, …, `'9'` respectively. | ||
/// | ||
/// If `d >= 10`, returns `None`. | ||
/// If `d >= 10`, returns `None`. To get a digit up to `d == 35`, use | ||
/// [`from_digit`](Self::from_digit) instead. | ||
#[unstable(feature = "ascii_char", issue = "110998")] | ||
#[inline] | ||
pub const fn digit(d: u8) -> Option<Self> { | ||
|
@@ -515,6 +516,37 @@ impl AsciiChar { | |
} | ||
} | ||
|
||
/// Returns a *character* digit corresponding to given numeric value of | ||
/// a digit. | ||
/// | ||
/// When passed the *number* `0`, `1`, …, `8`, `9`, `10`, …, `34`, `35`, | ||
/// returns the *character* `'0'`, `'1'`, …, `'8'`, `'9'`, `'a'`, …, `'y'`, | ||
/// `'z'` respectively. | ||
/// | ||
/// If `d >= 36`, returns `None`. To get a digit only for `d < 10`, use | ||
/// [`digit`](Self::digit) instead. | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// #![feature(ascii_char, ascii_char_variants)] | ||
/// use core::ascii::Char; | ||
/// | ||
/// assert_eq!(Some(Char::Digit0), Char::from_digit(0)); | ||
/// assert_eq!(Some(Char::Digit9), Char::from_digit(9)); | ||
/// assert_eq!(Some(Char::SmallA), Char::from_digit(10)); | ||
/// assert_eq!(Some(Char::SmallF), Char::from_digit(15)); | ||
/// assert_eq!(Some(Char::SmallZ), Char::from_digit(35)); | ||
/// assert_eq!(None, Char::from_digit(36)); | ||
/// ``` | ||
#[unstable(feature = "ascii_char", issue = "110998")] | ||
#[inline] | ||
pub const fn from_digit(d: u32) -> Option<Self> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this was motivated by char::from_digit. I really don’t know what makes more sense here. |
||
const DIGITS: [AsciiChar; 36] = | ||
*b"0123456789abcdefghijklmnopqrstuvwxyz".as_ascii().unwrap(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One thing I don't know how to solve here is that people might also want upper-case. Or base-64 style where Oh, I guess |
||
if d < 36 { Some(DIGITS[d as usize]) } else { None } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this more efficient than simply There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it. |
||
} | ||
|
||
/// Gets this ASCII character as a byte. | ||
#[unstable(feature = "ascii_char", issue = "110998")] | ||
#[inline] | ||
|
@@ -567,12 +599,14 @@ impl fmt::Display for AsciiChar { | |
#[unstable(feature = "ascii_char", issue = "110998")] | ||
impl fmt::Debug for AsciiChar { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
use AsciiChar::*; | ||
|
||
#[inline] | ||
fn backslash(a: AsciiChar) -> ([AsciiChar; 4], u8) { | ||
([AsciiChar::ReverseSolidus, a, AsciiChar::Null, AsciiChar::Null], 2) | ||
fn backslash(ch: AsciiChar) -> ([AsciiChar; 6], usize) { | ||
([Apostrophe, ReverseSolidus, ch, Apostrophe, Null, Null], 4) | ||
} | ||
|
||
let (buf, len) = match self { | ||
let (buf, len) = match *self { | ||
AsciiChar::Null => backslash(AsciiChar::Digit0), | ||
AsciiChar::CharacterTabulation => backslash(AsciiChar::SmallT), | ||
AsciiChar::CarriageReturn => backslash(AsciiChar::SmallR), | ||
|
@@ -582,21 +616,15 @@ impl fmt::Debug for AsciiChar { | |
_ => { | ||
let byte = self.to_u8(); | ||
if !byte.is_ascii_control() { | ||
([*self, AsciiChar::Null, AsciiChar::Null, AsciiChar::Null], 1) | ||
([Apostrophe, *self, Apostrophe, Null, Null, Null], 3) | ||
} else { | ||
const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap(); | ||
|
||
let hi = HEX_DIGITS[usize::from(byte >> 4)]; | ||
let lo = HEX_DIGITS[usize::from(byte & 0xf)]; | ||
([AsciiChar::ReverseSolidus, AsciiChar::SmallX, hi, lo], 4) | ||
let hi = Self::from_digit(u32::from(byte >> 4)).unwrap(); | ||
let lo = Self::from_digit(u32::from(byte & 0xf)).unwrap(); | ||
([Apostrophe, ReverseSolidus, SmallX, hi, lo, Apostrophe], 6) | ||
} | ||
} | ||
}; | ||
|
||
f.write_char('\'')?; | ||
for byte in &buf[..len as usize] { | ||
f.write_str(byte.as_str())?; | ||
} | ||
f.write_char('\'') | ||
f.write_str(buf[..len].as_str()) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, that only reason I added this method was to use it for things like
'0' + d
inrust/library/core/src/fmt/num.rs
Lines 149 to 150 in 604f185
But then it looks like it's not actually used. So it's possible that maybe it shouldn't have existed at all; I don't know.
(The idea was to give something to point to when people say "but
'0' + d
was so nice". But for hex there was never that shorthand, so having people use"…".as_ascii().unwrap()[d]
might be fine for those non-decimal uses.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem at the moment is unwrap not being const, so one has to
write some annoying code:
It’s not the end of the world of course, but it’s certainly less
convenient that a AsciiChar::from_digit call.
Though I can see reasons to wait for const unwrap or
a"..."
syntax(proposed in the tracking issue) before considering adding this
function.
By the way, maybe for
b'0' + d
the solution is to implementAdd
?In debug builds it would panic on overflow while on release it would
wrap (i.e. mask out most significant bit).