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}