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}