use core::marker::PhantomData;
use stabby_macros::tyeval;
use super::{
istable::{IBitMask, IForbiddenValues, ISingleForbiddenValue, NicheExporter, Saturator},
unsigned::NonZero,
vtable::{H, T},
IStable,
};
use crate::*;
pub trait IDeterminant: IStable {
unsafe fn ok(union: *mut u8) -> Self;
unsafe fn err(union: *mut u8) -> Self;
fn is_det_ok(&self, union: *const u8) -> bool;
type IsNicheTrick: Bit;
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BitDeterminant {
Ok = 0,
Err = 1,
}
unsafe impl IStable for BitDeterminant {
type Size = U1;
type Align = U1;
type ForbiddenValues = End;
type UnusedBits = Array<U0, U254, End>;
type HasExactlyOneNiche = Saturator;
type ContainsIndirections = B0;
primitive_report!("BitDeterminant");
}
impl IDeterminant for BitDeterminant {
unsafe fn ok(_: *mut u8) -> Self {
BitDeterminant::Ok
}
unsafe fn err(_: *mut u8) -> Self {
BitDeterminant::Err
}
fn is_det_ok(&self, _: *const u8) -> bool {
(*self as u8 & 1) == 0
}
type IsNicheTrick = B0;
}
impl IDeterminant for End {
unsafe fn ok(_: *mut u8) -> Self {
End
}
unsafe fn err(_: *mut u8) -> Self {
End
}
fn is_det_ok(&self, _: *const u8) -> bool {
false
}
type IsNicheTrick = B0;
}
#[derive(Clone, Copy)]
#[repr(C)]
pub struct ValueIsErr<Offset, Value, Tail: IStable>(PhantomData<(Offset, Value)>, Tail);
impl<Offset, Value, Tail: IStable> Unpin for ValueIsErr<Offset, Value, Tail> {}
unsafe impl<Offset, Value, Tail: IStable> IStable for ValueIsErr<Offset, Value, Tail> {
type Size = Tail::Size;
type Align = Tail::Align;
type ForbiddenValues = Tail::ForbiddenValues;
type UnusedBits = Tail::UnusedBits;
type HasExactlyOneNiche = Tail::HasExactlyOneNiche;
type ContainsIndirections = B0;
primitive_report!("ValueIsErr");
}
impl<Offset: Unsigned, Value: Unsigned, Tail: IDeterminant + core::fmt::Debug> core::fmt::Debug
for ValueIsErr<Offset, Value, Tail>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"ValIsErr(ptr[{}]={}, {:?})",
Offset::USIZE,
Value::U8,
&self.1,
)
}
}
impl<Offset: Unsigned, Value: Unsigned, Tail: IDeterminant> IDeterminant
for ValueIsErr<Offset, Value, Tail>
where
ValueIsErr<Offset, Value, Tail>: IStable,
{
unsafe fn ok(union: *mut u8) -> Self {
ValueIsErr(PhantomData, Tail::ok(union))
}
unsafe fn err(union: *mut u8) -> Self {
let ptr = union;
*ptr.add(Offset::USIZE) = Value::U8;
ValueIsErr(PhantomData, Tail::err(union))
}
fn is_det_ok(&self, union: *const u8) -> bool {
let ptr = union;
unsafe { *ptr.add(Offset::USIZE) != Value::U8 || self.1.is_det_ok(union) }
}
type IsNicheTrick = B1;
}
pub trait IntoValueIsErr {
type ValueIsErr: IDeterminant + IStable + Unpin;
}
impl IntoValueIsErr for End {
type ValueIsErr = End;
}
impl<Offset: Unsigned, Value: Unsigned, Tail: IForbiddenValues + IntoValueIsErr> IntoValueIsErr
for Array<Offset, Value, Tail>
{
type ValueIsErr = ValueIsErr<Offset, Value, Tail::ValueIsErr>;
}
#[crate::stabby]
#[derive(Clone, Copy)]
pub struct BitIsErr<Offset, Mask>(PhantomData<(Offset, Mask)>);
impl<Offset: Unsigned, Mask: Unsigned> core::fmt::Debug for BitIsErr<Offset, Mask> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "BitIsErr(ptr[{}] & {})", Offset::USIZE, Mask::U8)
}
}
impl<Offset, Mask> Unpin for BitIsErr<Offset, Mask> {}
impl<Offset: Unsigned, Mask: Unsigned> IDeterminant for BitIsErr<Offset, Mask> {
unsafe fn ok(union: *mut u8) -> Self {
let ptr = union;
if Mask::U8 == 1 {
*ptr.add(Offset::USIZE) = 0;
}
*ptr.add(Offset::USIZE) &= u8::MAX ^ Mask::U8;
BitIsErr(PhantomData)
}
unsafe fn err(union: *mut u8) -> Self {
let ptr = union;
if Mask::U8 == 1 {
*ptr.add(Offset::USIZE) = 0;
}
*ptr.add(Offset::USIZE) |= Mask::U8;
BitIsErr(PhantomData)
}
fn is_det_ok(&self, union: *const u8) -> bool {
let ptr = union;
unsafe { *ptr.add(Offset::USIZE) & Mask::U8 == 0 }
}
type IsNicheTrick = B1;
}
#[derive(Debug, Clone, Copy)]
pub struct Not<Determinant>(Determinant);
impl<Determinant> Unpin for Not<Determinant> {}
unsafe impl<Determinant: IStable> IStable for Not<Determinant> {
type Size = Determinant::Size;
type Align = Determinant::Align;
type ForbiddenValues = Determinant::ForbiddenValues;
type UnusedBits = Determinant::UnusedBits;
type HasExactlyOneNiche = Determinant::HasExactlyOneNiche;
type ContainsIndirections = Determinant::ContainsIndirections;
primitive_report!("Not", Determinant);
}
impl<Determinant: IDeterminant> IDeterminant for Not<Determinant>
where
Not<Determinant>: IStable,
{
unsafe fn ok(union: *mut u8) -> Self {
Not(Determinant::err(union))
}
unsafe fn err(union: *mut u8) -> Self {
Not(Determinant::ok(union))
}
fn is_det_ok(&self, union: *const u8) -> bool {
!self.0.is_det_ok(union)
}
type IsNicheTrick = Determinant::IsNicheTrick;
}
pub trait IDeterminantProvider<Other>: IStable {
type OkShift: Unsigned;
type ErrShift: Unsigned;
type Determinant: IDeterminant + Unpin;
type NicheExporter: IStable + Default + Copy + Unpin;
}
mod seal {
use super::*;
pub trait IDeterminantProviderInnerRev {
type OkShift: Unsigned;
type ErrShift: Unsigned;
type Determinant: IDeterminant + Unpin;
type NicheExporter: IStable + Default + Copy + Unpin;
}
pub trait IDeterminantProviderInner {
type ErrShift: Unsigned;
type Determinant: IDeterminant + Unpin;
type NicheExporter: IStable + Default + Copy + Unpin;
}
}
pub(crate) use seal::*;
type UnionAlign<Ok, Err> = <<Ok as IStable>::Align as PowerOf2>::Max<<Err as IStable>::Align>;
type UnionSize<Ok, Err, OkShift, ErrShift> =
<<tyeval!(<Ok as IStable>::Size + OkShift) as Unsigned>::Max<
tyeval!(<Err as IStable>::Size + ErrShift),
> as Unsigned>::NextMultipleOf<UnionAlign<Ok, Err>>;
type PaddedSize<T, Shift> = <<T as IStable>::Size as Unsigned>::Add<Shift>;
type ShiftedUnusedBits<T, Shift> = <<T as IStable>::UnusedBits as IBitMask>::Shift<Shift>;
pub(crate) type UnionMemberUnusedBits<Ok, Err, OkShift> =
<<<<OkShift as Unsigned>::Padding as IStable>::UnusedBits as IBitMask>::BitOr<
ShiftedUnusedBits<Ok, OkShift>,
> as IBitMask>::BitOr<
ShiftedUnusedBits<
<tyeval!(UnionSize<Ok, Err, OkShift, U0> - PaddedSize<Ok, OkShift>) as Unsigned>::Padding,
PaddedSize<Ok, OkShift>,
>,
>;
macro_rules! same_as {
($T: ty) => {
type ErrShift = <$T as IDeterminantProviderInner>::ErrShift;
type Determinant = <$T as IDeterminantProviderInner>::Determinant;
type NicheExporter = <$T as IDeterminantProviderInner>::NicheExporter;
};
($T: ty, $Trait: ty) => {
type OkShift = <$T as $Trait>::OkShift;
type ErrShift = <$T as $Trait>::ErrShift;
type Determinant = <$T as $Trait>::Determinant;
type NicheExporter = <$T as $Trait>::NicheExporter;
};
}
impl<A: IStable, B: IStable> IDeterminantProvider<B> for A
where
(A, B, <A::Size as Unsigned>::GreaterOrEq<B::Size>): IDeterminantProviderInnerRev,
{
same_as!(
(A, B, <A::Size as Unsigned>::GreaterOrEq<B::Size>),
IDeterminantProviderInnerRev
);
}
impl<Ok: IStable, Err: IStable> IDeterminantProviderInnerRev for (Ok, Err, B0)
where
(Err, Ok, Ok::Size): IDeterminantProviderInner,
{
type OkShift = <(Err, Ok, Ok::Size) as IDeterminantProviderInner>::ErrShift;
type ErrShift = U0;
type Determinant = Not<<(Err, Ok, Ok::Size) as IDeterminantProviderInner>::Determinant>;
type NicheExporter = <(Err, Ok, Ok::Size) as IDeterminantProviderInner>::NicheExporter;
}
impl<Ok: IStable, Err: IStable> IDeterminantProviderInnerRev for (Ok, Err, B1)
where
(Ok, Err, Err::Size): IDeterminantProviderInner,
{
type OkShift = U0;
same_as!((Ok, Err, Err::Size));
}
mod err_non_empty;
mod err_size_0;