Skip to main content

crypto_bigint/int/
from.rs

1//! `From`-like conversions for [`Int`].
2
3use crate::{CtOption, I64, I128, Int, Limb, Uint, Word};
4
5macro_rules! check_limbs {
6    ($limbs:expr) => {
7        const {
8            assert!($limbs >= 1, "number of limbs must be greater than zero");
9        }
10    };
11}
12
13#[allow(clippy::cast_sign_loss)]
14impl<const LIMBS: usize> Int<LIMBS> {
15    /// Create a [`Int`] from an `i8` (const-friendly)
16    // TODO(tarcieri): replace with `const impl From<i8>` when stable
17    #[inline]
18    #[must_use]
19    pub const fn from_i8(n: i8) -> Self {
20        check_limbs!(LIMBS);
21        Uint::new([Limb(n as Word)]).as_int().resize()
22    }
23
24    /// Create a [`Int`] from an `i16` (const-friendly)
25    // TODO(tarcieri): replace with `const impl From<i16>` when stable
26    #[inline]
27    #[must_use]
28    pub const fn from_i16(n: i16) -> Self {
29        check_limbs!(LIMBS);
30        Uint::new([Limb(n as Word)]).as_int().resize()
31    }
32
33    /// Create a [`Int`] from an `i32` (const-friendly)
34    // TODO(tarcieri): replace with `const impl From<i32>` when stable
35    #[inline]
36    #[must_use]
37    pub const fn from_i32(n: i32) -> Self {
38        check_limbs!(LIMBS);
39        Uint::new([Limb(n as Word)]).as_int().resize()
40    }
41
42    cpubits::cpubits! {
43        32 => {
44            /// Create a [`Int`] from an `i64` (const-friendly)
45            // TODO(tarcieri): replace with `const impl From<i64>` when stable
46            #[inline]
47            pub const fn from_i64(n: i64) -> Self {
48                check_limbs!(LIMBS);
49                Uint::<{ I64::LIMBS }>::from_u64(n as u64).as_int().resize()
50            }
51        }
52        64 => {
53            /// Create a [`Int`] from an `i64` (const-friendly)
54            // TODO(tarcieri): replace with `const impl From<i64>` when stable
55            #[inline]
56            #[must_use]
57            pub const fn from_i64(n: i64) -> Self {
58                check_limbs!(LIMBS);
59                Uint::new([Limb(n as Word)]).as_int().resize()
60            }
61        }
62    }
63
64    /// Create a [`Int`] from an `i128` (const-friendly)
65    // TODO(tarcieri): replace with `const impl From<i128>` when stable
66    #[inline]
67    #[must_use]
68    pub const fn from_i128(n: i128) -> Self {
69        Uint::<{ I128::LIMBS }>::from_u128(n as u128)
70            .as_int()
71            .resize()
72    }
73
74    /// Convert a `CtOption<Uint<LIMBS>>` to a `CtOption<Int<LIMBS>>`
75    // TODO(tarcieri): replace with `const impl From<CtOption<Uint>>` when stable
76    #[inline]
77    pub(super) const fn from_uint_opt(opt: CtOption<Uint<LIMBS>>) -> CtOption<Self> {
78        CtOption::new(*opt.as_inner_unchecked().as_int(), opt.is_some())
79    }
80}
81
82impl<const LIMBS: usize> From<i8> for Int<LIMBS> {
83    #[inline]
84    fn from(n: i8) -> Self {
85        const {
86            debug_assert!(LIMBS > 0, "limbs must be non-zero");
87        }
88        Self::from_i8(n)
89    }
90}
91
92impl<const LIMBS: usize> From<i16> for Int<LIMBS> {
93    #[inline]
94    fn from(n: i16) -> Self {
95        const {
96            debug_assert!(LIMBS > 0, "limbs must be non-zero");
97        }
98        Self::from_i16(n)
99    }
100}
101
102impl<const LIMBS: usize> From<i32> for Int<LIMBS> {
103    #[inline]
104    fn from(n: i32) -> Self {
105        const {
106            debug_assert!(LIMBS > 0, "limbs must be non-zero");
107        }
108        Self::from_i32(n)
109    }
110}
111
112impl<const LIMBS: usize> From<i64> for Int<LIMBS> {
113    #[inline]
114    fn from(n: i64) -> Self {
115        #[allow(clippy::integer_division_remainder_used, reason = "const/debug")]
116        const {
117            debug_assert!(LIMBS >= 8 / Limb::BYTES, "not enough limbs");
118        }
119        Self::from_i64(n)
120    }
121}
122
123impl<const LIMBS: usize> From<i128> for Int<LIMBS> {
124    #[inline]
125    fn from(n: i128) -> Self {
126        #[allow(clippy::integer_division_remainder_used, reason = "const/debug")]
127        const {
128            debug_assert!(LIMBS >= 16 / Limb::BYTES, "not enough limbs");
129        }
130        Self::from_i128(n)
131    }
132}
133
134impl From<I64> for i64 {
135    #[inline]
136    #[allow(clippy::cast_possible_wrap)]
137    fn from(n: I64) -> i64 {
138        u64::from(n.0) as i64
139    }
140}
141
142impl From<I128> for i128 {
143    #[inline]
144    #[allow(clippy::cast_possible_wrap)]
145    fn from(n: I128) -> i128 {
146        u128::from(n.0) as i128
147    }
148}
149
150impl<const LIMBS: usize, const LIMBS2: usize> From<&Int<LIMBS>> for Int<LIMBS2> {
151    #[inline]
152    fn from(num: &Int<LIMBS>) -> Int<LIMBS2> {
153        num.resize()
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use crate::{I128, Limb};
160
161    cpubits::cpubits! {
162        32 => { use crate::I64 as IntEx; }
163        64 => { use crate::I128 as IntEx; }
164    }
165
166    #[test]
167    fn from_i8() {
168        let n = IntEx::from(42i8);
169        assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]);
170        let n = IntEx::from(-42i8);
171        assert_eq!(n.as_limbs(), &[Limb::MAX - Limb::from(41u32), Limb::MAX]);
172    }
173
174    #[test]
175    fn from_i16() {
176        let n = IntEx::from(42i16);
177        assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]);
178        let n = IntEx::from(-42i16);
179        assert_eq!(n.as_limbs(), &[Limb::MAX - Limb::from(41u32), Limb::MAX]);
180    }
181
182    #[test]
183    fn from_i32() {
184        let n = IntEx::from(42i32);
185        assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]);
186        let n = IntEx::from(-42i32);
187        assert_eq!(n.as_limbs(), &[Limb::MAX - Limb::from(41u32), Limb::MAX]);
188    }
189
190    #[test]
191    fn from_i64() {
192        let n = IntEx::from(42i64);
193        assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]);
194        let n = IntEx::from(-42i64);
195        assert_eq!(n.as_limbs(), &[Limb::MAX - Limb::from(41u32), Limb::MAX]);
196    }
197
198    #[test]
199    fn from_i128() {
200        let n = I128::from(42i128);
201        assert_eq!(&n.as_limbs()[..2], &[Limb(42), Limb(0)]);
202        assert_eq!(i128::from(n), 42i128);
203        let n = I128::from(-42i128);
204        assert_eq!(&n.as_limbs()[..2], &[Limb::MAX - Limb(41), Limb::MAX]);
205        assert_eq!(i128::from(n), -42i128);
206    }
207}