use {
core::{
fmt::{self, Display, Formatter},
ptr,
},
crate::{Error, Result},
};
mod impls;
mod number_writer;
mod tests;
macro_rules! to_le_bytes { ($n: ident) => { $n.to_le_bytes() }}
macro_rules! from_le_bytes { ($ty: ty, $bytes: expr) => { <$ty>::from_le_bytes($bytes) }}
#[cfg(feature="std")]
#[doc(cfg(feature="std"))]
pub (crate) use self::number_writer::*;
#[cfg(feature="std")]
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64"))]
pub (crate) const MAX_INT_DIGITS: usize = 40;
#[cfg(feature="std")]
#[cfg(not(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")))]
pub (crate) const MAX_INT_DIGITS: usize = core::mem::size_of::<usize>() * 3;
#[cfg(feature="std")]
#[test]
fn tests() {
use alloc::string::ToString;
assert!(MAX_INT_DIGITS >= u128::max_value().to_string().len());
assert!(MAX_INT_DIGITS >= i128::min_value().to_string().len());
assert!(MAX_INT_DIGITS >= usize::max_value().to_string().len());
assert!(MAX_INT_DIGITS >= isize::min_value().to_string().len());
}
const DATA_SIZE: usize = size_of::<u128>();
#[derive(Debug, Clone, Copy)]
pub struct Number {
kind: Kind,
data: [u8; DATA_SIZE],
}
impl Number {
fn as_u64(&self) -> u64 {
unsafe {
from_le_bytes!(u64, *ptr::from_ref(&self.data[..size_of::<u64>()]).cast())
}
}
fn as_i64(&self) -> i64 {
unsafe {
from_le_bytes!(i64, *ptr::from_ref(&self.data[..size_of::<i64>()]).cast())
}
}
fn as_u128(&self) -> u128 {
unsafe {
from_le_bytes!(u128, *ptr::from_ref(&self.data[..size_of::<u128>()]).cast())
}
}
fn as_i128(&self) -> i128 {
unsafe {
from_le_bytes!(i128, *ptr::from_ref(&self.data[..size_of::<i128>()]).cast())
}
}
fn as_f64(&self) -> f64 {
unsafe {
from_le_bytes!(f64, *ptr::from_ref(&self.data[..size_of::<f64>()]).cast())
}
}
fn as_f32(&self) -> f32 {
unsafe {
from_le_bytes!(f32, *ptr::from_ref(&self.data[..size_of::<f32>()]).cast())
}
}
}
#[derive(Debug, Clone, Copy)]
enum Kind {
I64, U64,
I128, U128,
F32, F64,
}
impl Display for Number {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self.kind {
Kind::I64 => self.as_i64().fmt(f),
Kind::U64 => self.as_u64().fmt(f),
Kind::I128 => self.as_i128().fmt(f),
Kind::U128 => self.as_u128().fmt(f),
Kind::F32 => self.as_f32().fmt(f),
Kind::F64 => self.as_f64().fmt(f),
}
}
}
macro_rules! impl_from_primitives_for_number { ($(($primitive: ty, $variant: tt, $target: ty)),+$(,)?) => {
$(
impl From<&$primitive> for Number {
fn from(p: &$primitive) -> Self {
let mut result = Self {
kind: Kind::$variant,
data: [u8::MIN; DATA_SIZE],
};
let p = <$target>::from(*p);
result.data[..size_of::<$target>()].copy_from_slice(&to_le_bytes!(p));
result
}
}
impl From<$primitive> for Number {
fn from(p: $primitive) -> Self {
Self::from(&p)
}
}
)+
}}
impl_from_primitives_for_number!(
(i8, I64, i64), (i16, I64, i64), (i32, I64, i64), (i64, I64, i64), (i128, I128, i128),
(u8, U64, u64), (u16, U64, u64), (u32, U64, u64), (u64, U64, u64), (u128, U128, u128),
(f32, F32, f32), (f64, F64, f64),
);
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64"))]
macro_rules! impl_from_usize_isize_for_number { ($(($primitive: ty, $variant64: tt, $target: ty)),+$(,)?) => {
$(
impl From<&$primitive> for Number {
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64"))]
fn from(n: &$primitive) -> Self {
let mut result = Self {
kind: Kind::$variant64,
data: [u8::MIN; DATA_SIZE],
};
let n = *n as $target;
result.data[..size_of::<$target>()].copy_from_slice(&to_le_bytes!(n));
result
}
}
impl From<$primitive> for Number {
fn from(n: $primitive) -> Self {
Self::from(&n)
}
}
)+
}}
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64"))]
impl_from_usize_isize_for_number!(
(usize, U64, u64),
(isize, I64, i64),
);
macro_rules! impl_try_from_number_for_integers { ($($ty: ty,)+) => {
$(
impl TryFrom<&Number> for $ty {
type Error = Error;
fn try_from(n: &Number) -> Result<Self> {
match n.kind {
Kind::U64 => {
let n = n.as_u64();
Self::try_from(n).map_err(|_| err!("Cannot convert {n} into {ty}", ty=stringify!($ty)))
},
Kind::I64 => {
let n = n.as_i64();
Self::try_from(n).map_err(|_| err!("Cannot convert {n} into {ty}", ty=stringify!($ty)))
},
Kind::U128 => {
let n = n.as_u128();
Self::try_from(n).map_err(|_| err!("Cannot convert {n} into {ty}", ty=stringify!($ty)))
},
Kind::I128 => {
let n = n.as_i128();
Self::try_from(n).map_err(|_| err!("Cannot convert {n} into {ty}", ty=stringify!($ty)))
},
Kind::F32 | Kind::F64 => Err(e!("Not an integer")),
}
}
}
impl TryFrom<Number> for $ty {
type Error = Error;
fn try_from(n: Number) -> Result<Self> {
Self::try_from(&n)
}
}
)+
}}
impl_try_from_number_for_integers!(
i8, i16, i32, i64, i128, isize,
u8, u16, u32, u64, u128, usize,
);
impl TryFrom<&Number> for f32 {
type Error = Error;
fn try_from(n: &Number) -> Result<Self> {
match n.kind {
Kind::U64 => {
let n = n.as_u64();
u16::try_from(n).map(|n| Self::from(n)).map_err(|_| err!("Cannot convert {n} into f32"))
},
Kind::I64 => {
let n = n.as_i64();
i16::try_from(n).map(|n| Self::from(n)).map_err(|_| err!("Cannot convert {n} into f32"))
},
Kind::U128 => {
let n = n.as_u128();
u16::try_from(n).map(|n| Self::from(n)).map_err(|_| err!("Cannot convert {n} into f32"))
},
Kind::I128 => {
let n = n.as_i128();
i16::try_from(n).map(|n| Self::from(n)).map_err(|_| err!("Cannot convert {n} into f32"))
},
Kind::F32 => Ok(n.as_f32()),
Kind::F64 => Err(e!("Cannot convert f64 into f32")),
}
}
}
impl TryFrom<Number> for f32 {
type Error = Error;
fn try_from(n: Number) -> Result<Self> {
Self::try_from(&n)
}
}
impl TryFrom<&Number> for f64 {
type Error = Error;
fn try_from(n: &Number) -> Result<Self> {
match n.kind {
Kind::U64 => {
let n = n.as_u64();
u32::try_from(n).map(|n| Self::from(n)).map_err(|_| err!("Cannot convert {n} into f64"))
},
Kind::I64 => {
let n = n.as_i64();
i32::try_from(n).map(|n| Self::from(n)).map_err(|_| err!("Cannot convert {n} into f64"))
},
Kind::U128 => {
let n = n.as_u128();
u32::try_from(n).map(|n| Self::from(n)).map_err(|_| err!("Cannot convert {n} into f64"))
},
Kind::I128 => {
let n = n.as_i128();
i32::try_from(n).map(|n| Self::from(n)).map_err(|_| err!("Cannot convert {n} into f64"))
},
Kind::F32 => Ok(n.as_f32().into()),
Kind::F64 => Ok(n.as_f64()),
}
}
}
impl TryFrom<Number> for f64 {
type Error = Error;
fn try_from(n: Number) -> Result<Self> {
Self::try_from(&n)
}
}