use super::*;
use crate::{Cmp, StringU8, TextLut, is};
impl Digits<u8> {
pub const MAX_DIGITS_10: u8 = 3;
pub const MAX_DIGITS_16: u8 = 2;
#[doc = DOC_COUNT_DIGITS_10!()]
#[must_use]
pub const fn count_digits10(self) -> u8 {
is![self.0 == 0, 1, self.0.ilog10() as u8 + 1]
}
#[doc = DOC_COUNT_DIGITS_16!()]
#[must_use]
pub const fn count_digits16(self) -> u8 {
match self.0 {
0 => 1,
0x1..=0xF => 1,
_ => 2,
}
}
#[must_use]
#[inline(always)]
pub const fn digit_at_index10(self, index: u8) -> u8 {
is![index >= self.count_digits10(), return b'0'];
const POWERS: [u8; 3] = [100, 10, 1];
self.digit_at_power10(POWERS[index as usize])
}
#[must_use]
pub const fn digit_at_index10_checked(self, index: u8) -> Option<u8> {
is![index >= self.count_digits10(), return None];
let power = TextLut::POWERS10[index as usize] as u8;
Some((self.0 / power % 10) + b'0')
}
#[must_use]
pub const fn digit_at_index16(self, index: u8) -> u8 {
let shift = index as u32 * 4;
let digit = (self.0.unbounded_shr(shift) & 0xF) as usize;
TextLut::DIGITS_BASE36[digit]
}
#[must_use]
pub const fn digit_at_index16_checked(self, index: u8) -> Option<u8> {
is![index >= self.count_digits16(), return None];
let shift = index as u32 * 4;
let digit = (self.0.unbounded_shr(shift) & 0xF) as usize;
Some(TextLut::DIGITS_BASE36[digit])
}
#[must_use]
pub const fn digit_value_at_index10(self, index: u8) -> u8 {
is![index >= self.count_digits10(), return 0];
let power = TextLut::POWERS10[index as usize] as u8;
self.0 / power % 10
}
#[must_use]
pub const fn digit_value_at_index10_checked(self, index: u8) -> Option<u8> {
is![index >= self.count_digits10(), return None];
let power = TextLut::POWERS10[index as usize] as u8;
Some(self.0 / power % 10)
}
#[must_use]
#[inline(always)]
pub const fn digit_value_at_index16(self, index: u8) -> u8 {
let shift = index as u32 * 4;
self.0.unbounded_shr(shift) & 0xF
}
#[must_use]
pub const fn digit_value_at_index16_checked(self, index: u8) -> Option<u8> {
is![index < self.count_digits16(), Some(self.digit_value_at_index16(index)), None]
}
#[doc = DOC_DIGIT_AT_POWER_10!()]
#[must_use]
#[inline(always)]
pub(crate) const fn digit_at_power10(self, divisor: u8) -> u8 {
(self.0 / divisor % 10) + b'0'
}
#[doc = DOC_DIGIT_AT_POWER_16!()]
#[must_use]
#[inline(always)]
pub(crate) const fn digit_at_power16(self, divisor: u8) -> u8 {
let digit = match divisor {
0x1 => self.0 & 0xF,
0x10 => (self.0 >> 4) & 0xF,
_ => (self.0 / divisor) % 16,
};
TextLut::DIGITS_BASE36[digit as usize]
}
#[must_use]
pub const fn digits10(self) -> [u8; Self::MAX_DIGITS_10 as usize] {
[
self.digit_at_power10(100), self.digit_at_power10(10),
self.digit_at_power10(1),
]
}
#[must_use]
pub const fn digits16(self) -> [u8; Self::MAX_DIGITS_16 as usize] {
[
self.digit_at_power16(0x10), self.digit_at_power16(0x1),
]
}
#[inline(always)]
const fn write_digits10_inner(self, buf: &mut [u8], offset: usize) -> usize {
let n = self.0;
if n < 10 {
buf[offset] = n + b'0';
1
} else if n < 100 {
buf[offset] = n / 10 + b'0';
buf[offset + 1] = n % 10 + b'0';
2
} else {
buf[offset] = n / 100 + b'0';
buf[offset + 1] = (n / 10) % 10 + b'0';
buf[offset + 2] = n % 10 + b'0';
3
}
}
pub const fn write_digits10(self, buf: &mut [u8], offset: usize) -> usize {
is![offset + 3 > buf.len(), return 0];
self.write_digits10_inner(buf, offset)
}
pub const fn write_digits10_omit0(self, buf: &mut [u8], offset: usize) -> usize {
is![self.0 == 0, return 0];
is![offset + 3 > buf.len(), return 0];
self.write_digits10_inner(buf, offset)
}
pub const fn write_digits16(self, buf: &mut [u8], offset: usize) -> usize {
let n = self.0;
is![offset + 2 > buf.len(), return 0];
if n < 0x10 {
buf[offset] = TextLut::DIGITS_BASE36[n as usize];
1
} else {
buf[offset] = TextLut::DIGITS_BASE36[(n >> 4) as usize];
buf[offset + 1] = TextLut::DIGITS_BASE36[(n & 0x0F) as usize];
2
}
}
pub const fn write_digits16_omit0(self, buf: &mut [u8], offset: usize) -> usize {
let n = self.0;
is![n == 0, return 0];
is![offset + 2 > buf.len(), return 0];
if n < 0x10 {
buf[offset] = TextLut::DIGITS_BASE36[n as usize];
1
} else {
buf[offset] = TextLut::DIGITS_BASE36[(n >> 4) as usize];
buf[offset + 1] = TextLut::DIGITS_BASE36[(n & 0x0F) as usize];
2
}
}
#[doc = DOC_DIGITS_STR!()] #[rustfmt::skip]
pub const fn digits10_str(self, width: u8) -> StringU8<{Self::MAX_DIGITS_10 as usize}> {
let width = Cmp(width).clamp(self.count_digits10(), Self::MAX_DIGITS_10);
#[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
return crate::unwrap![ok StringU8::<{Self::MAX_DIGITS_10 as usize}>
::from_array_nright(self.digits10(), width)];
#[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
unsafe { StringU8::<{Self::MAX_DIGITS_10 as usize}>
::from_array_nright_unchecked(self.digits10(), width) }
}
#[doc = DOC_DIGITS_STR!()] #[rustfmt::skip]
pub const fn digits16_str(self, width: u8) -> StringU8<{Self::MAX_DIGITS_16 as usize}> {
let width = Cmp(width).clamp(self.count_digits16(), Self::MAX_DIGITS_16);
#[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
return crate::unwrap![ok StringU8::<{Self::MAX_DIGITS_16 as usize}>
::from_array_nright(self.digits16(), width)];
#[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
unsafe { StringU8::<{Self::MAX_DIGITS_16 as usize}>
::from_array_nright_unchecked(self.digits16(), width) }
}
#[must_use]
pub const fn digits10_1(self) -> u8 {
debug_assert![self.0 <= 9];
self.0 + b'0'
}
#[must_use]
pub const fn digits10_2(self) -> [u8; 2] {
debug_assert![self.0 <= 99];
[self.digit_at_power10(10), self.digit_at_power10(1)]
}
pub const fn digits16_1(self) -> u8 {
debug_assert![self.0 <= 0xF];
TextLut::DIGITS_BASE36[self.0 as usize]
}
}
#[cfg(test)]
mod tests {
use super::Digits;
#[test]
fn test_write_digits10() {
let mut buf = [0u8; 10];
assert_eq!(Digits(123_u8).write_digits10(&mut buf, 0), 3);
assert_eq!(Digits(45_u8).write_digits10(&mut buf, 3), 2);
assert_eq!(Digits(0_u8).write_digits10(&mut buf, 5), 1); assert_eq!(Digits(6_u8).write_digits10(&mut buf, 6), 1);
assert_eq!(&buf[0..7], b"1234506");
assert_eq!(Digits(100_u8).write_digits10(&mut buf[0..2], 0), 0); }
#[test]
fn test_write_digits10_omit0() {
let mut buf = [0u8; 10];
assert_eq!(Digits(123_u8).write_digits10_omit0(&mut buf, 0), 3);
assert_eq!(Digits(45_u8).write_digits10_omit0(&mut buf, 3), 2);
assert_eq!(Digits(0_u8).write_digits10_omit0(&mut buf, 3), 0); assert_eq!(Digits(6_u8).write_digits10_omit0(&mut buf, 5), 1);
assert_eq!(&buf[0..6], b"123456");
assert_eq!(Digits(100_u8).write_digits10_omit0(&mut buf[0..2], 0), 0); }
#[test]
fn test_write_digits16() {
let mut buf = [0u8; 10];
assert_eq!(Digits(0xA_u8).write_digits16(&mut buf, 0), 1);
assert_eq!(Digits(0_u8).write_digits16(&mut buf, 1), 1); assert_eq!(Digits(0xBC_u8).write_digits16(&mut buf, 2), 2);
assert_eq!(&buf[0..4], b"A0BC");
assert_eq!(Digits(0x10_u8).write_digits16(&mut buf[0..1], 0), 0); }
#[test]
fn test_write_digits16_omit0() {
let mut buf = [0u8; 10];
assert_eq!(Digits(0x1_u8).write_digits16_omit0(&mut buf, 0), 1);
assert_eq!(Digits(0x0__u8).write_digits16_omit0(&mut buf, 1), 0); assert_eq!(Digits(0x23_u8).write_digits16_omit0(&mut buf, 1), 2);
assert_eq!(&buf[0..3], b"123");
assert_eq!(Digits(0x10_u8).write_digits16_omit0(&mut buf[0..1], 0), 0); }
}