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