1use core::marker::PhantomData;
16use stabby_macros::tyeval;
17
18use super::{
19 istable::{IBitMask, IForbiddenValues, ISingleForbiddenValue, NicheExporter, Saturator},
20 unsigned::NonZero,
21 vtable::{H, T},
22 IStable,
23};
24use crate::*;
25
26pub trait IDeterminant: IStable {
28 unsafe fn ok(union: *mut u8) -> Self;
32 unsafe fn err(union: *mut u8) -> Self;
36 fn is_det_ok(&self, union: *const u8) -> bool;
38 type IsNicheTrick: Bit;
40}
41
42#[repr(u8)]
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45pub enum BitDeterminant {
46 Ok = 0,
48 Err = 1,
50}
51unsafe impl IStable for BitDeterminant {
53 type Size = U1;
54 type Align = U1;
55 type ForbiddenValues = End;
56 type UnusedBits = Array<U0, U254, End>;
57 type HasExactlyOneNiche = Saturator;
58 type ContainsIndirections = B0;
59 #[cfg(feature = "experimental-ctypes")]
60 type CType = u8;
61 primitive_report!("BitDeterminant");
62}
63
64impl IDeterminant for BitDeterminant {
65 unsafe fn ok(_: *mut u8) -> Self {
66 BitDeterminant::Ok
67 }
68 unsafe fn err(_: *mut u8) -> Self {
69 BitDeterminant::Err
70 }
71 fn is_det_ok(&self, _: *const u8) -> bool {
72 (*self as u8 & 1) == 0
73 }
74 type IsNicheTrick = B0;
75}
76impl IDeterminant for End {
77 unsafe fn ok(_: *mut u8) -> Self {
78 End
79 }
80 unsafe fn err(_: *mut u8) -> Self {
81 End
82 }
83 fn is_det_ok(&self, _: *const u8) -> bool {
84 false
85 }
86 type IsNicheTrick = B0;
87}
88
89#[derive(Clone, Copy)]
91#[repr(C)]
92pub struct ValueIsErr<Offset, Value, Tail: IStable>(PhantomData<(Offset, Value)>, Tail);
93impl<Offset, Value, Tail: IStable> Unpin for ValueIsErr<Offset, Value, Tail> {}
94unsafe impl<Offset, Value, Tail: IStable> IStable for ValueIsErr<Offset, Value, Tail> {
96 type Size = Tail::Size;
97 type Align = Tail::Align;
98 type ForbiddenValues = Tail::ForbiddenValues;
99 type UnusedBits = Tail::UnusedBits;
100 type HasExactlyOneNiche = Tail::HasExactlyOneNiche;
101 type ContainsIndirections = B0;
102 #[cfg(feature = "experimental-ctypes")]
103 type CType = ();
104 primitive_report!("ValueIsErr");
105}
106impl<Offset: Unsigned, Value: Unsigned, Tail: IDeterminant + core::fmt::Debug> core::fmt::Debug
107 for ValueIsErr<Offset, Value, Tail>
108{
109 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
110 write!(
111 f,
112 "ValIsErr(ptr[{}]={}, {:?})",
113 Offset::USIZE,
114 Value::U8,
115 &self.1,
116 )
117 }
118}
119impl<Offset: Unsigned, Value: Unsigned, Tail: IDeterminant> IDeterminant
120 for ValueIsErr<Offset, Value, Tail>
121where
122 ValueIsErr<Offset, Value, Tail>: IStable,
123{
124 unsafe fn ok(union: *mut u8) -> Self {
125 ValueIsErr(PhantomData, Tail::ok(union))
126 }
127 unsafe fn err(union: *mut u8) -> Self {
128 let ptr = union;
129 *ptr.add(Offset::USIZE) = Value::U8;
130 ValueIsErr(PhantomData, Tail::err(union))
131 }
132 fn is_det_ok(&self, union: *const u8) -> bool {
133 let ptr = union;
134 unsafe { *ptr.add(Offset::USIZE) != Value::U8 || self.1.is_det_ok(union) }
135 }
136 type IsNicheTrick = B1;
137}
138pub trait IntoValueIsErr {
140 type ValueIsErr: IDeterminant + IStable + Unpin;
142}
143impl IntoValueIsErr for End {
144 type ValueIsErr = End;
145}
146impl<Offset: Unsigned, Value: Unsigned, Tail: IForbiddenValues + IntoValueIsErr> IntoValueIsErr
147 for Array<Offset, Value, Tail>
148{
149 type ValueIsErr = ValueIsErr<Offset, Value, Tail::ValueIsErr>;
150}
151#[crate::stabby]
153#[derive(Clone, Copy)]
154pub struct BitIsErr<Offset, Mask>(PhantomData<(Offset, Mask)>);
155impl<Offset: Unsigned, Mask: Unsigned> core::fmt::Debug for BitIsErr<Offset, Mask> {
156 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
157 write!(f, "BitIsErr(ptr[{}] & {})", Offset::USIZE, Mask::U8)
158 }
159}
160impl<Offset, Mask> Unpin for BitIsErr<Offset, Mask> {}
161impl<Offset: Unsigned, Mask: Unsigned> IDeterminant for BitIsErr<Offset, Mask> {
162 unsafe fn ok(union: *mut u8) -> Self {
163 let ptr = union;
164 if Mask::U8 == 1 {
165 *ptr.add(Offset::USIZE) = 0;
166 }
167 *ptr.add(Offset::USIZE) &= u8::MAX ^ Mask::U8;
168 BitIsErr(PhantomData)
169 }
170 unsafe fn err(union: *mut u8) -> Self {
171 let ptr = union;
172 if Mask::U8 == 1 {
173 *ptr.add(Offset::USIZE) = 0;
174 }
175 *ptr.add(Offset::USIZE) |= Mask::U8;
176 BitIsErr(PhantomData)
177 }
178 fn is_det_ok(&self, union: *const u8) -> bool {
179 let ptr = union;
180 unsafe { *ptr.add(Offset::USIZE) & Mask::U8 == 0 }
181 }
182 type IsNicheTrick = B1;
183}
184#[derive(Debug, Clone, Copy)]
186pub struct Not<Determinant>(Determinant);
187impl<Determinant> Unpin for Not<Determinant> {}
188unsafe impl<Determinant: IStable> IStable for Not<Determinant> {
190 type Size = Determinant::Size;
191 type Align = Determinant::Align;
192 type ForbiddenValues = Determinant::ForbiddenValues;
193 type UnusedBits = Determinant::UnusedBits;
194 type HasExactlyOneNiche = Determinant::HasExactlyOneNiche;
195 type ContainsIndirections = Determinant::ContainsIndirections;
196 #[cfg(feature = "experimental-ctypes")]
197 type CType = Determinant::CType;
198 primitive_report!("Not", Determinant);
199}
200impl<Determinant: IDeterminant> IDeterminant for Not<Determinant>
201where
202 Not<Determinant>: IStable,
203{
204 unsafe fn ok(union: *mut u8) -> Self {
205 Not(Determinant::err(union))
206 }
207 unsafe fn err(union: *mut u8) -> Self {
208 Not(Determinant::ok(union))
209 }
210 fn is_det_ok(&self, union: *const u8) -> bool {
211 !self.0.is_det_ok(union)
212 }
213 type IsNicheTrick = Determinant::IsNicheTrick;
214}
215
216pub trait IDeterminantProvider<Other>: IStable {
219 type OkShift: Unsigned;
221 type ErrShift: Unsigned;
223 type Determinant: IDeterminant + Unpin;
225 type NicheExporter: IStable + Default + Copy + Unpin;
227}
228mod seal {
229 use super::*;
230 pub trait IDeterminantProviderInnerRev {
231 type OkShift: Unsigned;
232 type ErrShift: Unsigned;
233 type Determinant: IDeterminant + Unpin;
234 type NicheExporter: IStable + Default + Copy + Unpin;
235 }
236 pub trait IDeterminantProviderInner {
237 type ErrShift: Unsigned;
238 type Determinant: IDeterminant + Unpin;
239 type NicheExporter: IStable + Default + Copy + Unpin;
240 }
241}
242pub(crate) use seal::*;
243
244type UnionAlign<Ok, Err> = <<Ok as IStable>::Align as PowerOf2>::Max<<Err as IStable>::Align>;
246type UnionSize<Ok, Err, OkShift, ErrShift> =
248 <<tyeval!(<Ok as IStable>::Size + OkShift) as Unsigned>::Max<
249 tyeval!(<Err as IStable>::Size + ErrShift),
250 > as Unsigned>::NextMultipleOf<UnionAlign<Ok, Err>>;
251type PaddedSize<T, Shift> = <<T as IStable>::Size as Unsigned>::Add<Shift>;
253type ShiftedUnusedBits<T, Shift> = <<T as IStable>::UnusedBits as IBitMask>::Shift<Shift>;
255
256pub(crate) type UnionMemberUnusedBits<Ok, Err, OkShift> =
258 <<<<OkShift as Unsigned>::Padding as IStable>::UnusedBits as IBitMask>::BitOr<
259 ShiftedUnusedBits<Ok, OkShift>,
260 > as IBitMask>::BitOr<
261 ShiftedUnusedBits<
262 <tyeval!(UnionSize<Ok, Err, OkShift, U0> - PaddedSize<Ok, OkShift>) as Unsigned>::Padding,
263 PaddedSize<Ok, OkShift>,
264 >,
265 >;
266
267macro_rules! same_as {
268 ($T: ty) => {
269 type ErrShift = <$T as IDeterminantProviderInner>::ErrShift;
270 type Determinant = <$T as IDeterminantProviderInner>::Determinant;
271 type NicheExporter = <$T as IDeterminantProviderInner>::NicheExporter;
272 };
274 ($T: ty, $Trait: ty) => {
275 type OkShift = <$T as $Trait>::OkShift;
276 type ErrShift = <$T as $Trait>::ErrShift;
277 type Determinant = <$T as $Trait>::Determinant;
278 type NicheExporter = <$T as $Trait>::NicheExporter;
279 };
281}
282
283impl<A: IStable, B: IStable> IDeterminantProvider<B> for A
284where
285 (A, B, <A::Size as Unsigned>::GreaterOrEq<B::Size>): IDeterminantProviderInnerRev,
286{
287 same_as!(
288 (A, B, <A::Size as Unsigned>::GreaterOrEq<B::Size>),
289 IDeterminantProviderInnerRev
290 );
291}
292
293impl<Ok: IStable, Err: IStable> IDeterminantProviderInnerRev for (Ok, Err, B0)
295where
296 (Err, Ok, Ok::Size): IDeterminantProviderInner,
297{
298 type OkShift = <(Err, Ok, Ok::Size) as IDeterminantProviderInner>::ErrShift;
299 type ErrShift = U0;
300 type Determinant = Not<<(Err, Ok, Ok::Size) as IDeterminantProviderInner>::Determinant>;
301 type NicheExporter = <(Err, Ok, Ok::Size) as IDeterminantProviderInner>::NicheExporter;
302 }
304impl<Ok: IStable, Err: IStable> IDeterminantProviderInnerRev for (Ok, Err, B1)
306where
307 (Ok, Err, Err::Size): IDeterminantProviderInner,
308{
309 type OkShift = U0;
310 same_as!((Ok, Err, Err::Size));
311}
312
313mod err_non_empty;
315mod err_size_0;