Skip to main content

alox_48/rb_types/
fixnum.rs

1// Copyright (c) 2024 Lily Lyons
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use crate::{FromPrimitive, NumCast, ToPrimitive};
8
9/// A type representing an integer within the interval [-2<sup>30</sup>, 2<sup>30</sup>).
10#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
11pub struct Fixnum(i32);
12
13impl Fixnum {
14    /// Attempts to create a new [`Fixnum`] from a sign and little-endian bytes.
15    /// Will fail if the represented integer is outside of the interval
16    /// [-2<sup>30</sup>, 2<sup>30</sup>).
17    pub fn from_le_bytes(is_negative: bool, le_bytes: &[u8]) -> Option<Self> {
18        let (is_negative, le_bytes) = super::canonicalize_le_bytes_ref(is_negative, le_bytes);
19        (le_bytes.len() <= size_of::<i32>())
20            .then(|| {
21                let value = i32::from_le_bytes(super::to_array_with_default(le_bytes));
22                let value = if is_negative {
23                    value.wrapping_neg()
24                } else {
25                    value
26                };
27                (value.is_negative() == is_negative)
28                    .then(|| FromPrimitive::from_i32(value))
29                    .flatten()
30            })
31            .flatten()
32    }
33}
34
35impl From<i8> for Fixnum {
36    fn from(value: i8) -> Self {
37        Self(value.into())
38    }
39}
40
41impl From<u8> for Fixnum {
42    fn from(value: u8) -> Self {
43        Self(value.into())
44    }
45}
46
47impl From<i16> for Fixnum {
48    fn from(value: i16) -> Self {
49        Self(value.into())
50    }
51}
52
53impl From<u16> for Fixnum {
54    fn from(value: u16) -> Self {
55        Self(value.into())
56    }
57}
58
59impl From<Fixnum> for i32 {
60    fn from(value: Fixnum) -> Self {
61        value.0
62    }
63}
64
65impl From<Fixnum> for i64 {
66    fn from(value: Fixnum) -> Self {
67        value.0.into()
68    }
69}
70
71impl From<Fixnum> for i128 {
72    fn from(value: Fixnum) -> Self {
73        value.0.into()
74    }
75}
76
77impl From<Fixnum> for num_bigint::BigInt {
78    fn from(value: Fixnum) -> Self {
79        value.0.into()
80    }
81}
82
83impl FromPrimitive for Fixnum {
84    fn from_i64(n: i64) -> Option<Self> {
85        if (-(1 << 30)..1 << 30).contains(&n) {
86            Some(Self(n as i32))
87        } else {
88            None
89        }
90    }
91
92    fn from_u64(n: u64) -> Option<Self> {
93        n.to_i64().and_then(Self::from_i64)
94    }
95}
96
97impl ToPrimitive for Fixnum {
98    fn to_i64(&self) -> Option<i64> {
99        self.0.to_i64()
100    }
101
102    fn to_u64(&self) -> Option<u64> {
103        self.0.to_u64()
104    }
105}
106
107impl NumCast for Fixnum {
108    fn from<T: ToPrimitive>(n: T) -> Option<Self> {
109        n.to_i32().and_then(FromPrimitive::from_i32)
110    }
111}
112
113macro_rules! try_from_impl {
114    ($($from:ty => $to:ty),* $(,)?) => {
115        $(impl TryFrom<$from> for $to {
116            type Error = $from;
117            fn try_from(value: $from) -> Result<Self, Self::Error> {
118                NumCast::from(value).ok_or(value)
119            }
120        })*
121    };
122}
123
124try_from_impl! {
125    i32 => Fixnum,
126    u32 => Fixnum,
127    i64 => Fixnum,
128    u64 => Fixnum,
129    i128 => Fixnum,
130    u128 => Fixnum,
131    isize => Fixnum,
132    usize => Fixnum,
133    Fixnum => i8,
134    Fixnum => u8,
135    Fixnum => i16,
136    Fixnum => u16,
137    Fixnum => u32,
138    Fixnum => u64,
139    Fixnum => u128,
140    Fixnum => isize,
141    Fixnum => usize,
142}
143
144impl num_bigint::ToBigInt for Fixnum {
145    fn to_bigint(&self) -> Option<num_bigint::BigInt> {
146        self.0.to_bigint()
147    }
148}
149
150impl num_bigint::ToBigUint for Fixnum {
151    fn to_biguint(&self) -> Option<num_bigint::BigUint> {
152        self.0.to_biguint()
153    }
154}
155
156impl std::fmt::Debug for Fixnum {
157    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158        self.0.fmt(f)
159    }
160}
161
162impl std::fmt::Display for Fixnum {
163    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164        self.0.fmt(f)
165    }
166}