use crate::uninhabited::PhantomUninhabited;
pub trait Bool: BoolT + private_bool::Sealed {
const VALUE: bool;
}
pub trait BoolT {
type Type: Bool;
}
pub enum False {}
impl Bool for False {
const VALUE: bool = false;
}
impl BoolT for False {
type Type = Self;
}
pub enum True {}
impl Bool for True {
const VALUE: bool = true;
}
impl BoolT for True {
type Type = Self;
}
mod private_bool {
use super::*;
pub trait Sealed {}
impl Sealed for False {}
impl Sealed for True {}
}
pub struct NandBase<A: Bool, B: Bool>(PhantomUninhabited<(A, B)>);
impl BoolT for NandBase<False, False> {
type Type = True;
}
impl BoolT for NandBase<False, True> {
type Type = True;
}
impl BoolT for NandBase<True, False> {
type Type = True;
}
impl BoolT for NandBase<True, True> {
type Type = False;
}
pub struct Nand<A: BoolT, B: BoolT>(PhantomUninhabited<(A, B)>);
impl<A: BoolT, B: BoolT> BoolT for Nand<A, B>
where
NandBase<A::Type, B::Type>: BoolT,
{
type Type = <NandBase<A::Type, B::Type> as BoolT>::Type;
}
pub struct Not<A: BoolT>(PhantomUninhabited<A>);
impl<A: BoolT> BoolT for Not<A>
where
Nand<A, A>: BoolT,
{
type Type = <Nand<A, A> as BoolT>::Type;
}
pub struct And<A: BoolT, B: BoolT>(PhantomUninhabited<(A, B)>);
impl<A: BoolT, B: BoolT> BoolT for And<A, B>
where
Nand<A, B>: BoolT,
Not<<Nand<A, B> as BoolT>::Type>: BoolT,
{
type Type = <Not<<Nand<A, B> as BoolT>::Type> as BoolT>::Type;
}
pub struct Or<A: BoolT, B: BoolT>(PhantomUninhabited<(A, B)>);
impl<A: BoolT, B: BoolT> BoolT for Or<A, B>
where
Not<A>: BoolT,
Not<B>: BoolT,
Nand<<Not<A> as BoolT>::Type, <Not<B> as BoolT>::Type>: BoolT,
{
type Type = <Nand<<Not<A> as BoolT>::Type, <Not<B> as BoolT>::Type> as BoolT>::Type;
}
pub struct Nor<A: BoolT, B: BoolT>(PhantomUninhabited<(A, B)>);
impl<A: BoolT, B: BoolT> BoolT for Nor<A, B>
where
Or<A, B>: BoolT,
Not<<Or<A, B> as BoolT>::Type>: BoolT,
{
type Type = <Not<<Or<A, B> as BoolT>::Type> as BoolT>::Type;
}
pub struct Xnor<A: BoolT, B: BoolT>(PhantomUninhabited<(A, B)>);
impl<A: BoolT, B: BoolT> BoolT for Xnor<A, B>
where
Nand<A, B>: BoolT,
And<A, B>: BoolT,
Or<<Nand<A, B> as BoolT>::Type, <And<A, B> as BoolT>::Type>: BoolT,
{
type Type = <Or<<Nand<A, B> as BoolT>::Type, <And<A, B> as BoolT>::Type> as BoolT>::Type;
}
pub struct Xor<A: BoolT, B: BoolT>(PhantomUninhabited<(A, B)>);
impl<A: BoolT, B: BoolT> BoolT for Xor<A, B>
where
Xnor<A, B>: BoolT,
Not<<Xnor<A, B> as BoolT>::Type>: BoolT,
{
type Type = <Not<<Xnor<A, B> as BoolT>::Type> as BoolT>::Type;
}
pub type BoolEq<A, B> = Xnor<A, B>;
pub const fn assert_false<T: BoolT<Type = False>>() {}
pub const fn assert_true<T: BoolT<Type = True>>() {}
pub trait BoolIsEq: private_eq::BoolIsEqSealed {}
impl<T: private_eq::BoolIsEqSealed> BoolIsEq for T {}
pub trait BoolNotEq: private_eq::BoolNotEqSealed {}
impl<T: private_eq::BoolNotEqSealed> BoolNotEq for T {}
mod private_eq {
use super::*;
pub trait BoolIsEqSealed {}
impl<V: Bool, A: BoolT<Type = V>, B: BoolT<Type = V>> BoolIsEqSealed for (A, B) {}
pub trait BoolNotEqSealed {}
impl<A, B> BoolNotEqSealed for (A, B)
where
A: BoolT,
B: BoolT,
(A, Not<B>): BoolIsEq,
{
}
}
pub const fn assert_bool_eq<T1: BoolT, T2: BoolT>()
where
(T1, T2): BoolIsEq,
{
}
mod test {
use super::*;
const _: () = assert_false::<False>();
const _: () = assert_true::<True>();
const _: () = assert_true::<Not<False>>();
const _: () = assert_false::<Not<True>>();
const _: () = assert_false::<And<False, False>>();
const _: () = assert_false::<And<False, True>>();
const _: () = assert_false::<And<True, False>>();
const _: () = assert_true::<And<True, True>>();
const _: () = assert_true::<Nand<False, False>>();
const _: () = assert_true::<Nand<False, True>>();
const _: () = assert_false::<Nand<True, True>>();
const _: () = assert_true::<Nand<True, False>>();
const _: () = assert_false::<Or<False, False>>();
const _: () = assert_true::<Or<False, True>>();
const _: () = assert_true::<Or<True, False>>();
const _: () = assert_true::<Or<True, True>>();
const _: () = assert_true::<Nor<False, False>>();
const _: () = assert_false::<Nor<False, True>>();
const _: () = assert_false::<Nor<True, False>>();
const _: () = assert_false::<Nor<True, True>>();
}