use std::{fmt::Debug, hash::Hash, mem::ManuallyDrop, ptr};
mod sealed {
pub trait Sealed {}
}
pub unsafe trait GenericConstBool:
sealed::Sealed + Copy + Ord + Hash + Default + Debug + 'static + Send + Sync
{
const VALUE: bool;
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct ConstBool<const VALUE: bool>;
impl<const VALUE: bool> Debug for ConstBool<VALUE> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("ConstBool").field(&Self::VALUE).finish()
}
}
impl<const VALUE: bool> sealed::Sealed for ConstBool<VALUE> {}
unsafe impl<const VALUE: bool> GenericConstBool for ConstBool<VALUE> {
const VALUE: bool = VALUE;
}
pub trait ConstBoolDispatchTag {
type Type<Select: GenericConstBool>;
}
pub enum ConstBoolDispatch<FalseT, TrueT> {
False(FalseT),
True(TrueT),
}
impl<FalseT, TrueT> ConstBoolDispatch<FalseT, TrueT> {
pub fn new<
Tag: ConstBoolDispatchTag<Type<ConstBool<false>> = FalseT>
+ ConstBoolDispatchTag<Type<ConstBool<true>> = TrueT>,
Select: GenericConstBool,
>(
v: Tag::Type<Select>,
) -> Self {
let v = ManuallyDrop::new(v);
let v_ptr: *const Tag::Type<Select> = &*v;
unsafe {
if Select::VALUE {
ConstBoolDispatch::True(ptr::read(v_ptr.cast()))
} else {
ConstBoolDispatch::False(ptr::read(v_ptr.cast()))
}
}
}
}