[go: up one dir, main page]

rug/integer/
traits.rs

1// Copyright © 2016–2025 Trevor Spiteri
2
3// This program is free software: you can redistribute it and/or modify it under
4// the terms of the GNU Lesser General Public License as published by the Free
5// Software Foundation, either version 3 of the License, or (at your option) any
6// later version.
7//
8// This program is distributed in the hope that it will be useful, but WITHOUT
9// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11// details.
12//
13// You should have received a copy of the GNU Lesser General Public License and
14// a copy of the GNU General Public License along with this program. If not, see
15// <https://www.gnu.org/licenses/>.
16
17use crate::ext::xmpz;
18#[allow(deprecated)]
19use crate::integer::SmallInteger;
20use crate::integer::big;
21use crate::integer::{MiniInteger, ParseIntegerError, TryFromIntegerError};
22use crate::misc::StringLike;
23use crate::{Assign, Integer};
24use az::{Az, CheckedCast};
25use core::error::Error;
26use core::fmt::{
27    Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex,
28};
29use core::hash::{Hash, Hasher};
30use core::mem;
31use core::mem::MaybeUninit;
32use core::str::FromStr;
33use gmp_mpfr_sys::gmp::limb_t;
34
35impl Default for Integer {
36    #[inline]
37    fn default() -> Integer {
38        Integer::new()
39    }
40}
41
42impl Clone for Integer {
43    #[inline]
44    fn clone(&self) -> Integer {
45        unsafe {
46            let mut dst = MaybeUninit::uninit();
47            xmpz::init_set(dst.as_mut_ptr(), self);
48            dst.assume_init()
49        }
50    }
51
52    #[inline]
53    fn clone_from(&mut self, source: &Integer) {
54        self.assign(source);
55    }
56}
57
58impl Drop for Integer {
59    #[inline]
60    fn drop(&mut self) {
61        unsafe {
62            xmpz::clear(self);
63        }
64    }
65}
66
67impl Hash for Integer {
68    #[inline]
69    fn hash<H: Hasher>(&self, state: &mut H) {
70        self.inner().size.hash(state);
71        self.inner_data().hash(state);
72    }
73}
74
75impl Assign for Integer {
76    #[inline]
77    fn assign(&mut self, src: Integer) {
78        drop(mem::replace(self, src));
79    }
80}
81
82impl Assign<&Integer> for Integer {
83    #[inline]
84    fn assign(&mut self, src: &Integer) {
85        xmpz::set(self, src);
86    }
87}
88
89impl From<&Integer> for Integer {
90    #[inline]
91    fn from(val: &Integer) -> Self {
92        val.clone()
93    }
94}
95
96impl Assign<MiniInteger> for Integer {
97    #[inline]
98    fn assign(&mut self, mut src: MiniInteger) {
99        self.assign(src.borrow_excl());
100    }
101}
102
103impl Assign<&MiniInteger> for Integer {
104    #[inline]
105    fn assign(&mut self, src: &MiniInteger) {
106        self.assign(&*src.borrow());
107    }
108}
109
110impl From<MiniInteger> for Integer {
111    #[inline]
112    fn from(mut src: MiniInteger) -> Self {
113        Integer::from(src.borrow_excl())
114    }
115}
116
117impl From<&MiniInteger> for Integer {
118    #[inline]
119    fn from(src: &MiniInteger) -> Self {
120        Integer::from(&*src.borrow())
121    }
122}
123
124#[allow(deprecated)]
125impl Assign<SmallInteger> for Integer {
126    #[inline]
127    fn assign(&mut self, src: SmallInteger) {
128        self.assign(&*src);
129    }
130}
131
132#[allow(deprecated)]
133impl Assign<&SmallInteger> for Integer {
134    #[inline]
135    fn assign(&mut self, src: &SmallInteger) {
136        self.assign(&**src);
137    }
138}
139
140#[allow(deprecated)]
141impl From<SmallInteger> for Integer {
142    #[inline]
143    fn from(src: SmallInteger) -> Self {
144        Integer::from(&*src)
145    }
146}
147
148#[allow(deprecated)]
149impl From<&SmallInteger> for Integer {
150    #[inline]
151    fn from(src: &SmallInteger) -> Self {
152        Integer::from(&**src)
153    }
154}
155
156macro_rules! try_from {
157    ($T:ty) => {
158        impl TryFrom<Integer> for $T {
159            type Error = TryFromIntegerError;
160            #[inline]
161            fn try_from(value: Integer) -> Result<Self, TryFromIntegerError> {
162                TryFrom::try_from(&value)
163            }
164        }
165
166        impl TryFrom<&Integer> for $T {
167            type Error = TryFromIntegerError;
168            #[inline]
169            fn try_from(value: &Integer) -> Result<Self, TryFromIntegerError> {
170                value
171                    .checked_cast()
172                    .ok_or(TryFromIntegerError { _unused: () })
173            }
174        }
175    };
176}
177
178try_from! { i8 }
179try_from! { i16 }
180try_from! { i32 }
181try_from! { i64 }
182try_from! { i128 }
183try_from! { isize }
184try_from! { u8 }
185try_from! { u16 }
186try_from! { u32 }
187try_from! { u64 }
188try_from! { u128 }
189try_from! { usize }
190
191macro_rules! unsafe_assign {
192    ($T:ty, $set:path, $init_set:path) => {
193        impl Assign<$T> for Integer {
194            #[inline]
195            fn assign(&mut self, src: $T) {
196                $set(self, src);
197            }
198        }
199
200        impl Assign<&$T> for Integer {
201            #[inline]
202            fn assign(&mut self, src: &$T) {
203                self.assign(*src);
204            }
205        }
206
207        impl From<$T> for Integer {
208            #[inline]
209            fn from(src: $T) -> Self {
210                unsafe {
211                    let mut dst = MaybeUninit::uninit();
212                    $init_set(dst.as_mut_ptr(), src);
213                    dst.assume_init()
214                }
215            }
216        }
217    };
218}
219
220macro_rules! assign {
221    ($T:ty as $U:ty) => {
222        impl Assign<$T> for Integer {
223            #[inline]
224            fn assign(&mut self, src: $T) {
225                self.assign(src.az::<$U>());
226            }
227        }
228
229        impl Assign<&$T> for Integer {
230            #[inline]
231            fn assign(&mut self, src: &$T) {
232                self.assign((*src).az::<$U>());
233            }
234        }
235
236        impl From<$T> for Integer {
237            #[inline]
238            fn from(src: $T) -> Self {
239                Integer::from(src.az::<$U>())
240            }
241        }
242    };
243}
244
245assign! { i8 as i32 }
246assign! { i16 as i32 }
247unsafe_assign! { i32, xmpz::set_i32, xmpz::init_set_i32 }
248unsafe_assign! { i64, xmpz::set_i64, xmpz::init_set_i64 }
249unsafe_assign! { i128, xmpz::set_i128, xmpz::init_set_i128 }
250#[cfg(target_pointer_width = "32")]
251assign! { isize as i32 }
252#[cfg(target_pointer_width = "64")]
253assign! { isize as i64 }
254
255assign! { bool as u32 }
256assign! { u8 as u32 }
257assign! { u16 as u32 }
258unsafe_assign! { u32, xmpz::set_u32, xmpz::init_set_u32 }
259unsafe_assign! { u64, xmpz::set_u64, xmpz::init_set_u64 }
260unsafe_assign! { u128, xmpz::set_u128, xmpz::init_set_u128 }
261#[cfg(target_pointer_width = "32")]
262assign! { usize as u32 }
263#[cfg(target_pointer_width = "64")]
264assign! { usize as u64 }
265
266impl FromStr for Integer {
267    type Err = ParseIntegerError;
268    #[inline]
269    fn from_str(src: &str) -> Result<Integer, ParseIntegerError> {
270        Ok(Integer::from(Integer::parse(src)?))
271    }
272}
273
274impl Display for Integer {
275    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
276        fmt_radix(self, f, 10, false, "")
277    }
278}
279
280impl Debug for Integer {
281    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
282        fmt_radix(self, f, 10, false, "")
283    }
284}
285
286impl Binary for Integer {
287    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
288        fmt_radix(self, f, 2, false, "0b")
289    }
290}
291
292impl Octal for Integer {
293    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
294        fmt_radix(self, f, 8, false, "0o")
295    }
296}
297
298impl LowerHex for Integer {
299    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
300        fmt_radix(self, f, 16, false, "0x")
301    }
302}
303
304impl UpperHex for Integer {
305    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
306        fmt_radix(self, f, 16, true, "0x")
307    }
308}
309
310fn fmt_radix(
311    i: &Integer,
312    f: &mut Formatter<'_>,
313    radix: i32,
314    to_upper: bool,
315    prefix: &str,
316) -> FmtResult {
317    let mut s = StringLike::new_malloc();
318    big::append_to_string(&mut s, i, radix, to_upper);
319    let st = s.as_str();
320    let (neg, buf) = if let Some(stripped) = st.strip_prefix('-') {
321        (true, stripped)
322    } else {
323        (false, st)
324    };
325    f.pad_integral(!neg, prefix, buf)
326}
327
328#[cfg(feature = "float")]
329mod float_conv {
330    use crate::float;
331    use crate::{Float, Integer};
332    use core::fmt::{Formatter, LowerExp, Result as FmtResult, UpperExp};
333
334    fn float_from_int(i: &Integer) -> Float {
335        let abs = i.as_abs();
336        let mut prec = abs.significant_bits();
337        // avoid copying trailing zeros
338        if let Some(zeros) = abs.find_one(0) {
339            prec -= zeros;
340        }
341        prec = prec.max(float::prec_min());
342        Float::with_val(prec, i)
343    }
344
345    impl LowerExp for Integer {
346        fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
347            LowerExp::fmt(&float_from_int(self), f)
348        }
349    }
350
351    impl UpperExp for Integer {
352        fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
353            UpperExp::fmt(&float_from_int(self), f)
354        }
355    }
356}
357
358/// Provides a reference to the underlying digits as
359/// <code>\&[\[][slice][limb_t][`limb_t`][\]][slice]</code>. See
360/// [`as_limbs`][Integer::as_limbs].
361impl AsRef<[limb_t]> for Integer {
362    #[inline]
363    fn as_ref(&self) -> &[limb_t] {
364        self.as_limbs()
365    }
366}
367
368impl TryFromIntegerError {
369    fn desc(&self) -> &str {
370        "out of range conversion attempted"
371    }
372}
373
374impl Display for TryFromIntegerError {
375    fn fmt(&self, f: &mut Formatter) -> FmtResult {
376        Display::fmt(self.desc(), f)
377    }
378}
379
380impl Error for TryFromIntegerError {
381    #[allow(deprecated)]
382    fn description(&self) -> &str {
383        self.desc()
384    }
385}
386
387// Safety: mpz_t is thread safe as guaranteed by the GMP library.
388unsafe impl Send for Integer {}
389unsafe impl Sync for Integer {}
390
391#[cfg(test)]
392mod tests {
393    use crate::{Assign, Integer};
394
395    #[test]
396    fn check_assign() {
397        let mut i = Integer::from(1);
398        assert_eq!(i, 1);
399        let other = Integer::from(2);
400        i.assign(&other);
401        assert_eq!(i, 2);
402        i.assign(-other);
403        assert_eq!(i, -2);
404    }
405
406    macro_rules! check_fallible_conversions_helper {
407        ($int:ident, $bits:expr, $I:ty, $U:ty) => {{
408            const I_MIN: $I = -1 << ($bits - 1);
409            const I_MAX: $I = -1 - I_MIN;
410            $int.assign(I_MIN);
411            assert_eq!(<$I>::try_from(&$int).ok(), Some(I_MIN));
412            $int -= 1;
413            assert!(<$I>::try_from(&$int).is_err());
414            $int.assign(I_MAX);
415            assert_eq!(<$I>::try_from(&$int).ok(), Some(I_MAX));
416            $int += 1;
417            assert!(<$I>::try_from(&$int).is_err());
418
419            const U_MIN: $U = 0;
420            const U_MAX: $U = !0;
421            $int.assign(U_MIN);
422            assert_eq!(<$U>::try_from(&$int).ok(), Some(U_MIN));
423            $int -= 1;
424            assert!(<$U>::try_from(&$int).is_err());
425            $int.assign(U_MAX);
426            assert_eq!(<$U>::try_from(&$int).ok(), Some(U_MAX));
427            $int += 1;
428            assert!(<$U>::try_from(&$int).is_err());
429        }};
430    }
431
432    #[test]
433    fn check_fallible_conversions() {
434        let mut int = Integer::new();
435        check_fallible_conversions_helper!(int, 8, i8, u8);
436        check_fallible_conversions_helper!(int, 16, i16, u16);
437        check_fallible_conversions_helper!(int, 32, i32, u32);
438        check_fallible_conversions_helper!(int, 64, i64, u64);
439        check_fallible_conversions_helper!(int, 128, i128, u128);
440    }
441}