pub trait Binary<T, U> {
type Output;
fn call(t: T, u: U) -> Self::Output;
}
pub enum Pair {}
impl<T, U> Binary<T, U> for Pair {
type Output = (T, U);
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { (t, u) }
}
pub enum Add {}
impl<T, U> Binary<T, U> for Add where T: std::ops::Add<U> {
type Output = T::Output;
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { t.add(u) }
}
pub enum Sub {}
impl<T, U> Binary<T, U> for Sub where T: std::ops::Sub<U> {
type Output = T::Output;
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { t.sub(u) }
}
pub enum Mul {}
impl<T, U> Binary<T, U> for Mul where T: std::ops::Mul<U> {
type Output = T::Output;
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { t.mul(u) }
}
pub enum Div {}
impl<T, U> Binary<T, U> for Div where T: std::ops::Div<U> {
type Output = T::Output;
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { t.div(u) }
}
pub enum Rem {}
impl<T, U> Binary<T, U> for Rem where T: std::ops::Rem<U> {
type Output = T::Output;
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { t.rem(u) }
}
pub enum BitAnd {}
impl<T, U> Binary<T, U> for BitAnd where T: std::ops::BitAnd<U> {
type Output = T::Output;
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { t.bitand(u) }
}
pub enum BitOr {}
impl<T, U> Binary<T, U> for BitOr where T: std::ops::BitOr<U> {
type Output = T::Output;
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { t.bitor(u) }
}
pub enum BitXor {}
impl<T, U> Binary<T, U> for BitXor where T: std::ops::BitXor<U> {
type Output = T::Output;
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { t.bitxor(u) }
}
pub enum Shl {}
impl<T, U> Binary<T, U> for Shl where T: std::ops::Shl<U> {
type Output = T::Output;
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { t.shl(u) }
}
pub enum Shr {}
impl<T, U> Binary<T, U> for Shr where T: std::ops::Shr<U> {
type Output = T::Output;
#[inline(always)]
fn call(t: T, u: U) -> Self::Output { t.shr(u) }
}
#[macro_export]
macro_rules! impl_op_for_view {
($op:ident for $v:ident<$($a:lifetime,)? $($param:ident$(: $bound:path)?),*> { $method:ident }) => {
impl<$($a,)? RHS: $crate::View, $($param$(: $bound)?),*> std::ops::$op<RHS> for $v<$($a,)? $($param),*> where
Self: $crate::View,
<Self as View>::I: $crate::Broadcast<RHS::I>,
<Self as View>::T: std::ops::$op<RHS::T>,
{
type Output = $crate::view::Zip<Self, RHS, $crate::ops::$op>;
fn $method(self, other: RHS) -> Self::Output { self.binary(other) }
}
};
}
#[macro_export]
macro_rules! impl_ops_for_view {
($v:ident<$($a:lifetime,)? $($param:ident$(: $bound:path)?),*>) => {
$crate::impl_op_for_view! { Add for $v<$($a,)? $($param$(: $bound)?),*> { add } }
$crate::impl_op_for_view! { Sub for $v<$($a,)? $($param$(: $bound)?),*> { sub } }
$crate::impl_op_for_view! { Mul for $v<$($a,)? $($param$(: $bound)?),*> { mul } }
$crate::impl_op_for_view! { Div for $v<$($a,)? $($param$(: $bound)?),*> { div } }
$crate::impl_op_for_view! { Rem for $v<$($a,)? $($param$(: $bound)?),*> { rem } }
$crate::impl_op_for_view! { BitAnd for $v<$($a,)? $($param$(: $bound)?),*> { bitand } }
$crate::impl_op_for_view! { BitOr for $v<$($a,)? $($param$(: $bound)?),*> { bitor } }
$crate::impl_op_for_view! { BitXor for $v<$($a,)? $($param$(: $bound)?),*> { bitxor } }
$crate::impl_op_for_view! { Shl for $v<$($a,)? $($param$(: $bound)?),*> { shl } }
$crate::impl_op_for_view! { Shr for $v<$($a,)? $($param$(: $bound)?),*> { shr } }
};
}
#[macro_export]
macro_rules! impl_ops_for_memoryview {
($v:ident<$($a:lifetime,)? $($param:ident$(: $bound:path)?),*>) => {
impl<$($a,)? $($param$(: $bound)?),*> std::ops::Index<<Self as View>::I> for $v<$($a,)? $($param),*> where
Self: $crate::ViewRef,
{
type Output = <Self as View>::T;
fn index(&self, index: <Self as View>::I) -> &Self::Output { self.at_ref(index) }
}
impl<$($a,)? $($param$(: $bound)?),*> std::ops::IndexMut<<Self as View>::I> for $v<$($a,)? $($param),*> where
Self: $crate::ViewMut,
{
fn index_mut(&mut self, index: <Self as View>::I) -> &mut Self::Output { self.at_mut(index) }
}
};
}