use std::marker::PhantomData;
use ::bit::{Bit, B1, B0};
use ::uint::{Unsigned, UInt, UTerm};
pub trait Trim {
type Output;
}
pub trait TrimTrailingZeros {
type Output;
}
pub trait Invert {
type Output;
}
pub trait PrivateInvert<Rhs> {
type Output;
}
pub trait PrivateSizeOf {
type Output;
}
pub struct InvertedUTerm;
pub struct InvertedUInt<IU: InvertedUnsigned, B: Bit> {
_marker: PhantomData<(IU, B)>
}
pub trait PrivateAnd<Rhs = Self> {
type Output;
}
pub trait PrivateXor<Rhs = Self> {
type Output;
}
pub trait PrivateSub<Rhs = Self> {
type Output;
}
pub trait PrivateIntegerAdd<C, N> {
type Output;
}
pub trait PrivatePow<Y, N> {
type Output;
}
pub trait PrivateDiv<C, I, Q, Divisor> {
type Output;
}
pub trait PrivateDivFirstStep<C, Divisor> {
type Output;
}
pub trait ShiftDiff<Rhs> {
type Output;
}
pub trait BitDiff<Rhs> {
type Output;
}
pub trait InvertedUnsigned {
fn to_u64() -> u64;
}
impl InvertedUnsigned for InvertedUTerm {
fn to_u64() -> u64 { 0 }
}
impl<IU: InvertedUnsigned, B: Bit> InvertedUnsigned for InvertedUInt<IU, B> {
fn to_u64() -> u64 {
B::to_u8() as u64 | IU::to_u64() << 1
}
}
impl Invert for UTerm {
type Output = InvertedUTerm;
}
impl<U: Unsigned, B: Bit> Invert for UInt<U, B>
where U: PrivateInvert<InvertedUInt<InvertedUTerm, B>>
{
type Output = <U as PrivateInvert<InvertedUInt<InvertedUTerm, B>>>::Output;
}
impl<IU: InvertedUnsigned> PrivateInvert<IU> for UTerm {
type Output = IU;
}
impl<IU: InvertedUnsigned, U: Unsigned, B: Bit> PrivateInvert<IU> for UInt<U, B>
where U: PrivateInvert<InvertedUInt<IU, B>>
{
type Output = <U as PrivateInvert<InvertedUInt<IU, B>>>::Output;
}
#[test]
fn test_inversion() {
type Test4 = <::uint::U4 as Invert>::Output;
type Test5 = <::uint::U5 as Invert>::Output;
type Test12 = <::uint::U12 as Invert>::Output;
type Test16 = <::uint::U16 as Invert>::Output;
assert_eq!(1, <Test4 as InvertedUnsigned>::to_u64());
assert_eq!(5, <Test5 as InvertedUnsigned>::to_u64());
assert_eq!(3, <Test12 as InvertedUnsigned>::to_u64());
assert_eq!(1, <Test16 as InvertedUnsigned>::to_u64());
}
impl Invert for InvertedUTerm {
type Output = UTerm;
}
impl<IU: InvertedUnsigned, B: Bit> Invert for InvertedUInt<IU, B>
where IU: PrivateInvert<UInt<UTerm, B>>
{
type Output = <IU as PrivateInvert<UInt<UTerm, B>>>::Output;
}
impl<U: Unsigned> PrivateInvert<U> for InvertedUTerm {
type Output = U;
}
impl<U: Unsigned, IU: InvertedUnsigned, B: Bit> PrivateInvert<U> for InvertedUInt<IU, B>
where IU: PrivateInvert<UInt<U, B>>
{
type Output = <IU as PrivateInvert<UInt<U, B>>>::Output;
}
#[test]
fn test_double_inversion() {
type Test4 = <<::uint::U4 as Invert>::Output as Invert>::Output;
type Test5 = <<::uint::U5 as Invert>::Output as Invert>::Output;
type Test12 = <<::uint::U12 as Invert>::Output as Invert>::Output;
type Test16 = <<::uint::U16 as Invert>::Output as Invert>::Output;
assert_eq!(4, <Test4 as Unsigned>::to_u64());
assert_eq!(5, <Test5 as Unsigned>::to_u64());
assert_eq!(12, <Test12 as Unsigned>::to_u64());
assert_eq!(16, <Test16 as Unsigned>::to_u64());
}
impl TrimTrailingZeros for InvertedUTerm {
type Output = InvertedUTerm;
}
impl<IU: InvertedUnsigned> TrimTrailingZeros for InvertedUInt<IU, B1> {
type Output = Self;
}
impl<IU: InvertedUnsigned> TrimTrailingZeros for InvertedUInt<IU, B0>
where IU: TrimTrailingZeros
{
type Output = <IU as TrimTrailingZeros>::Output;
}
impl<U: Unsigned> Trim for U
where U: Invert,
<U as Invert>::Output: TrimTrailingZeros,
<<U as Invert>::Output as TrimTrailingZeros>::Output: Invert
{
type Output = <<<U as Invert>::Output as TrimTrailingZeros>::Output as Invert>::Output;
}
pub trait PrivateCmp<Rhs, SoFar> {
type Output;
}