use crate::{FromPrimitive, NumCast, ToPrimitive};
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct Fixnum(i32);
impl Fixnum {
pub fn from_le_bytes(is_negative: bool, le_bytes: &[u8]) -> Option<Self> {
let (is_negative, le_bytes) = super::canonicalize_le_bytes_ref(is_negative, le_bytes);
(le_bytes.len() <= size_of::<i32>())
.then(|| {
let value = i32::from_le_bytes(super::to_array_with_default(le_bytes));
let value = if is_negative {
value.wrapping_neg()
} else {
value
};
(value.is_negative() == is_negative)
.then(|| FromPrimitive::from_i32(value))
.flatten()
})
.flatten()
}
}
impl From<i8> for Fixnum {
fn from(value: i8) -> Self {
Self(value.into())
}
}
impl From<u8> for Fixnum {
fn from(value: u8) -> Self {
Self(value.into())
}
}
impl From<i16> for Fixnum {
fn from(value: i16) -> Self {
Self(value.into())
}
}
impl From<u16> for Fixnum {
fn from(value: u16) -> Self {
Self(value.into())
}
}
impl From<Fixnum> for i32 {
fn from(value: Fixnum) -> Self {
value.0
}
}
impl From<Fixnum> for i64 {
fn from(value: Fixnum) -> Self {
value.0.into()
}
}
impl From<Fixnum> for i128 {
fn from(value: Fixnum) -> Self {
value.0.into()
}
}
impl From<Fixnum> for num_bigint::BigInt {
fn from(value: Fixnum) -> Self {
value.0.into()
}
}
impl FromPrimitive for Fixnum {
fn from_i64(n: i64) -> Option<Self> {
if (-(1 << 30)..1 << 30).contains(&n) {
Some(Self(n as i32))
} else {
None
}
}
fn from_u64(n: u64) -> Option<Self> {
n.to_i64().and_then(Self::from_i64)
}
}
impl ToPrimitive for Fixnum {
fn to_i64(&self) -> Option<i64> {
self.0.to_i64()
}
fn to_u64(&self) -> Option<u64> {
self.0.to_u64()
}
}
impl NumCast for Fixnum {
fn from<T: ToPrimitive>(n: T) -> Option<Self> {
n.to_i32().and_then(FromPrimitive::from_i32)
}
}
macro_rules! try_from_impl {
($($from:ty => $to:ty),* $(,)?) => {
$(impl TryFrom<$from> for $to {
type Error = $from;
fn try_from(value: $from) -> Result<Self, Self::Error> {
NumCast::from(value).ok_or(value)
}
})*
};
}
try_from_impl! {
i32 => Fixnum,
u32 => Fixnum,
i64 => Fixnum,
u64 => Fixnum,
i128 => Fixnum,
u128 => Fixnum,
isize => Fixnum,
usize => Fixnum,
Fixnum => i8,
Fixnum => u8,
Fixnum => i16,
Fixnum => u16,
Fixnum => u32,
Fixnum => u64,
Fixnum => u128,
Fixnum => isize,
Fixnum => usize,
}
impl num_bigint::ToBigInt for Fixnum {
fn to_bigint(&self) -> Option<num_bigint::BigInt> {
self.0.to_bigint()
}
}
impl num_bigint::ToBigUint for Fixnum {
fn to_biguint(&self) -> Option<num_bigint::BigUint> {
self.0.to_biguint()
}
}
impl std::fmt::Debug for Fixnum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::fmt::Display for Fixnum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}