#![allow(deprecated)]
use crate::integer::{MiniInteger, ToSmall};
use crate::{Assign, Rational};
use core::fmt::{Debug, Formatter, Result as FmtResult};
use core::marker::PhantomData;
use core::ops::Deref;
use gmp_mpfr_sys::gmp::limb_t;
#[deprecated(since = "1.23.0", note = "use `MiniRational` instead")]
#[derive(Clone)]
pub struct SmallRational {
inner: Option<Rational>,
phantom: PhantomData<*const limb_t>,
}
unsafe impl Send for SmallRational {}
impl Default for SmallRational {
#[inline]
fn default() -> Self {
SmallRational::new()
}
}
impl Debug for SmallRational {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match &self.inner {
Some(r) => Debug::fmt(r, f),
None => Debug::fmt(Rational::ZERO, f),
}
}
}
impl SmallRational {
#[inline]
pub const fn new() -> Self {
SmallRational {
inner: None,
phantom: PhantomData,
}
}
#[inline]
pub unsafe fn as_nonreallocating_rational(&mut self) -> &mut Rational {
if self.inner.is_none() {
*self = SmallRational {
inner: Some(Rational::new()),
phantom: PhantomData,
};
}
match &mut self.inner {
Some(r) => r,
None => unreachable!(),
}
}
pub unsafe fn from_canonical<Num: ToSmall, Den: ToSmall>(num: Num, den: Den) -> Self {
let num = MiniInteger::from(num);
let den = MiniInteger::from(den);
SmallRational {
inner: Some(unsafe { Rational::from_canonical(num, den) }),
phantom: PhantomData,
}
}
pub unsafe fn assign_canonical<Num: ToSmall, Den: ToSmall>(&mut self, num: Num, den: Den) {
let mut num = MiniInteger::from(num);
let mut den = MiniInteger::from(den);
unsafe {
self.as_nonreallocating_rational()
.assign_canonical(num.borrow_excl(), den.borrow_excl());
}
}
}
impl Deref for SmallRational {
type Target = Rational;
#[inline]
fn deref(&self) -> &Rational {
match &self.inner {
Some(r) => r,
None => Rational::ZERO,
}
}
}
impl<Num: ToSmall> Assign<Num> for SmallRational {
#[inline]
fn assign(&mut self, src: Num) {
let mut mini = MiniInteger::from(src);
unsafe {
self.as_nonreallocating_rational()
.assign(mini.borrow_excl());
}
}
}
impl<Num: ToSmall> From<Num> for SmallRational {
fn from(src: Num) -> Self {
let mut mini = MiniInteger::from(src);
SmallRational {
inner: Some(Rational::from(mini.borrow_excl())),
phantom: PhantomData,
}
}
}
impl<Num: ToSmall, Den: ToSmall> Assign<(Num, Den)> for SmallRational {
fn assign(&mut self, src: (Num, Den)) {
assert!(!src.1.is_zero(), "division by zero");
let mut num = MiniInteger::from(src.0);
let mut den = MiniInteger::from(src.1);
unsafe {
self.as_nonreallocating_rational()
.assign((num.borrow_excl(), den.borrow_excl()));
}
}
}
impl<Num: ToSmall, Den: ToSmall> From<(Num, Den)> for SmallRational {
fn from(src: (Num, Den)) -> Self {
assert!(!src.1.is_zero(), "division by zero");
let mut num = MiniInteger::from(src.0);
let mut den = MiniInteger::from(src.1);
SmallRational {
inner: Some(Rational::from((num.borrow_excl(), den.borrow_excl()))),
phantom: PhantomData,
}
}
}
impl Assign<&Self> for SmallRational {
#[inline]
fn assign(&mut self, other: &Self) {
self.clone_from(other);
}
}
impl Assign for SmallRational {
#[inline]
fn assign(&mut self, other: Self) {
*self = other;
}
}
#[cfg(test)]
mod tests {
use crate::Assign;
use crate::rational::SmallRational;
#[test]
fn check_assign() {
let mut r = SmallRational::from((1, 2));
assert_eq!(*r, SmallRational::from((1, 2)));
r.assign(3);
assert_eq!(*r, 3);
let other = SmallRational::from((4, 5));
r.assign(&other);
assert_eq!(*r, SmallRational::from((4, 5)));
r.assign((6, 7));
assert_eq!(*r, SmallRational::from((6, 7)));
r.assign(other);
assert_eq!(*r, SmallRational::from((4, 5)));
}
fn swapped_parts(small: &SmallRational) -> bool {
unsafe {
let num = (*small.numer().as_raw()).d;
let den = (*small.denom().as_raw()).d;
num > den
}
}
#[test]
fn check_swapped_parts() {
let mut r = SmallRational::from((2, 3));
assert_eq!(*r, SmallRational::from((2, 3)));
assert_eq!(*r.clone(), *r);
let mut orig_swapped_parts = swapped_parts(&r);
unsafe {
r.as_nonreallocating_rational().recip_mut();
}
assert_eq!(*r, SmallRational::from((3, 2)));
assert_eq!(*r.clone(), *r);
assert!(swapped_parts(&r) != orig_swapped_parts);
unsafe {
r.assign_canonical(5, 7);
}
assert_eq!(*r, SmallRational::from((5, 7)));
assert_eq!(*r.clone(), *r);
orig_swapped_parts = swapped_parts(&r);
unsafe {
r.as_nonreallocating_rational().recip_mut();
}
assert_eq!(*r, SmallRational::from((7, 5)));
assert_eq!(*r.clone(), *r);
assert!(swapped_parts(&r) != orig_swapped_parts);
r.assign(2);
assert_eq!(*r, 2);
assert_eq!(*r.clone(), *r);
orig_swapped_parts = swapped_parts(&r);
unsafe {
r.as_nonreallocating_rational().recip_mut();
}
assert_eq!(*r, SmallRational::from((1, 2)));
assert_eq!(*r.clone(), *r);
assert!(swapped_parts(&r) != orig_swapped_parts);
r.assign((3, -5));
assert_eq!(*r, SmallRational::from((-3, 5)));
assert_eq!(*r.clone(), *r);
orig_swapped_parts = swapped_parts(&r);
unsafe {
r.as_nonreallocating_rational().recip_mut();
}
assert_eq!(*r, SmallRational::from((-5, 3)));
assert_eq!(*r.clone(), *r);
assert!(swapped_parts(&r) != orig_swapped_parts);
}
}