use core::ops::{Neg, Not, Sub};
use super::basic::{Z0, N1, P1, B0, B1, Integer, NonZero};
use super::add1::Add1;
use super::sub1::Sub1;
use super::standardization::{IfB0, IfB1};
use crate::variable::{Var,Numeric};
pub trait SubWithBorrow<Rhs> {
type Output;
}
impl<I:NonZero + Neg> SubWithBorrow<I> for P1 {
type Output = I::Output;
}
impl<I: NonZero + Not> SubWithBorrow<I> for N1
where
<I as Not>::Output:Sub1,
{
type Output = <I::Output as Sub1>::Output;
}
impl<H: NonZero + Sub1> SubWithBorrow<P1> for B0<H>
where
H::Output: IfB0,
{
type Output = <H::Output as IfB0>::Output;
}
impl<H: NonZero> SubWithBorrow<N1> for B0<H>
{
type Output = Self;
}
impl<H1: NonZero + SubWithBorrow<H2>, H2: NonZero> SubWithBorrow<B0<H2>> for B0<H1>
where
H1::Output: IfB1,
{
type Output = <H1::Output as IfB1>::Output;
}
impl<H1: NonZero + SubWithBorrow<H2>, H2: NonZero> SubWithBorrow<B1<H2>> for B0<H1>
where
<H1 as SubWithBorrow<H2>>::Output: IfB0,
{
type Output = <H1::Output as IfB0>::Output;
}
impl<H: NonZero + Sub1> SubWithBorrow<P1> for B1<H>
where
H::Output: IfB1,
{
type Output = <H::Output as IfB1>::Output;
}
impl<H: NonZero> SubWithBorrow<N1> for B1<H>
{
type Output = Self;
}
impl<H1: NonZero + Sub<H2>, H2: NonZero> SubWithBorrow<B0<H2>> for B1<H1>
where
<H1 as Sub<H2>>::Output: IfB0,
{
type Output = <H1::Output as IfB0>::Output;
}
impl<H1: NonZero + SubWithBorrow<H2>, H2: NonZero> SubWithBorrow<B1<H2>> for B1<H1>
where
<H1 as SubWithBorrow<H2>>::Output: IfB1,
{
type Output = <H1::Output as IfB1>::Output;
}
impl<I: Integer + Neg> Sub<I> for Z0 {
type Output = I::Output;
#[inline(always)]
fn sub(self, i: I) -> Self::Output {
-i
}
}
impl<I: Integer + Sub1> Sub<I> for P1
where
<I as Sub1>::Output: Neg,
{
type Output = <I::Output as Neg>::Output;
#[inline(always)]
fn sub(self, i: I) -> Self::Output {
-i.sub1()
}
}
impl<I: Integer + Add1> Sub<I> for N1
where
<I as Add1>::Output: Neg,
{
type Output = <I::Output as Neg>::Output;
#[inline(always)]
fn sub(self, i: I) -> Self::Output {
-i.add1()
}
}
impl<H: NonZero> Sub<Z0> for B0<H> {
type Output = Self;
#[inline(always)]
fn sub(self, _: Z0) -> Self::Output {
self
}
}
impl<H: NonZero> Sub<P1> for B0<H>
where
B0<H>:Sub1,
{
type Output = <B0<H> as Sub1>::Output;
#[inline(always)]
fn sub(self, _: P1) -> Self::Output {
self.sub1()
}
}
impl<H: NonZero> Sub<N1> for B0<H>
where
B0<H>:Add1,
{
type Output = <B0<H> as Add1>::Output;
#[inline(always)]
fn sub(self, _: N1) -> Self::Output {
self.add1()
}
}
impl<H1: NonZero + Sub<H2>, H2: NonZero> Sub<B0<H2>> for B0<H1>
where
<H1 as Sub<H2>>::Output: IfB0,
{
type Output = <H1::Output as IfB0>::Output;
#[inline(always)]
fn sub(self, _: B0<H2>) -> Self::Output {
<<H1 as Sub<H2>>::Output as IfB0>::b0()
}
}
impl<H1: NonZero + SubWithBorrow<H2>, H2: NonZero> Sub<B1<H2>> for B0<H1>
where
<H1 as SubWithBorrow<H2>>::Output: IfB1,
{
type Output = <H1::Output as IfB1>::Output;
#[inline(always)]
fn sub(self, _: B1<H2>) -> Self::Output {
<<H1 as SubWithBorrow<H2>>::Output as IfB1>::b1()
}
}
impl<H: NonZero> Sub<Z0> for B1<H> {
type Output = Self;
#[inline(always)]
fn sub(self, _: Z0) -> Self::Output {
self
}
}
impl<H: NonZero> Sub<P1> for B1<H>
where
B1<H>:Sub1,
{
type Output = <B1<H> as Sub1>::Output;
#[inline(always)]
fn sub(self, _: P1) -> Self::Output {
self.sub1()
}
}
impl<H: NonZero + Add1> Sub<N1> for B1<H>
where
B1<H>: Add1,
{
type Output = <B1<H> as Add1>::Output;
#[inline(always)]
fn sub(self, _: N1) -> Self::Output {
self.add1()
}
}
impl<H1: NonZero + Sub<H2>, H2: NonZero> Sub<B0<H2>> for B1<H1>
where
Diff<H1, H2>: IfB1,
{
type Output = <H1::Output as IfB1>::Output;
#[inline(always)]
fn sub(self, _: B0<H2>) -> Self::Output {
<Diff<H1, H2> as IfB1>::b1()
}
}
impl<H1: NonZero + Sub<H2>, H2: NonZero> Sub<B1<H2>> for B1<H1>
where
Diff<H1, H2>: IfB0,
{
type Output = <H1::Output as IfB0>::Output;
#[inline(always)]
fn sub(self, _: B1<H2>) -> Self::Output {
<Diff<H1, H2> as IfB0>::b0()
}
}
pub type Diff<A, B> = <A as Sub<B>>::Output;
impl<T: Numeric + Neg> Sub<Var<T>> for Z0 {
type Output = Var<T>;
#[inline(always)]
fn sub(self, rhs: Var<T>) -> Self::Output {
Var(-rhs.0)
}
}
impl<T: Numeric> Sub<Var<T>> for P1{
type Output = Var<T>;
#[inline(always)]
fn sub(self, rhs: Var<T>) -> Self::Output {
Var(1.into()) - rhs
}
}
impl<T: Numeric> Sub<Var<T>> for N1
where
Var<T>: Neg,
<Var<T> as Neg>::Output: Sub1,
{
type Output = Var<T>;
#[inline(always)]
fn sub(self, rhs: Var<T>) -> Self::Output {
Var((-1).into()) - rhs
}
}
impl<T: Numeric, H: NonZero> Sub<Var<T>> for B0<H>
where
B0<H>:Integer
{
type Output = Var<T>;
#[inline(always)]
fn sub(self, rhs: Var<T>) -> Self::Output {
Var(T::from(B0::<H>::to_i32()) - rhs.0)
}
}
impl<T: Numeric, H: NonZero> Sub<Var<T>> for B1<H>
where
B1<H>:Integer
{
type Output = Var<T>;
#[inline(always)]
fn sub(self, rhs: Var<T>) -> Self::Output {
Var(T::from(B1::<H>::to_i32()) - rhs.0)
}
}