use crate::{boolean::Boolean, tuple::FirstOf};
use typenum::{
Eq, False, Gr, GrEq, IsEqual, IsGreater, IsGreaterOrEqual, IsLess, IsLessOrEqual, Le, LeEq,
NonZero, True, B0, U0, Z0,
};
pub trait If<Cond> {
type Output;
}
pub type IfOutput<Output, Cond> = <Output as If<Cond>>::Output;
impl<Cond, Output> If<Cond> for Output {
type Output = FirstOf<(Output, Cond)>;
}
pub trait IfSame<Lhs, Rhs> {
type Output;
}
pub type IfSameOutput<Output, Lhs, Rhs> = <Output as IfSame<Lhs, Rhs>>::Output;
impl<Same, Output> IfSame<Same, Same> for Output {
type Output = Output;
}
pub trait IfPredicate<Cond>
where
Cond: Boolean,
{
type Output;
}
pub type IfPredicateOutput<Output, Cond> = <Output as IfPredicate<Cond>>::Output;
impl<Output> IfPredicate<True> for Output {
type Output = Output;
}
pub trait IfNotPredicate<Cond>
where
Cond: Boolean,
{
type Output;
}
pub type IfNotPredicateOutput<Output, Cond> = <Output as IfNotPredicate<Cond>>::Output;
impl<Output> IfNotPredicate<False> for Output {
type Output = Output;
}
pub trait IfElsePredicate<Cond, ElseOutput>
where
Cond: Boolean,
{
type Output;
}
pub type IfElsePredicateOutput<TrueOutput, Cond, FalseOutput> =
<TrueOutput as IfElsePredicate<Cond, FalseOutput>>::Output;
impl<TrueOutput, FalseOutput> IfElsePredicate<True, FalseOutput> for TrueOutput {
type Output = TrueOutput;
}
impl<TrueOutput, FalseOutput> IfElsePredicate<False, FalseOutput> for TrueOutput {
type Output = FalseOutput;
}
pub trait IfLess<Lhs, Rhs> {
type Output;
}
pub type IfLessOutput<Output, Lhs, Rhs> = <Output as IfLess<Lhs, Rhs>>::Output;
impl<Lhs, Rhs, Output> IfLess<Lhs, Rhs> for Output
where
Lhs: IsLess<Rhs>,
Output: IfPredicate<Le<Lhs, Rhs>>,
Le<Lhs, Rhs>: Boolean,
{
type Output = IfPredicateOutput<Output, Le<Lhs, Rhs>>;
}
pub trait IfElseLess<Lhs, Rhs, Else> {
type Output;
}
pub type IfElseLessOutput<Output, Lhs, Rhs, Else> = <Output as IfElseLess<Lhs, Rhs, Else>>::Output;
impl<Lhs, Rhs, Output, Else> IfElseLess<Lhs, Rhs, Else> for Output
where
Lhs: IsLess<Rhs>,
Output: IfElsePredicate<Le<Lhs, Rhs>, Else>,
Le<Lhs, Rhs>: Boolean,
{
type Output = IfElsePredicateOutput<Output, Le<Lhs, Rhs>, Else>;
}
pub trait IfLessOrEqual<Lhs, Rhs> {
type Output;
}
pub type IfLessOrEqualOutput<Output, Lhs, Rhs> = <Output as IfLessOrEqual<Lhs, Rhs>>::Output;
impl<Lhs, Rhs, Output> IfLessOrEqual<Lhs, Rhs> for Output
where
Lhs: IsLessOrEqual<Rhs>,
Output: IfPredicate<LeEq<Lhs, Rhs>>,
LeEq<Lhs, Rhs>: Boolean,
{
type Output = IfPredicateOutput<Output, LeEq<Lhs, Rhs>>;
}
pub trait IfElseLessOrEqual<Lhs, Rhs, Else> {
type Output;
}
pub type IfElseLessOrEqualOutput<Output, Lhs, Rhs, Else> =
<Output as IfElseLessOrEqual<Lhs, Rhs, Else>>::Output;
impl<Lhs, Rhs, Output, Else> IfElseLessOrEqual<Lhs, Rhs, Else> for Output
where
Lhs: IsLess<Rhs>,
Output: IfElsePredicate<Le<Lhs, Rhs>, Else>,
Le<Lhs, Rhs>: Boolean,
{
type Output = IfElsePredicateOutput<Output, Le<Lhs, Rhs>, Else>;
}
pub trait IfGreater<Lhs, Rhs> {
type Output;
}
pub type IfGreaterOutput<Output, Lhs, Rhs> = <Output as IfGreater<Lhs, Rhs>>::Output;
impl<Lhs, Rhs, Output> IfGreater<Lhs, Rhs> for Output
where
Lhs: IsGreater<Rhs>,
Output: IfPredicate<Gr<Lhs, Rhs>>,
Gr<Lhs, Rhs>: Boolean,
{
type Output = IfPredicateOutput<Output, Gr<Lhs, Rhs>>;
}
pub trait IfElseGreater<Lhs, Rhs, Else> {
type Output;
}
pub type IfElseGreaterOutput<Output, Lhs, Rhs, Else> =
<Output as IfElseGreater<Lhs, Rhs, Else>>::Output;
impl<Lhs, Rhs, Output, Else> IfElseGreater<Lhs, Rhs, Else> for Output
where
Lhs: IsLess<Rhs>,
Output: IfElsePredicate<Le<Lhs, Rhs>, Else>,
Le<Lhs, Rhs>: Boolean,
{
type Output = IfElsePredicateOutput<Output, Le<Lhs, Rhs>, Else>;
}
pub trait IfGreaterOrEqual<Lhs, Rhs> {
type Output;
}
pub type IfGreaterOrEqualOutput<Output, Lhs, Rhs> = <Output as IfGreaterOrEqual<Lhs, Rhs>>::Output;
impl<Lhs, Rhs, Output> IfGreaterOrEqual<Lhs, Rhs> for Output
where
Lhs: IsGreaterOrEqual<Rhs>,
Output: IfPredicate<GrEq<Lhs, Rhs>>,
GrEq<Lhs, Rhs>: Boolean,
{
type Output = IfPredicateOutput<Output, GrEq<Lhs, Rhs>>;
}
pub trait IfElseGreaterOrEqual<Lhs, Rhs, Else> {
type Output;
}
pub type IfElseGreaterOrEqualOutput<Output, Lhs, Rhs, Else> =
<Output as IfElseGreaterOrEqual<Lhs, Rhs, Else>>::Output;
impl<Lhs, Rhs, Output, Else> IfElseGreaterOrEqual<Lhs, Rhs, Else> for Output
where
Lhs: IsLess<Rhs>,
Output: IfElsePredicate<Le<Lhs, Rhs>, Else>,
Le<Lhs, Rhs>: Boolean,
{
type Output = IfElsePredicateOutput<Output, Le<Lhs, Rhs>, Else>;
}
pub trait IfEqual<Lhs, Rhs> {
type Output;
}
pub type IfEqualOutput<Output, Lhs, Rhs> = <Output as IfEqual<Lhs, Rhs>>::Output;
impl<Lhs, Rhs, Output> IfEqual<Lhs, Rhs> for Output
where
Lhs: IsEqual<Rhs>,
Output: IfPredicate<Eq<Lhs, Rhs>>,
Eq<Lhs, Rhs>: Boolean,
{
type Output = IfPredicateOutput<Output, Eq<Lhs, Rhs>>;
}
pub trait IfElseEqual<Lhs, Rhs, Else> {
type Output;
}
pub type IfElseEqualOutput<Output, Lhs, Rhs, Else> =
<Output as IfElseEqual<Lhs, Rhs, Else>>::Output;
impl<Lhs, Rhs, Output, Else> IfElseEqual<Lhs, Rhs, Else> for Output
where
Lhs: IsEqual<Rhs>,
Output: IfElsePredicate<Eq<Lhs, Rhs>, Else>,
Eq<Lhs, Rhs>: Boolean,
{
type Output = IfElsePredicateOutput<Output, Eq<Lhs, Rhs>, Else>;
}
pub trait IfZero<Value> {
type Output;
}
pub type IfZeroOutput<Output, Value> = <Output as IfZero<Value>>::Output;
impl<Output> IfZero<B0> for Output {
type Output = Output;
}
impl<Output> IfZero<Z0> for Output {
type Output = Output;
}
impl<Output> IfZero<U0> for Output {
type Output = Output;
}
pub trait IfNonZero<Value>
where
Value: NonZero,
{
type Output;
}
pub type IfNonZeroOutput<Output, Value> = <Output as IfNonZero<Value>>::Output;
impl<Value, Output> IfNonZero<Value> for Output
where
Value: NonZero,
{
type Output = Output;
}
#[cfg(test)]
mod tests {
use super::*;
use typenum::{consts::*, Le, Unsigned};
type Assert1 = IfOutput<U3, ()>;
type Assert2 = IfSameOutput<(), u8, u8>;
type Assert3 = IfPredicateOutput<(), Le<U3, U4>>;
type Assert4 = IfElsePredicateOutput<True, False, Le<U3, U4>>;
type Assert5 = IfLessOutput<(), U6, U9>;
type Assert6 = IfLessOrEqualOutput<(), U6, U6>;
type Assert7 = IfLessOrEqualOutput<(), U6, U7>;
type Assert8 = IfGreaterOutput<(), U7, U4>;
type Assert9 = IfGreaterOrEqualOutput<(), U7, U4>;
type Assert10 = IfGreaterOrEqualOutput<(), U7, U7>;
type Assert11 = IfEqualOutput<(), Z0, Z0>;
type Assert12<Value> = IfZeroOutput<(), Value>;
type Assert13<Value> = IfNonZeroOutput<(), Value>;
#[test]
fn control_test() {
assert_eq!(3, Assert1::USIZE);
let _: Assert2 = ();
let _: Assert3 = ();
assert!(Assert4::BOOL);
let _: Assert5 = ();
let _: Assert6 = ();
let _: Assert7 = ();
let _: Assert8 = ();
let _: Assert9 = ();
let _: Assert10 = ();
let _: Assert11 = ();
let _: Assert12<B0> = ();
let _: Assert12<Z0> = ();
let _: Assert12<U0> = ();
let _: Assert13<P1> = ();
let _: Assert13<N1> = ();
let _: Assert13<U1> = ();
}
}