use super::CheckedUnsignedAbs::{Negative, Positive};
use super::Sign::{self, Minus, NoSign, Plus};
use super::{BigInt, UnsignedAbs};
use crate::{IsizePromotion, UsizePromotion};
use core::iter::Product;
use core::ops::{Mul, MulAssign};
use num_traits::{CheckedMul, One, Zero};
impl Mul<Sign> for Sign {
type Output = Sign;
#[inline]
fn mul(self, other: Sign) -> Sign {
match (self, other) {
(NoSign, _) | (_, NoSign) => NoSign,
(Plus, Plus) | (Minus, Minus) => Plus,
(Plus, Minus) | (Minus, Plus) => Minus,
}
}
}
macro_rules! impl_mul {
($(impl<$($a:lifetime),*> Mul<$Other:ty> for $Self:ty;)*) => {$(
impl<$($a),*> Mul<$Other> for $Self {
type Output = BigInt;
#[inline]
fn mul(self, other: $Other) -> BigInt {
let BigInt { data: x, .. } = self;
let BigInt { data: y, .. } = other;
BigInt::from_biguint(self.sign * other.sign, x * y)
}
}
)*}
}
impl_mul! {
impl<> Mul<BigInt> for BigInt;
impl<'b> Mul<&'b BigInt> for BigInt;
impl<'a> Mul<BigInt> for &'a BigInt;
impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt;
}
macro_rules! impl_mul_assign {
($(impl<$($a:lifetime),*> MulAssign<$Other:ty> for BigInt;)*) => {$(
impl<$($a),*> MulAssign<$Other> for BigInt {
#[inline]
fn mul_assign(&mut self, other: $Other) {
let BigInt { data: y, .. } = other;
self.data *= y;
if self.data.is_zero() {
self.sign = NoSign;
} else {
self.sign = self.sign * other.sign;
}
}
}
)*}
}
impl_mul_assign! {
impl<> MulAssign<BigInt> for BigInt;
impl<'a> MulAssign<&'a BigInt> for BigInt;
}
promote_all_scalars!(impl Mul for BigInt, mul);
promote_all_scalars_assign!(impl MulAssign for BigInt, mul_assign);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u32> for BigInt, mul);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u64> for BigInt, mul);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u128> for BigInt, mul);
impl Mul<u32> for BigInt {
type Output = BigInt;
#[inline]
fn mul(self, other: u32) -> BigInt {
BigInt::from_biguint(self.sign, self.data * other)
}
}
impl MulAssign<u32> for BigInt {
#[inline]
fn mul_assign(&mut self, other: u32) {
self.data *= other;
if self.data.is_zero() {
self.sign = NoSign;
}
}
}
impl Mul<u64> for BigInt {
type Output = BigInt;
#[inline]
fn mul(self, other: u64) -> BigInt {
BigInt::from_biguint(self.sign, self.data * other)
}
}
impl MulAssign<u64> for BigInt {
#[inline]
fn mul_assign(&mut self, other: u64) {
self.data *= other;
if self.data.is_zero() {
self.sign = NoSign;
}
}
}
impl Mul<u128> for BigInt {
type Output = BigInt;
#[inline]
fn mul(self, other: u128) -> BigInt {
BigInt::from_biguint(self.sign, self.data * other)
}
}
impl MulAssign<u128> for BigInt {
#[inline]
fn mul_assign(&mut self, other: u128) {
self.data *= other;
if self.data.is_zero() {
self.sign = NoSign;
}
}
}
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i32> for BigInt, mul);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i64> for BigInt, mul);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i128> for BigInt, mul);
impl Mul<i32> for BigInt {
type Output = BigInt;
#[inline]
fn mul(self, other: i32) -> BigInt {
match other.checked_uabs() {
Positive(u) => self * u,
Negative(u) => -self * u,
}
}
}
impl MulAssign<i32> for BigInt {
#[inline]
fn mul_assign(&mut self, other: i32) {
match other.checked_uabs() {
Positive(u) => *self *= u,
Negative(u) => {
self.sign = -self.sign;
self.data *= u;
}
}
}
}
impl Mul<i64> for BigInt {
type Output = BigInt;
#[inline]
fn mul(self, other: i64) -> BigInt {
match other.checked_uabs() {
Positive(u) => self * u,
Negative(u) => -self * u,
}
}
}
impl MulAssign<i64> for BigInt {
#[inline]
fn mul_assign(&mut self, other: i64) {
match other.checked_uabs() {
Positive(u) => *self *= u,
Negative(u) => {
self.sign = -self.sign;
self.data *= u;
}
}
}
}
impl Mul<i128> for BigInt {
type Output = BigInt;
#[inline]
fn mul(self, other: i128) -> BigInt {
match other.checked_uabs() {
Positive(u) => self * u,
Negative(u) => -self * u,
}
}
}
impl MulAssign<i128> for BigInt {
#[inline]
fn mul_assign(&mut self, other: i128) {
match other.checked_uabs() {
Positive(u) => *self *= u,
Negative(u) => {
self.sign = -self.sign;
self.data *= u;
}
}
}
}
impl CheckedMul for BigInt {
#[inline]
fn checked_mul(&self, v: &BigInt) -> Option<BigInt> {
Some(self.mul(v))
}
}
impl_product_iter_type!(BigInt);