use crate::{
rel, Bit, Bit0, Bit1, Cons, Positive, Push, PushAfterMsb, ReplaceOnes, ShiftLowering,
ShiftRaising, Value,
};
use core::fmt::Debug;
use core::hash::Hash;
use core::ops::{BitAnd, BitOr, BitXor};
pub trait RecList: Copy + Clone + Default + PartialEq + Debug + Hash {
const LEN: usize;
const VALUES: Self;
fn len() -> usize {
Self::LEN
}
}
pub trait SameList: RecList {
type Item: Value;
fn item(self) -> Self::Item {
Default::default()
}
}
pub trait LengthSame<S>: RecList {}
pub trait PositiveAll: RecList {}
pub trait PositiveAny: RecList {}
impl PositiveAny for Bit1 {}
impl<B: Bit, V: Positive> PositiveAny for Cons<B, V> {}
impl<A: PositiveAny> PositiveAny for (Bit0, A) {}
impl<A: RecList> PositiveAny for (Bit1, A) {}
impl<B: Bit, V: Positive, A: RecList> PositiveAny for (Cons<B, V>, A) {}
pub trait BitAndAll<S>: RecList {
type Output: LengthSame<Self>;
fn bitand_all(self, _: &S) -> Self::Output {
Default::default()
}
}
pub trait BitOrAll<S>: RecList {
type Output: LengthSame<Self>;
fn bitor_all(self, _: &S) -> Self::Output {
Default::default()
}
}
pub trait BitXorAll<S>: RecList {
type Output: LengthSame<Self>;
fn bitxor_all(self, _: &S) -> Self::Output {
Default::default()
}
}
pub trait ShiftRaisingAll: RecList {
type Output: LengthSame<Self>;
fn shift_raising_all(self) -> Self::Output {
Default::default()
}
}
pub trait ShiftLoweringAll: RecList {
type Output: LengthSame<Self>;
type Lsb: LengthSame<Self> + BitList;
fn shift_lowering_all(self) -> Self::Output {
Default::default()
}
}
pub trait PushAll<B>: RecList {
type Output: LengthSame<Self>;
fn push_all(self, _: &B) -> Self::Output {
Default::default()
}
}
pub trait PushAfterMsbAll<B>: RecList {
type Output: LengthSame<Self>;
fn push_after_msb_all(self, _: &B) -> Self::Output {
Default::default()
}
}
pub trait ReplaceOnesAll<S>: RecList {
type Output: LengthSame<Self>;
fn replace_ones_all(self, _: &S) -> Self::Output {
Default::default()
}
}
pub trait BitAndFold: RecList {
type Output: Value;
fn bitand_fold(self) -> Self::Output {
Default::default()
}
}
pub trait BitOrFold: RecList {
type Output: Value;
fn bitor_fold(self) -> Self::Output {
Default::default()
}
}
pub trait BitXorFold: RecList {
type Output: Value;
fn bitxor_fold(self) -> Self::Output {
Default::default()
}
}
pub trait Compare: RecList {
type MAX: Value;
type MIN: Value;
fn max(&self) -> Self::MAX {
Default::default()
}
fn min(&self) -> Self::MIN {
Default::default()
}
}
pub trait Transpose: Compare {
type Output: RecList;
fn transpose(self) -> Self::Output {
Default::default()
}
}
impl<T: TransposeImpl<()>> Transpose for T {
type Output = T::Output;
}
#[doc(hidden)]
pub trait TransposeImpl<Acc = ()>: Compare {
type Output: RecList;
}
impl<A, TOut> TransposeImpl<()> for A
where
A: TransposeImpl<<Self as Compare>::MAX, Output = TOut>,
TOut: RecList,
{
type Output = <Self as TransposeImpl<<Self as Compare>::MAX>>::Output;
}
impl<A, TVL0, TVL> TransposeImpl<Bit1> for A
where
A: ShiftLoweringAll<Lsb = TVL0> + Compare,
TVL0: BitList<Val = TVL>,
TVL: RecList,
{
type Output = TVL;
}
impl<B: Bit, S: Positive, A, TVL, TVH> TransposeImpl<Cons<B, S>> for A
where
A: ShiftLoweringAll + Compare,
<A as ShiftLoweringAll>::Output: TransposeImpl<S, Output = TVH>,
<A as ShiftLoweringAll>::Lsb: BitList<Val = TVL>,
(TVL, TVH): RecList,
{
type Output = (TVL, TVH);
}
pub trait BitList: RecList {
type Val: Value;
}
impl BitList for Bit0 {
type Val = Bit0;
}
impl BitList for Bit1 {
type Val = Bit1;
}
impl<B: Bit, A: BitList> BitList for (B, A)
where
(B, A): RecList,
(B, A::Val): Normalize,
{
type Val = <(B, A::Val) as Normalize>::Output;
}
#[doc(hidden)]
pub trait Normalize {
type Output: Value;
}
impl<B: Bit> Normalize for (B, Bit0) {
type Output = B;
}
impl<B: Bit> Normalize for (B, Bit1) {
type Output = Cons<B, Bit1>;
}
impl<B: Bit, B0: Bit, V0: Positive> Normalize for (B, Cons<B0, V0>) {
type Output = Cons<B, Cons<B0, V0>>;
}
macro_rules! impl_all {
(@all [$($param0:ident),*] $trait:ident, $inner_trait:ident [$($param:ident : $tparam:ident),*] $obj:ty ) => {
impl<$($param0,)*$($param: $tparam),*> $trait<$($param0),*> for $obj
where
$obj: $inner_trait<$($param0),*>,
<$obj as $inner_trait<$($param0),*>>::Output: LengthSame<$obj> + Default,
{
type Output = <$obj as $inner_trait<$($param0),*>>::Output;
}
impl<$($param0,)*$($param: $tparam,)* A> $trait<$($param0),*> for ($obj, A)
where
$obj: $inner_trait<$($param0,)*>,
A: $trait<$($param0),*>,
(<$obj as $inner_trait<$($param0),*>>::Output, <A as $trait<$($param0),*>>::Output): LengthSame<($obj, A)> + Default,
{
type Output = (<$obj as $inner_trait<$($param0),*>>::Output, <A as $trait<$($param0),*>>::Output);
}
};
(@fold $trait:ident, $inner_trait:ident [$($param:ident : $tparam:ident),*] $obj:ty ) => {
impl<$($param: $tparam),*> $trait for $obj
{
type Output = $obj;
}
impl<$($param: $tparam,)* A> $trait for ($obj, A)
where
$obj: $inner_trait<<A as $trait>::Output>,
A: $trait,
<$obj as $inner_trait<<A as $trait>::Output>>::Output: Value,
{
type Output = <$obj as $inner_trait<<A as $trait>::Output>>::Output;
}
};
([$($param:ident : $tparam:ident),*] $obj:ty ) => {
impl<$($param: $tparam),*> RecList for $obj {
const LEN: usize = 1;
const VALUES: Self = <Self as Value>::VALUE;
}
impl<A: RecList$(,$param: $tparam)*> RecList for ($obj, A) {
const LEN: usize = <A as RecList>::LEN + 1;
const VALUES: Self = (<$obj as Value>::VALUE, A::VALUES);
}
impl<$($param: $tparam),*> SameList for $obj
where $obj: Value,
{
type Item = $obj;
}
impl<A$(,$param: $tparam)*> SameList for ($obj, A)
where
A: SameList<Item = $obj>,
$obj: Value,
{
type Item = $obj;
}
impl<$($param: $tparam),*> ShiftLoweringAll for $obj
where
$obj: ShiftLowering,
<$obj as ShiftLowering>::Lsb: BitList + LengthSame<Self>,
<$obj as ShiftLowering>::Output: LengthSame<Self>,
{
type Lsb = <$obj as ShiftLowering>::Lsb;
type Output = <$obj as ShiftLowering>::Output;
}
impl<A$(,$param: $tparam)*> ShiftLoweringAll for ($obj, A)
where
(<$obj as ShiftLowering>::Lsb, A::Lsb): BitList + LengthSame<Self>,
(<$obj as ShiftLowering>::Output, A::Output): LengthSame<Self>,
A: ShiftLoweringAll,
$obj: ShiftLowering,
{
type Lsb = (<$obj as ShiftLowering>::Lsb, A::Lsb);
type Output = (<$obj as ShiftLowering>::Output, A::Output);
}
impl<$($param: $tparam),*> Compare for $obj {
type MAX = $obj;
type MIN = $obj;
}
impl<A: Compare$(,$param: $tparam)*> Compare for ($obj, A)
where
($obj, A): RecList,
<A as Compare>::MAX: rel::Compare<$obj>,
<A as Compare>::MIN: rel::Compare<$obj>,
{
type MAX = <<A as Compare>::MAX as rel::Compare<$obj>>::MAX;
type MIN = <<A as Compare>::MIN as rel::Compare<$obj>>::MIN;
}
impl_all!(@all [S] BitAndAll, BitAnd [$($param: $tparam),*] $obj);
impl_all!(@all [S] BitOrAll, BitOr [$($param: $tparam),*] $obj);
impl_all!(@all [S] BitXorAll, BitXor [$($param: $tparam),*] $obj);
impl_all!(@all [] ShiftRaisingAll, ShiftRaising [$($param: $tparam),*] $obj);
impl_all!(@all [Bi] PushAll, Push [$($param: $tparam),*] $obj);
impl_all!(@all [Bi] PushAfterMsbAll, PushAfterMsb [$($param: $tparam),*] $obj);
impl_all!(@all [Si] ReplaceOnesAll, ReplaceOnes [$($param: $tparam),*] $obj);
impl_all!(@fold BitAndFold, BitAnd [$($param: $tparam),*] $obj);
impl_all!(@fold BitOrFold, BitOr [$($param: $tparam),*] $obj);
impl_all!(@fold BitXorFold, BitXor [$($param: $tparam),*] $obj);
};
}
macro_rules! impl_same {
(@
[$($param0:ident : $tparam0:ident),*] $obj0:ty;
[$($param1:ident : $tparam1:ident),*] $obj1:ty
) => {
impl<$($param0: $tparam0,)* $($param1: $tparam1),*> LengthSame<$obj0> for $obj1 {}
impl<$($param0: $tparam0,)* $($param1: $tparam1,)* B: RecList, A: LengthSame<B>> LengthSame<($obj0, A)> for ($obj1, B) {}
};
(
[$($param0:ident : $tparam0:ident),*] $obj0:ty
) => {
impl_same!(@ [$($param0 : $tparam0),*] $obj0; [] Bit0);
impl_same!(@ [$($param0 : $tparam0),*] $obj0; [] Bit1);
impl_same!(@ [$($param0 : $tparam0),*] $obj0; [B1: Bit, V1: Positive] Cons<B1, V1>);
};
}
macro_rules! impl_positive_all {
([$($param:ident : $tparam:ident),*] $obj:ty ) => {
impl<$($param: $tparam),*> PositiveAll for $obj
where
$obj: Positive
{}
impl<A: PositiveAll$(,$param: $tparam)*> PositiveAll for ($obj, A)
where
$obj: Positive
{}
};
}
impl_all!([] Bit0);
impl_all!([] Bit1);
impl_all!([B: Bit, V: Positive] Cons<B, V>);
impl_positive_all!([] Bit1);
impl_positive_all!([B: Bit, V: Positive] Cons<B, V>);
impl_same!([] Bit0);
impl_same!([] Bit1);
impl_same!([B0: Bit, V0: Positive] Cons<B0, V0>);