Skip to content

Commit da5251f

Browse files
committed
Add u8::to_digit and associated tests
1 parent 6df26f8 commit da5251f

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

library/core/src/num/mod.rs

+65
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,71 @@ impl u8 {
687687
pub fn escape_ascii(&self) -> ascii::EscapeDefault {
688688
ascii::escape_default(*self)
689689
}
690+
691+
/// Converts a value to a digit in the given radix.
692+
///
693+
/// A 'radix' here is sometimes also called a 'base'. A radix of two
694+
/// indicates a binary number, a radix of ten, decimal, and a radix of
695+
/// sixteen, hexadecimal, to give some common values. Arbitrary
696+
/// radices are supported.
697+
///
698+
/// 'Digit' is defined to be only the following ASCII characters:
699+
///
700+
/// * `0-9`
701+
/// * `a-z`
702+
/// * `A-Z`
703+
///
704+
/// # Errors
705+
///
706+
/// Returns `None` if the value does not refer to a digit in the given radix.
707+
///
708+
/// # Panics
709+
///
710+
/// Panics if given a radix larger than 36.
711+
///
712+
/// # Examples
713+
///
714+
/// Basic usage:
715+
///
716+
/// ```
717+
/// assert_eq!(b'1'.to_digit(10), Some(1));
718+
/// assert_eq!(b'f'.to_digit(16), Some(15));
719+
/// ```
720+
///
721+
/// Passing a non-digit results in failure:
722+
///
723+
/// ```
724+
/// assert_eq!(b'f'.to_digit(10), None);
725+
/// assert_eq!(b'z'.to_digit(16), None);
726+
/// ```
727+
///
728+
/// Passing a large radix, causing a panic:
729+
///
730+
/// ```should_panic
731+
/// // this panics
732+
/// b'1'.to_digit(37);
733+
/// ```
734+
#[unstable(feature = "ascii_to_digit", issue = "none")]
735+
#[inline]
736+
pub fn to_digit(&self, radix: u32) -> Option<u32> {
737+
assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
738+
// the code is split up here to improve execution speed for cases where
739+
// the `radix` is constant and 10 or smaller
740+
let val = if intrinsics::likely(radix <= 10) {
741+
// If not a digit, a number greater than radix will be created.
742+
self.wrapping_sub(b'0')
743+
} else {
744+
match self {
745+
b'0'..=b'9' => self - b'0',
746+
b'a'..=b'z' => self - b'a' + 10,
747+
b'A'..=b'Z' => self - b'A' + 10,
748+
_ => return None,
749+
}
750+
};
751+
let val: u32 = val.into();
752+
753+
if val < radix { Some(val) } else { None }
754+
}
690755
}
691756

692757
#[lang = "u16"]

library/core/tests/ascii.rs

+17
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,23 @@ fn test_is_ascii_control() {
344344
);
345345
}
346346

347+
#[cfg(not(bootstrap))]
348+
#[test]
349+
fn test_to_digit() {
350+
assert_eq!(b'0'.to_digit(10), Some(0));
351+
assert_eq!(b'1'.to_digit(2), Some(1));
352+
assert_eq!(b'2'.to_digit(3), Some(2));
353+
assert_eq!(b'9'.to_digit(10), Some(9));
354+
assert_eq!(b'a'.to_digit(16), Some(10));
355+
assert_eq!(b'A'.to_digit(16), Some(10));
356+
assert_eq!(b'b'.to_digit(16), Some(11));
357+
assert_eq!(b'B'.to_digit(16), Some(11));
358+
assert_eq!(b'z'.to_digit(36), Some(35));
359+
assert_eq!(b'Z'.to_digit(36), Some(35));
360+
assert_eq!(b' '.to_digit(10), None);
361+
assert_eq!(b'$'.to_digit(36), None);
362+
}
363+
347364
// `is_ascii` does a good amount of pointer manipulation and has
348365
// alignment-dependent computation. This is all sanity-checked via
349366
// `debug_assert!`s, so we test various sizes/alignments thoroughly versus an

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#![feature(array_methods)]
55
#![feature(array_map)]
66
#![feature(array_windows)]
7+
#![cfg_attr(not(bootstrap), feature(ascii_to_digit))]
78
#![feature(bool_to_option)]
89
#![feature(bound_cloned)]
910
#![feature(box_syntax)]

0 commit comments

Comments
 (0)