use crate::U256;
use core::fmt;
pub(crate) const HEX_DIGITS: usize = 64;
#[cfg(feature = "fmt")]
pub(crate) const DEC_DIGITS: usize = 78;
pub(crate) const LOWER: [u8; 16] = *b"0123456789abcdef";
#[cfg(feature = "fmt")]
pub(crate) const UPPER: [u8; 16] = *b"0123456789ABCDEF";
pub(crate) fn hex_digits<'a>(
n: &U256,
buf: &'a mut [u8; HEX_DIGITS],
table: &[u8; 16],
) -> &'a str {
let mut pos = buf.len();
let mut v = *n;
if v.is_zero() {
pos -= 1;
buf[pos] = b'0';
} else {
while !v.is_zero() {
pos -= 1;
buf[pos] = table[(v.to_limbs()[0] & 0xf) as usize];
v = v.wrapping_shr(4);
}
}
core::str::from_utf8(&buf[pos..]).expect("hex digits are ASCII")
}
impl fmt::Debug for U256 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buf = [0u8; HEX_DIGITS];
f.write_str("0x")?;
f.write_str(hex_digits(self, &mut buf, &LOWER))
}
}
#[cfg(feature = "fmt")]
impl fmt::LowerHex for U256 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buf = [0u8; HEX_DIGITS];
let digits = hex_digits(self, &mut buf, &LOWER);
f.pad_integral(true, "0x", digits)
}
}
#[cfg(feature = "fmt")]
impl fmt::UpperHex for U256 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buf = [0u8; HEX_DIGITS];
let digits = hex_digits(self, &mut buf, &UPPER);
f.pad_integral(true, "0x", digits)
}
}
#[cfg(feature = "fmt")]
pub(crate) fn dec_digits<'a>(
n: &U256,
buf: &'a mut [u8; DEC_DIGITS],
) -> &'a str {
let mut pos = buf.len();
let mut v = *n;
if v.is_zero() {
pos -= 1;
buf[pos] = b'0';
}
while !v.is_zero() {
let (q, r) = v.div_rem_small(1_000_000_000);
v = q;
let mut r = r;
let count = if v.is_zero() {
let mut d = 0;
let mut t = r;
while t != 0 {
d += 1;
t /= 10;
}
d
} else {
9
};
let mut i = 0;
while i < count {
pos -= 1;
buf[pos] = b'0' + (r % 10) as u8;
r /= 10;
i += 1;
}
}
core::str::from_utf8(&buf[pos..]).expect("decimal digits are ASCII")
}
#[cfg(feature = "fmt")]
impl fmt::Display for U256 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buf = [0u8; DEC_DIGITS];
let digits = dec_digits(self, &mut buf);
f.pad_integral(true, "", digits)
}
}
#[cfg(feature = "fmt")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParseU256Error {
Empty,
InvalidDigit,
Overflow,
}
#[cfg(feature = "fmt")]
impl fmt::Display for ParseU256Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::Empty => "cannot parse an empty string as U256",
Self::InvalidDigit => "invalid decimal digit",
Self::Overflow => "value does not fit in 256 bits",
})
}
}
#[cfg(all(feature = "fmt", feature = "std"))]
impl std::error::Error for ParseU256Error {}
#[cfg(feature = "fmt")]
impl core::str::FromStr for U256 {
type Err = ParseU256Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(ParseU256Error::Empty);
}
let mut acc = U256::ZERO;
for byte in s.bytes() {
if !byte.is_ascii_digit() {
return Err(ParseU256Error::InvalidDigit);
}
let (scaled, overflow) = acc.overflowing_mul_u32(10);
if overflow {
return Err(ParseU256Error::Overflow);
}
let (next, overflow) =
scaled.overflowing_add(U256::from_u32((byte - b'0') as u32));
if overflow {
return Err(ParseU256Error::Overflow);
}
acc = next;
}
Ok(acc)
}
}