Thanks to visit codestin.com
Credit goes to docs.rs

magnus/
integer.rs

1use std::{
2    fmt,
3    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
4    os::raw::c_long,
5};
6
7use rb_sys::{
8    rb_big_cmp, rb_big_div, rb_big_eq, rb_big_minus, rb_big_mul, rb_big_norm, rb_big_plus,
9    rb_int2big, rb_ll2inum, rb_to_int, rb_ull2inum, ruby_special_consts, ruby_value_type, Qtrue,
10    VALUE,
11};
12
13use crate::{
14    error::{protect, Error},
15    into_value::IntoValue,
16    numeric::Numeric,
17    r_bignum::RBignum,
18    try_convert::TryConvert,
19    value::{
20        private::{self, ReprValue as _},
21        Fixnum, NonZeroValue, ReprValue, Value,
22    },
23    Ruby,
24};
25
26pub(crate) enum IntegerType {
27    Fixnum(Fixnum),
28    Bignum(RBignum),
29}
30
31/// # `Integer`
32///
33/// Functions that can be used to create instances of [`Integer`].
34///
35/// See also the [`Integer`] type.
36impl Ruby {
37    /// Create a new `Integer` from an `i64.`
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// use magnus::{rb_assert, Error, Ruby};
43    ///
44    /// fn example(ruby: &Ruby) -> Result<(), Error> {
45    ///     rb_assert!(ruby, "i == 0", i = ruby.integer_from_i64(0));
46    ///     rb_assert!(
47    ///         ruby,
48    ///         "i == 4611686018427387904",
49    ///         i = ruby.integer_from_i64(4611686018427387904),
50    ///     );
51    ///     rb_assert!(
52    ///         ruby,
53    ///         "i == -4611686018427387905",
54    ///         i = ruby.integer_from_i64(-4611686018427387905),
55    ///     );
56    ///
57    ///     Ok(())
58    /// }
59    /// # Ruby::init(example).unwrap()
60    /// ```
61    #[inline]
62    pub fn integer_from_i64(&self, n: i64) -> Integer {
63        unsafe {
64            Integer::from_rb_value_unchecked(
65                Fixnum::from_i64_impl(n)
66                    .map(|f| f.as_rb_value())
67                    .unwrap_or_else(|| rb_ll2inum(n)),
68            )
69        }
70    }
71
72    /// Create a new `Integer` from a `u64.`
73    ///
74    /// # Examples
75    ///
76    /// ```
77    /// use magnus::{rb_assert, Error, Ruby};
78    ///
79    /// fn example(ruby: &Ruby) -> Result<(), Error> {
80    ///     rb_assert!("i == 0", i = ruby.integer_from_u64(0));
81    ///     rb_assert!(
82    ///         "i == 4611686018427387904",
83    ///         i = ruby.integer_from_u64(4611686018427387904),
84    ///     );
85    ///
86    ///     Ok(())
87    /// }
88    /// # Ruby::init(example).unwrap()
89    /// ```
90    #[inline]
91    pub fn integer_from_u64(&self, n: u64) -> Integer {
92        unsafe {
93            Integer::from_rb_value_unchecked(
94                Fixnum::from_i64_impl(i64::try_from(n).unwrap_or(i64::MAX))
95                    .map(|f| f.as_rb_value())
96                    .unwrap_or_else(|| rb_ull2inum(n)),
97            )
98        }
99    }
100
101    /// Create a new `Integer` from an `i128.`
102    ///
103    /// # Examples
104    ///
105    /// ```
106    /// use magnus::{rb_assert, Error, Ruby};
107    ///
108    /// fn example(ruby: &Ruby) -> Result<(), Error> {
109    ///     rb_assert!(ruby, "i == 0", i = ruby.integer_from_i128(0));
110    ///     rb_assert!(
111    ///         ruby,
112    ///         "i == 170141183460469231731687303715884105727",
113    ///         i = ruby.integer_from_i128(170141183460469231731687303715884105727),
114    ///     );
115    ///     rb_assert!(
116    ///         ruby,
117    ///         "i == -170141183460469231731687303715884105728",
118    ///         i = ruby.integer_from_i128(-170141183460469231731687303715884105728),
119    ///     );
120    ///
121    ///     Ok(())
122    /// }
123    /// # Ruby::init(example).unwrap()
124    /// ```
125    #[inline]
126    pub fn integer_from_i128(&self, n: i128) -> Integer {
127        if n >= i64::MIN as i128 && n <= i64::MAX as i128 {
128            self.integer_from_i64(n as i64)
129        } else {
130            self.module_kernel()
131                .funcall("Integer", (n.to_string(),))
132                .unwrap()
133        }
134    }
135
136    /// Create a new `Integer` from a `u128.`
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use magnus::{rb_assert, Error, Ruby};
142    ///
143    /// fn example(ruby: &Ruby) -> Result<(), Error> {
144    ///     rb_assert!("i == 0", i = ruby.integer_from_u128(0));
145    ///     rb_assert!(
146    ///         "i == 340282366920938463463374607431768211455",
147    ///         i = ruby.integer_from_u128(340282366920938463463374607431768211455),
148    ///     );
149    ///
150    ///     Ok(())
151    /// }
152    /// # Ruby::init(example).unwrap()
153    /// ```
154    #[inline]
155    pub fn integer_from_u128(&self, n: u128) -> Integer {
156        if n <= u64::MAX as u128 {
157            self.integer_from_u64(n as u64)
158        } else {
159            self.module_kernel()
160                .funcall("Integer", (n.to_string(),))
161                .unwrap()
162        }
163    }
164}
165
166/// A type wrapping either a [`Fixnum`] or a [`RBignum`].
167///
168/// See the [`ReprValue`] trait for additional methods available on this type.
169/// See [`Ruby`](Ruby#integer) for methods to create an `Integer`.
170#[derive(Clone, Copy)]
171#[repr(transparent)]
172pub struct Integer(NonZeroValue);
173
174impl Integer {
175    /// Return `Some(Integer)` if `val` is an `Integer`, `None` otherwise.
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// use magnus::{eval, Integer};
181    /// # let _cleanup = unsafe { magnus::embed::init() };
182    ///
183    /// assert!(Integer::from_value(eval("0").unwrap()).is_some());
184    /// assert!(Integer::from_value(eval("9223372036854775807").unwrap()).is_some());
185    /// // not an int
186    /// assert!(Integer::from_value(eval("1.23").unwrap()).is_none());
187    /// ```
188    #[inline]
189    pub fn from_value(val: Value) -> Option<Self> {
190        unsafe {
191            if val.as_rb_value() & ruby_special_consts::RUBY_FIXNUM_FLAG as VALUE != 0 {
192                return Some(Self(NonZeroValue::new_unchecked(val)));
193            }
194            debug_assert_value!(val);
195            (val.rb_type() == ruby_value_type::RUBY_T_BIGNUM)
196                .then(|| Self(NonZeroValue::new_unchecked(val)))
197        }
198    }
199
200    #[inline]
201    pub(crate) unsafe fn from_rb_value_unchecked(val: VALUE) -> Self {
202        Self(NonZeroValue::new_unchecked(Value::new(val)))
203    }
204
205    pub(crate) fn integer_type(self) -> IntegerType {
206        unsafe {
207            if self.as_rb_value() & ruby_special_consts::RUBY_FIXNUM_FLAG as VALUE != 0 {
208                IntegerType::Fixnum(Fixnum::from_rb_value_unchecked(self.as_rb_value()))
209            } else {
210                IntegerType::Bignum(RBignum::from_rb_value_unchecked(self.as_rb_value()))
211            }
212        }
213    }
214
215    /// Create a new `Integer` from an `i64.`
216    ///
217    /// # Panics
218    ///
219    /// Panics if called from a non-Ruby thread. See [`Ruby::integer_from_i64`]
220    /// for the non-panicking version.
221    ///
222    /// # Examples
223    ///
224    /// ```
225    /// # #![allow(deprecated)]
226    /// use magnus::{rb_assert, Integer};
227    /// # let _cleanup = unsafe { magnus::embed::init() };
228    ///
229    /// rb_assert!("i == 0", i = Integer::from_i64(0));
230    /// rb_assert!(
231    ///     "i == 4611686018427387904",
232    ///     i = Integer::from_i64(4611686018427387904),
233    /// );
234    /// rb_assert!(
235    ///     "i == -4611686018427387905",
236    ///     i = Integer::from_i64(-4611686018427387905),
237    /// );
238    /// ```
239    #[cfg_attr(
240        not(feature = "old-api"),
241        deprecated(note = "please use `Ruby::integer_from_i64` instead")
242    )]
243    #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
244    #[inline]
245    pub fn from_i64(n: i64) -> Self {
246        get_ruby!().integer_from_i64(n)
247    }
248
249    /// Create a new `Integer` from a `u64.`
250    ///
251    /// # Panics
252    ///
253    /// Panics if called from a non-Ruby thread. See [`Ruby::integer_from_u64`]
254    /// for the non-panicking version.
255    ///
256    /// # Examples
257    ///
258    /// ```
259    /// # #![allow(deprecated)]
260    /// use magnus::{rb_assert, Integer};
261    /// # let _cleanup = unsafe { magnus::embed::init() };
262    ///
263    /// rb_assert!("i == 0", i = Integer::from_u64(0));
264    /// rb_assert!(
265    ///     "i == 4611686018427387904",
266    ///     i = Integer::from_u64(4611686018427387904),
267    /// );
268    /// ```
269    #[cfg_attr(
270        not(feature = "old-api"),
271        deprecated(note = "please use `Ruby::integer_from_u64` instead")
272    )]
273    #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
274    #[inline]
275    pub fn from_u64(n: u64) -> Self {
276        get_ruby!().integer_from_u64(n)
277    }
278
279    /// Convert `self` to an `i8`. Returns `Err` if `self` is out of range for
280    /// `i8`.
281    ///
282    /// # Examples
283    ///
284    /// ```
285    /// use magnus::{eval, Integer};
286    /// # let _cleanup = unsafe { magnus::embed::init() };
287    ///
288    /// assert_eq!(eval::<Integer>("127").unwrap().to_i8().unwrap(), 127);
289    /// assert!(eval::<Integer>("128").unwrap().to_i8().is_err());
290    /// assert_eq!(eval::<Integer>("-128").unwrap().to_i8().unwrap(), -128);
291    /// assert!(eval::<Integer>("-129").unwrap().to_i8().is_err());
292    /// ```
293    #[inline]
294    pub fn to_i8(self) -> Result<i8, Error> {
295        match self.integer_type() {
296            IntegerType::Fixnum(fix) => fix.to_i8(),
297            IntegerType::Bignum(_) => Err(Error::new(
298                Ruby::get_with(self).exception_range_error(),
299                "bignum too big to convert into `i8`",
300            )),
301        }
302    }
303
304    /// Convert `self` to an `i16`. Returns `Err` if `self` is out of range for
305    /// `i16`.
306    ///
307    /// # Examples
308    ///
309    /// ```
310    /// use magnus::{eval, Integer};
311    /// # let _cleanup = unsafe { magnus::embed::init() };
312    ///
313    /// assert_eq!(eval::<Integer>("32767").unwrap().to_i16().unwrap(), 32767);
314    /// assert!(eval::<Integer>("32768").unwrap().to_i16().is_err());
315    /// assert_eq!(eval::<Integer>("-32768").unwrap().to_i16().unwrap(), -32768);
316    /// assert!(eval::<Integer>("-32769").unwrap().to_i16().is_err());
317    /// ```
318    #[inline]
319    pub fn to_i16(self) -> Result<i16, Error> {
320        match self.integer_type() {
321            IntegerType::Fixnum(fix) => fix.to_i16(),
322            IntegerType::Bignum(_) => Err(Error::new(
323                Ruby::get_with(self).exception_range_error(),
324                "bignum too big to convert into `i16`",
325            )),
326        }
327    }
328
329    /// Convert `self` to an `i32`. Returns `Err` if `self` is out of range for
330    /// `i32`.
331    ///
332    /// # Examples
333    ///
334    /// ```
335    /// use magnus::{eval, Integer};
336    /// # let _cleanup = unsafe { magnus::embed::init() };
337    ///
338    /// assert_eq!(
339    ///     eval::<Integer>("2147483647").unwrap().to_i32().unwrap(),
340    ///     2147483647
341    /// );
342    /// assert!(eval::<Integer>("2147483648").unwrap().to_i32().is_err());
343    /// assert_eq!(
344    ///     eval::<Integer>("-2147483648").unwrap().to_i32().unwrap(),
345    ///     -2147483648
346    /// );
347    /// assert!(eval::<Integer>("-2147483649").unwrap().to_i32().is_err());
348    /// ```
349    #[inline]
350    pub fn to_i32(self) -> Result<i32, Error> {
351        match self.integer_type() {
352            IntegerType::Fixnum(fix) => fix.to_i32(),
353            IntegerType::Bignum(big) => big.to_i32(),
354        }
355    }
356
357    /// Convert `self` to an `i64`. Returns `Err` if `self` is out of range for
358    /// `i64`.
359    ///
360    /// # Examples
361    ///
362    /// ```
363    /// use magnus::{eval, Integer};
364    /// # let _cleanup = unsafe { magnus::embed::init() };
365    ///
366    /// assert_eq!(
367    ///     eval::<Integer>("4611686018427387903")
368    ///         .unwrap()
369    ///         .to_i64()
370    ///         .unwrap(),
371    ///     4611686018427387903
372    /// );
373    /// assert_eq!(
374    ///     eval::<Integer>("-4611686018427387904")
375    ///         .unwrap()
376    ///         .to_i64()
377    ///         .unwrap(),
378    ///     -4611686018427387904
379    /// );
380    /// assert!(eval::<Integer>("9223372036854775808")
381    ///     .unwrap()
382    ///     .to_i64()
383    ///     .is_err());
384    /// assert!(eval::<Integer>("-9223372036854775809")
385    ///     .unwrap()
386    ///     .to_i64()
387    ///     .is_err());
388    /// ```
389    #[inline]
390    pub fn to_i64(self) -> Result<i64, Error> {
391        match self.integer_type() {
392            IntegerType::Fixnum(fix) => Ok(fix.to_i64()),
393            IntegerType::Bignum(big) => big.to_i64(),
394        }
395    }
396
397    /// Convert `self` to an `i128`. Returns `Err` if `self` is out of range for
398    /// `i128`.
399    ///
400    /// # Examples
401    ///
402    /// ```
403    /// use magnus::{eval, Integer};
404    /// # let _cleanup = unsafe { magnus::embed::init() };
405    ///
406    /// assert_eq!(
407    ///     eval::<Integer>("170141183460469231731687303715884105727")
408    ///         .unwrap()
409    ///         .to_i128()
410    ///         .unwrap(),
411    ///     170141183460469231731687303715884105727
412    /// );
413    /// assert_eq!(
414    ///     eval::<Integer>("-170141183460469231731687303715884105728")
415    ///         .unwrap()
416    ///         .to_i128()
417    ///         .unwrap(),
418    ///     -170141183460469231731687303715884105728
419    /// );
420    /// assert!(eval::<Integer>("170141183460469231731687303715884105728")
421    ///     .unwrap()
422    ///     .to_i128()
423    ///     .is_err());
424    /// assert!(eval::<Integer>("-170141183460469231731687303715884105729")
425    ///     .unwrap()
426    ///     .to_i128()
427    ///     .is_err());
428    /// ```
429    #[inline]
430    pub fn to_i128(self) -> Result<i128, Error> {
431        match self.integer_type() {
432            IntegerType::Fixnum(fix) => Ok(fix.to_i128()),
433            IntegerType::Bignum(big) => big.to_i128(),
434        }
435    }
436
437    /// Convert `self` to an `isize`. Returns `Err` if `self` is out of range
438    /// for `isize`.
439    ///
440    /// # Examples
441    ///
442    /// ```
443    /// use magnus::{eval, Integer};
444    /// # let _cleanup = unsafe { magnus::embed::init() };
445    ///
446    /// assert_eq!(
447    ///     eval::<Integer>("4611686018427387903")
448    ///         .unwrap()
449    ///         .to_isize()
450    ///         .unwrap(),
451    ///     4611686018427387903
452    /// );
453    /// assert_eq!(
454    ///     eval::<Integer>("-4611686018427387904")
455    ///         .unwrap()
456    ///         .to_isize()
457    ///         .unwrap(),
458    ///     -4611686018427387904
459    /// );
460    /// ```
461    #[inline]
462    pub fn to_isize(self) -> Result<isize, Error> {
463        match self.integer_type() {
464            IntegerType::Fixnum(fix) => Ok(fix.to_isize()),
465            IntegerType::Bignum(big) => big.to_isize(),
466        }
467    }
468
469    /// Convert `self` to a `u8`. Returns `Err` if `self` is negative or out of
470    /// range for `u8`.
471    ///
472    /// # Examples
473    ///
474    /// ```
475    /// use magnus::{eval, Integer};
476    /// # let _cleanup = unsafe { magnus::embed::init() };
477    ///
478    /// assert_eq!(eval::<Integer>("255").unwrap().to_u8().unwrap(), 255);
479    /// assert!(eval::<Integer>("256").unwrap().to_u8().is_err());
480    /// assert!(eval::<Integer>("-1").unwrap().to_u8().is_err());
481    /// ```
482    #[inline]
483    pub fn to_u8(self) -> Result<u8, Error> {
484        match self.integer_type() {
485            IntegerType::Fixnum(fix) => fix.to_u8(),
486            IntegerType::Bignum(_) => Err(Error::new(
487                Ruby::get_with(self).exception_range_error(),
488                "bignum too big to convert into `u8`",
489            )),
490        }
491    }
492
493    /// Convert `self` to a `u16`. Returns `Err` if `self` is negative or out
494    /// of range for `u16`.
495    ///
496    /// # Examples
497    ///
498    /// ```
499    /// use magnus::{eval, Integer};
500    /// # let _cleanup = unsafe { magnus::embed::init() };
501    ///
502    /// assert_eq!(eval::<Integer>("65535").unwrap().to_u16().unwrap(), 65535);
503    /// assert!(eval::<Integer>("65536").unwrap().to_u16().is_err());
504    /// assert!(eval::<Integer>("-1").unwrap().to_u16().is_err());
505    /// ```
506    #[inline]
507    pub fn to_u16(self) -> Result<u16, Error> {
508        match self.integer_type() {
509            IntegerType::Fixnum(fix) => fix.to_u16(),
510            IntegerType::Bignum(_) => Err(Error::new(
511                Ruby::get_with(self).exception_range_error(),
512                "bignum too big to convert into `u16`",
513            )),
514        }
515    }
516
517    /// Convert `self` to a `u32`. Returns `Err` if `self` is negative or out
518    /// of range for `u32`.
519    ///
520    /// # Examples
521    ///
522    /// ```
523    /// use magnus::{eval, Integer};
524    /// # let _cleanup = unsafe { magnus::embed::init() };
525    ///
526    /// assert_eq!(
527    ///     eval::<Integer>("4294967295").unwrap().to_u32().unwrap(),
528    ///     4294967295
529    /// );
530    /// assert!(eval::<Integer>("4294967296").unwrap().to_u32().is_err());
531    /// assert!(eval::<Integer>("-1").unwrap().to_u32().is_err());
532    /// ```
533    #[inline]
534    pub fn to_u32(self) -> Result<u32, Error> {
535        match self.integer_type() {
536            IntegerType::Fixnum(fix) => fix.to_u32(),
537            IntegerType::Bignum(big) => big.to_u32(),
538        }
539    }
540
541    /// Convert `self` to a `u64`. Returns `Err` if `self` is negative or out
542    /// of range for `u64`.
543    ///
544    /// # Examples
545    ///
546    /// ```
547    /// use magnus::{eval, Integer};
548    /// # let _cleanup = unsafe { magnus::embed::init() };
549    ///
550    /// assert_eq!(
551    ///     eval::<Integer>("4611686018427387903")
552    ///         .unwrap()
553    ///         .to_u64()
554    ///         .unwrap(),
555    ///     4611686018427387903
556    /// );
557    /// assert!(eval::<Integer>("-1").unwrap().to_u64().is_err());
558    /// assert!(eval::<Integer>("18446744073709551616")
559    ///     .unwrap()
560    ///     .to_u64()
561    ///     .is_err());
562    /// ```
563    #[inline]
564    pub fn to_u64(self) -> Result<u64, Error> {
565        match self.integer_type() {
566            IntegerType::Fixnum(fix) => fix.to_u64(),
567            IntegerType::Bignum(big) => big.to_u64(),
568        }
569    }
570
571    /// Convert `self` to a `u128`. Returns `Err` if `self` is negative or out of
572    /// range for `u128`.
573    ///
574    /// # Examples
575    ///
576    /// ```
577    /// use magnus::{eval, Integer};
578    /// # let _cleanup = unsafe { magnus::embed::init() };
579    ///
580    /// assert_eq!(
581    ///     eval::<Integer>("340282366920938463463374607431768211455")
582    ///         .unwrap()
583    ///         .to_u128()
584    ///         .unwrap(),
585    ///     340282366920938463463374607431768211455
586    /// );
587    /// assert!(eval::<Integer>("-1").unwrap().to_u128().is_err());
588    /// assert!(eval::<Integer>("340282366920938463463374607431768211456")
589    ///     .unwrap()
590    ///     .to_u128()
591    ///     .is_err());
592    /// ```
593    #[inline]
594    pub fn to_u128(self) -> Result<u128, Error> {
595        match self.integer_type() {
596            IntegerType::Fixnum(fix) => fix.to_u128(),
597            IntegerType::Bignum(big) => big.to_u128(),
598        }
599    }
600
601    /// Convert `self` to a `usize`. Returns `Err` if `self` is negative or out
602    /// of range for `usize`.
603    ///
604    /// # Examples
605    ///
606    /// ```
607    /// use magnus::{eval, Integer};
608    /// # let _cleanup = unsafe { magnus::embed::init() };
609    ///
610    /// assert_eq!(
611    ///     eval::<Integer>("4611686018427387903")
612    ///         .unwrap()
613    ///         .to_usize()
614    ///         .unwrap(),
615    ///     4611686018427387903
616    /// );
617    /// assert!(eval::<Integer>("-1").unwrap().to_usize().is_err());
618    /// ```
619    #[inline]
620    pub fn to_usize(self) -> Result<usize, Error> {
621        match self.integer_type() {
622            IntegerType::Fixnum(fix) => fix.to_usize(),
623            IntegerType::Bignum(big) => big.to_usize(),
624        }
625    }
626
627    /// Normalize `self`. If `self` is a `Fixnum`, returns `self`. If `self` is
628    /// a `Bignum`, if it is small enough to fit in a `Fixnum`, returns a
629    /// `Fixnum` with the same value. Otherwise, returns `self`.
630    pub fn norm(&self) -> Self {
631        match self.integer_type() {
632            IntegerType::Fixnum(_) => *self,
633            IntegerType::Bignum(big) => unsafe {
634                Integer::from_rb_value_unchecked(rb_big_norm(big.as_rb_value()))
635            },
636        }
637    }
638
639    fn binary_operation_visit<T>(
640        &self,
641        other: &Self,
642        rust_op: fn(Fixnum, Fixnum) -> T,
643        ruby_op: fn(VALUE, VALUE) -> T,
644    ) -> T {
645        match self.integer_type() {
646            IntegerType::Bignum(a) => ruby_op(a.as_rb_value(), other.as_rb_value()),
647            IntegerType::Fixnum(a) => match other.integer_type() {
648                IntegerType::Bignum(b) => {
649                    let a = unsafe { rb_int2big(a.to_isize()) };
650                    ruby_op(a, b.as_rb_value())
651                }
652                IntegerType::Fixnum(b) => rust_op(a, b),
653            },
654        }
655    }
656}
657
658impl fmt::Display for Integer {
659    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
660        write!(f, "{}", unsafe { self.to_s_infallible() })
661    }
662}
663
664impl fmt::Debug for Integer {
665    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
666        write!(f, "{}", self.inspect())
667    }
668}
669
670impl IntoValue for Integer {
671    #[inline]
672    fn into_value_with(self, _: &Ruby) -> Value {
673        self.0.get()
674    }
675}
676
677impl Numeric for Integer {}
678
679unsafe impl private::ReprValue for Integer {}
680
681impl ReprValue for Integer {}
682
683impl TryConvert for Integer {
684    fn try_convert(val: Value) -> Result<Self, Error> {
685        match Self::from_value(val) {
686            Some(i) => Ok(i),
687            None => protect(|| {
688                debug_assert_value!(val);
689                unsafe { Self::from_rb_value_unchecked(rb_to_int(val.as_rb_value())) }
690            }),
691        }
692    }
693}
694
695impl PartialEq for Integer {
696    fn eq(&self, other: &Self) -> bool {
697        match self.integer_type() {
698            IntegerType::Bignum(a) => unsafe {
699                rb_big_eq(a.as_rb_value(), other.as_rb_value()) == Qtrue.into()
700            },
701            IntegerType::Fixnum(a) => a.as_rb_value() == other.norm().as_rb_value(),
702        }
703    }
704}
705
706impl PartialOrd for Integer {
707    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
708        self.binary_operation_visit(
709            other,
710            |a, b| (a.as_rb_value() as c_long).partial_cmp(&(b.as_rb_value() as c_long)),
711            |a, b| unsafe {
712                let result = rb_big_cmp(a, b);
713                Integer::from_rb_value_unchecked(result)
714                    .to_i64()
715                    .unwrap()
716                    .partial_cmp(&0)
717            },
718        )
719    }
720}
721
722impl Add for Integer {
723    type Output = Self;
724
725    fn add(self, other: Self) -> Self {
726        self.binary_operation_visit(
727            &other,
728            |a, b| {
729                let raw_a = a.as_rb_value() as c_long;
730                let raw_b = b.as_rb_value() as c_long;
731                let result = raw_a.checked_add(raw_b).and_then(|i| i.checked_sub(1));
732                if let Some(result) = result {
733                    unsafe { Integer::from_rb_value_unchecked(result as VALUE) }
734                } else {
735                    let a = unsafe { rb_int2big(a.to_isize()) };
736                    let result = unsafe { rb_big_plus(a, b.as_rb_value()) };
737                    unsafe { Integer::from_rb_value_unchecked(result) }
738                }
739            },
740            |a, b| {
741                let result = unsafe { rb_big_plus(a, b) };
742                unsafe { Integer::from_rb_value_unchecked(result) }
743            },
744        )
745    }
746}
747
748impl AddAssign for Integer {
749    fn add_assign(&mut self, other: Self) {
750        *self = *self + other;
751    }
752}
753
754impl Sub for Integer {
755    type Output = Self;
756
757    fn sub(self, other: Self) -> Self {
758        self.binary_operation_visit(
759            &other,
760            |a, b| {
761                let raw_a = a.as_rb_value() as c_long;
762                let raw_b = b.as_rb_value() as c_long;
763                let result = raw_a.checked_sub(raw_b).and_then(|i| i.checked_add(1));
764                if let Some(result) = result {
765                    unsafe { Integer::from_rb_value_unchecked(result as VALUE) }
766                } else {
767                    let a = unsafe { rb_int2big(a.to_isize()) };
768                    let result = unsafe { rb_big_minus(a, b.as_rb_value()) };
769                    unsafe { Integer::from_rb_value_unchecked(result) }
770                }
771            },
772            |a, b| {
773                let result = unsafe { rb_big_minus(a, b) };
774                unsafe { Integer::from_rb_value_unchecked(result) }
775            },
776        )
777    }
778}
779
780impl SubAssign for Integer {
781    fn sub_assign(&mut self, other: Self) {
782        *self = *self - other;
783    }
784}
785
786impl Mul for Integer {
787    type Output = Self;
788
789    fn mul(self, other: Self) -> Self {
790        self.binary_operation_visit(
791            &other,
792            |a, b| {
793                let raw_a = a.to_i64();
794                let raw_b = b.to_i64();
795                let result = raw_a.checked_mul(raw_b);
796                if let Some(result) = result {
797                    Ruby::get_with(a).integer_from_i64(result)
798                } else {
799                    let a = unsafe { rb_int2big(a.to_isize()) };
800                    let result = unsafe { rb_big_mul(a, b.as_rb_value()) };
801                    unsafe { Integer::from_rb_value_unchecked(result) }
802                }
803            },
804            |a, b| {
805                let result = unsafe { rb_big_mul(a, b) };
806                unsafe { Integer::from_rb_value_unchecked(result) }
807            },
808        )
809    }
810}
811
812impl MulAssign for Integer {
813    fn mul_assign(&mut self, other: Self) {
814        *self = *self * other;
815    }
816}
817
818impl Div for Integer {
819    type Output = Self;
820
821    fn div(self, other: Self) -> Self {
822        self.binary_operation_visit(
823            &other,
824            |a, b| {
825                let raw_a = a.to_i64();
826                let raw_b = b.to_i64();
827                // the only case when division can overflow is when dividing
828                // i64::MIN by -1, but Fixnum can't represent that I64::MIN
829                // so we can safely not use checked_div here
830                Ruby::get_with(a).integer_from_i64(raw_a / raw_b)
831            },
832            |a, b| {
833                let result = unsafe { rb_big_div(a, b) };
834                unsafe { Integer::from_rb_value_unchecked(result) }
835            },
836        )
837    }
838}
839
840impl DivAssign for Integer {
841    fn div_assign(&mut self, other: Self) {
842        *self = *self / other;
843    }
844}