equator/
decompose.rs

1use crate::{
2    expr,
3    structures::{DebugMessage, DebugMessageImpl},
4    traits::Eval,
5    CmpDisplay,
6};
7use core::fmt;
8
9pub type PtrToDeref = unsafe fn(*const *const ()) -> *const ();
10pub type PtrToCmp = unsafe fn(out: *mut (), cmp: *const (), lhs: *const (), rhs: *const ());
11pub type PtrToDebug = unsafe fn(*const ()) -> &'static dyn fmt::Debug;
12pub type PtrToDisplay =
13    unsafe fn(*const ()) -> &'static dyn CmpDisplay<*const (), dyn fmt::Debug, dyn fmt::Debug>;
14
15pub trait Decompose {
16    type Decomposed: Recompose;
17}
18
19pub trait Recompose: Sized {
20    type Result: Eval;
21    type Source;
22    type VTable: 'static;
23    type DebugLhs: Copy + fmt::Debug;
24    type DebugRhs: Copy + fmt::Debug;
25    type DebugCmp: Copy + fmt::Debug;
26
27    fn debug_impl(message: &DebugMessageImpl<'_, Self>, f: &mut fmt::Formatter) -> fmt::Result;
28    fn eval_impl(
29        debug_lhs: &Self::DebugLhs,
30        debug_rhs: &Self::DebugRhs,
31        debug_cmp: Self::DebugCmp,
32        vtable: &Self::VTable,
33    ) -> Self::Result;
34
35    fn debug_final(full: &DebugMessage<'_, Self>, f: &mut fmt::Formatter) -> fmt::Result {
36        let result = &Self::eval_impl(
37            &full.debug_lhs,
38            &full.debug_rhs,
39            full.debug_cmp,
40            &full.source.vtable,
41        );
42
43        let message = full.message;
44        let inner = DebugMessageImpl::<'_, Self> {
45            result,
46            source: &full.source.source,
47            debug_lhs: &full.debug_lhs,
48            debug_rhs: &full.debug_rhs,
49            debug_cmp: full.debug_cmp,
50            vtable: full.source.vtable,
51        };
52        write!(
53            f,
54            "Assertion failed at {}:{}:{}\n",
55            full.source.file, full.source.line, full.source.col
56        )?;
57        if message.as_str() != Some("") {
58            write!(f, "{message:#?}\n")?;
59        }
60        Self::debug_impl(&inner, f)
61    }
62}
63
64impl Recompose for bool {
65    type Result = Result<(), ()>;
66    type Source = &'static str;
67    type VTable = ();
68    type DebugLhs = ();
69    type DebugRhs = ();
70    type DebugCmp = bool;
71
72    fn eval_impl(
73        _: &Self::DebugLhs,
74        _: &Self::DebugRhs,
75        debug_cmp: Self::DebugCmp,
76        _: &Self::VTable,
77    ) -> Self::Result {
78        if debug_cmp {
79            Ok(())
80        } else {
81            Err(())
82        }
83    }
84
85    fn debug_impl(message: &DebugMessageImpl<'_, Self>, f: &mut fmt::Formatter) -> fmt::Result {
86        let source = *message.source;
87        let result = message.result.is_ok();
88        write!(f, "Assertion failed: {source}\n")?;
89        write!(f, "- {source} = {result:#?}")
90    }
91}
92
93impl Recompose for crate::CmpExpr {
94    type Result = Result<(), ()>;
95    type Source = expr::CmpExpr<(), &'static str, &'static str>;
96    type VTable =
97        expr::CmpExpr<(PtrToDisplay, PtrToCmp), (PtrToDebug, PtrToDeref), (PtrToDebug, PtrToDeref)>;
98    type DebugLhs = *const ();
99    type DebugRhs = *const ();
100    type DebugCmp = ();
101
102    fn eval_impl(
103        debug_lhs: &Self::DebugLhs,
104        debug_rhs: &Self::DebugRhs,
105        _: Self::DebugCmp,
106        vtable: &Self::VTable,
107    ) -> Self::Result {
108        let debug_lhs = unsafe { (vtable.lhs.1)(debug_lhs) };
109        let debug_rhs = unsafe { (vtable.rhs.1)(debug_rhs) };
110        let mut result = core::mem::MaybeUninit::<Self::Result>::uninit();
111        unsafe {
112            (vtable.cmp.1)(
113                (&mut result) as *mut core::mem::MaybeUninit<Self::Result> as *mut (),
114                core::ptr::NonNull::<()>::dangling().as_ptr(),
115                debug_lhs,
116                debug_rhs,
117            )
118        }
119        unsafe { result.assume_init() }
120    }
121
122    fn debug_impl(message: &DebugMessageImpl<'_, Self>, f: &mut fmt::Formatter) -> fmt::Result {
123        let lhs_source = message.source.lhs;
124        let rhs_source = message.source.rhs;
125        let debug_lhs = unsafe { (message.vtable.lhs.1)(message.debug_lhs) };
126        let debug_rhs = unsafe { (message.vtable.rhs.1)(message.debug_rhs) };
127
128        let lhs = unsafe { (message.vtable.lhs.0)(debug_lhs) };
129        let rhs = unsafe { (message.vtable.rhs.0)(debug_rhs) };
130
131        let err =
132            unsafe { (message.vtable.cmp.0)(message.result.as_ref().unwrap_err() as *const ()) };
133        err.fmt(
134            &(core::ptr::NonNull::<()>::dangling().as_ptr() as *const ()),
135            lhs,
136            lhs_source,
137            lhs,
138            rhs,
139            rhs_source,
140            rhs,
141            f,
142        )
143    }
144}
145
146impl<E> Recompose for crate::CustomCmpExpr<E> {
147    type Result = Result<(), E>;
148    type Source = expr::CustomCmpExpr<(), &'static str, &'static str>;
149    type VTable = expr::CustomCmpExpr<
150        (PtrToDisplay, PtrToCmp),
151        (PtrToDebug, PtrToDeref),
152        (PtrToDebug, PtrToDeref),
153    >;
154    type DebugLhs = *const ();
155    type DebugRhs = *const ();
156    type DebugCmp = *const ();
157
158    fn eval_impl(
159        debug_lhs: &Self::DebugLhs,
160        debug_rhs: &Self::DebugRhs,
161        debug_cmp: Self::DebugCmp,
162        vtable: &Self::VTable,
163    ) -> Self::Result {
164        let debug_lhs = unsafe { (vtable.lhs.1)(debug_lhs) };
165        let debug_rhs = unsafe { (vtable.rhs.1)(debug_rhs) };
166
167        let mut result = core::mem::MaybeUninit::<Self::Result>::uninit();
168        unsafe {
169            (vtable.cmp.1)(
170                (&mut result) as *mut core::mem::MaybeUninit<Self::Result> as *mut (),
171                debug_cmp,
172                debug_lhs,
173                debug_rhs,
174            )
175        }
176        unsafe { result.assume_init() }
177    }
178
179    fn debug_impl(message: &DebugMessageImpl<'_, Self>, f: &mut fmt::Formatter) -> fmt::Result {
180        let lhs_source = message.source.lhs;
181        let rhs_source = message.source.rhs;
182        let debug_lhs = unsafe { (message.vtable.lhs.1)(message.debug_lhs) };
183        let debug_rhs = unsafe { (message.vtable.rhs.1)(message.debug_rhs) };
184
185        let lhs = unsafe { (message.vtable.lhs.0)(debug_lhs) };
186        let rhs = unsafe { (message.vtable.rhs.0)(debug_rhs) };
187
188        let err = unsafe {
189            (message.vtable.cmp.0)(message.result.as_ref().unwrap_err() as *const E as *const ())
190        };
191        err.fmt(
192            &message.debug_cmp,
193            lhs,
194            lhs_source,
195            lhs,
196            rhs,
197            rhs_source,
198            rhs,
199            f,
200        )
201    }
202}
203
204impl<L: Recompose, R: Recompose> Recompose for crate::AndExpr<L, R> {
205    type Result = expr::AndExpr<L::Result, R::Result>;
206    type Source = expr::AndExpr<L::Source, R::Source>;
207    type VTable = expr::AndExpr<&'static L::VTable, &'static R::VTable>;
208    type DebugCmp = expr::AndExpr<L::DebugCmp, R::DebugCmp>;
209    type DebugLhs = expr::AndExpr<L::DebugLhs, R::DebugLhs>;
210    type DebugRhs = expr::AndExpr<L::DebugRhs, R::DebugRhs>;
211
212    fn eval_impl(
213        debug_lhs: &Self::DebugLhs,
214        debug_rhs: &Self::DebugRhs,
215        debug_cmp: Self::DebugCmp,
216        vtable: &Self::VTable,
217    ) -> Self::Result {
218        let lhs = L::eval_impl(&debug_lhs.lhs, &debug_rhs.lhs, debug_cmp.lhs, vtable.lhs);
219        let rhs = R::eval_impl(&debug_lhs.rhs, &debug_rhs.rhs, debug_cmp.rhs, vtable.rhs);
220        expr::AndExpr { lhs, rhs }
221    }
222
223    fn debug_impl(message: &DebugMessageImpl<'_, Self>, f: &mut fmt::Formatter) -> fmt::Result {
224        let lhs = DebugMessageImpl::<'_, L> {
225            result: &message.result.lhs,
226            source: &message.source.lhs,
227            vtable: message.vtable.lhs,
228            debug_lhs: &message.debug_lhs.lhs,
229            debug_rhs: &message.debug_rhs.lhs,
230            debug_cmp: message.debug_cmp.lhs,
231        };
232        let rhs = DebugMessageImpl::<'_, R> {
233            result: &message.result.rhs,
234            source: &message.source.rhs,
235            vtable: message.vtable.rhs,
236            debug_lhs: &message.debug_lhs.rhs,
237            debug_rhs: &message.debug_rhs.rhs,
238            debug_cmp: message.debug_cmp.rhs,
239        };
240
241        let lhs_eval = lhs.result.eval();
242        let rhs_eval = rhs.result.eval();
243        if !(lhs_eval && rhs_eval) {
244            if !lhs_eval {
245                L::debug_impl(&lhs, f)?;
246                if !rhs_eval {
247                    f.write_str("\n")?;
248                }
249            }
250            if !rhs_eval {
251                R::debug_impl(&rhs, f)?;
252            }
253        }
254        Ok(())
255    }
256}
257
258impl<L: Recompose, R: Recompose> Recompose for crate::OrExpr<L, R> {
259    type Result = expr::OrExpr<L::Result, R::Result>;
260    type Source = expr::OrExpr<L::Source, R::Source>;
261    type VTable = expr::OrExpr<&'static L::VTable, &'static R::VTable>;
262    type DebugCmp = expr::OrExpr<L::DebugCmp, R::DebugCmp>;
263    type DebugLhs = expr::OrExpr<L::DebugLhs, R::DebugLhs>;
264    type DebugRhs = expr::OrExpr<L::DebugRhs, R::DebugRhs>;
265
266    fn eval_impl(
267        debug_lhs: &Self::DebugLhs,
268        debug_rhs: &Self::DebugRhs,
269        debug_cmp: Self::DebugCmp,
270        vtable: &Self::VTable,
271    ) -> Self::Result {
272        let lhs = L::eval_impl(&debug_lhs.lhs, &debug_rhs.lhs, debug_cmp.lhs, vtable.lhs);
273        let rhs = R::eval_impl(&debug_lhs.rhs, &debug_rhs.rhs, debug_cmp.rhs, vtable.rhs);
274        expr::OrExpr { lhs, rhs }
275    }
276
277    fn debug_impl(message: &DebugMessageImpl<'_, Self>, f: &mut fmt::Formatter) -> fmt::Result {
278        let lhs = DebugMessageImpl::<'_, L> {
279            result: &message.result.lhs,
280            source: &message.source.lhs,
281            vtable: message.vtable.lhs,
282            debug_lhs: &message.debug_lhs.lhs,
283            debug_rhs: &message.debug_rhs.lhs,
284            debug_cmp: message.debug_cmp.lhs,
285        };
286        let rhs = DebugMessageImpl::<'_, R> {
287            result: &message.result.rhs,
288            source: &message.source.rhs,
289            vtable: message.vtable.rhs,
290            debug_lhs: &message.debug_lhs.rhs,
291            debug_rhs: &message.debug_rhs.rhs,
292            debug_cmp: message.debug_cmp.rhs,
293        };
294
295        let lhs_eval = lhs.result.eval();
296        let rhs_eval = rhs.result.eval();
297        if !(lhs_eval || rhs_eval) {
298            if !lhs_eval {
299                L::debug_impl(&lhs, f)?;
300                if !rhs_eval {
301                    f.write_str("\n")?;
302                }
303            }
304            if !rhs_eval {
305                R::debug_impl(&rhs, f)?;
306            }
307        }
308        Ok(())
309    }
310}
311
312impl Decompose for &'static str {
313    type Decomposed = bool;
314}
315impl Decompose for expr::CmpExpr<(), &'static str, &'static str> {
316    type Decomposed = crate::CmpExpr;
317}
318impl Decompose for expr::CustomCmpExpr<(), &'static str, &'static str> {
319    type Decomposed = crate::CustomCmpExpr<()>;
320}
321impl<L: Decompose, R: Decompose> Decompose for expr::AndExpr<L, R> {
322    type Decomposed = crate::AndExpr<L::Decomposed, R::Decomposed>;
323}
324impl<L: Decompose, R: Decompose> Decompose for expr::OrExpr<L, R> {
325    type Decomposed = crate::OrExpr<L::Decomposed, R::Decomposed>;
326}