equator/
lib.rs

1#![no_std]
2
3use core::fmt::{Debug, Formatter, Result};
4use core::marker::PhantomData;
5
6#[doc(hidden)]
7pub use equator_macro::assert as __assert_impl;
8
9#[macro_export]
10macro_rules! assert {
11    ($($tokens: tt)*) => {
12        $crate::__assert_impl!($crate, $($tokens)*)
13    };
14}
15
16#[macro_export]
17macro_rules! debug_assert {
18    ($($tokens: tt)*) => {
19        if cfg!(debug_assertions) {
20            $crate::__assert_impl!($crate, $($tokens)*)
21        }
22    };
23}
24
25#[derive(Copy, Clone)]
26#[doc(hidden)]
27pub struct Finalize<E, Line, Col, File> {
28    pub expr: E,
29    pub line: Line,
30    pub col: Col,
31    pub file: File,
32}
33
34#[doc(hidden)]
35pub mod atomic {
36    #[derive(Copy, Clone)]
37    pub struct EqExpr<Lhs, Rhs> {
38        pub lhs: Lhs,
39        pub rhs: Rhs,
40    }
41
42    #[derive(Copy, Clone)]
43    pub struct NeExpr<Lhs, Rhs> {
44        pub lhs: Lhs,
45        pub rhs: Rhs,
46    }
47
48    #[derive(Copy, Clone)]
49    pub struct LtExpr<Lhs, Rhs> {
50        pub lhs: Lhs,
51        pub rhs: Rhs,
52    }
53
54    #[derive(Copy, Clone)]
55    pub struct LeExpr<Lhs, Rhs> {
56        pub lhs: Lhs,
57        pub rhs: Rhs,
58    }
59
60    #[derive(Copy, Clone)]
61    pub struct GtExpr<Lhs, Rhs> {
62        pub lhs: Lhs,
63        pub rhs: Rhs,
64    }
65
66    #[derive(Copy, Clone)]
67    pub struct GeExpr<Lhs, Rhs> {
68        pub lhs: Lhs,
69        pub rhs: Rhs,
70    }
71}
72
73#[doc(hidden)]
74#[repr(transparent)]
75pub struct DebugWrapper<T>(T);
76#[doc(hidden)]
77#[repr(transparent)]
78pub struct NoDebugWrapper<T>(T);
79
80impl<Lhs: PartialEq<Rhs>, Rhs> PartialEq<DebugWrapper<Rhs>> for DebugWrapper<Lhs> {
81    #[inline(always)]
82    fn eq(&self, other: &DebugWrapper<Rhs>) -> bool {
83        self.0 == other.0
84    }
85}
86impl<Lhs: PartialEq<Rhs>, Rhs> PartialEq<DebugWrapper<Rhs>> for NoDebugWrapper<Lhs> {
87    #[inline(always)]
88    fn eq(&self, other: &DebugWrapper<Rhs>) -> bool {
89        self.0 == other.0
90    }
91}
92impl<Lhs: PartialEq<Rhs>, Rhs> PartialEq<NoDebugWrapper<Rhs>> for DebugWrapper<Lhs> {
93    #[inline(always)]
94    fn eq(&self, other: &NoDebugWrapper<Rhs>) -> bool {
95        self.0 == other.0
96    }
97}
98impl<Lhs: PartialEq<Rhs>, Rhs> PartialEq<NoDebugWrapper<Rhs>> for NoDebugWrapper<Lhs> {
99    #[inline(always)]
100    fn eq(&self, other: &NoDebugWrapper<Rhs>) -> bool {
101        self.0 == other.0
102    }
103}
104
105impl<Lhs: PartialOrd<Rhs>, Rhs> PartialOrd<DebugWrapper<Rhs>> for DebugWrapper<Lhs> {
106    #[inline(always)]
107    fn partial_cmp(&self, other: &DebugWrapper<Rhs>) -> Option<core::cmp::Ordering> {
108        self.0.partial_cmp(&other.0)
109    }
110}
111impl<Lhs: PartialOrd<Rhs>, Rhs> PartialOrd<DebugWrapper<Rhs>> for NoDebugWrapper<Lhs> {
112    #[inline(always)]
113    fn partial_cmp(&self, other: &DebugWrapper<Rhs>) -> Option<core::cmp::Ordering> {
114        self.0.partial_cmp(&other.0)
115    }
116}
117impl<Lhs: PartialOrd<Rhs>, Rhs> PartialOrd<NoDebugWrapper<Rhs>> for DebugWrapper<Lhs> {
118    #[inline(always)]
119    fn partial_cmp(&self, other: &NoDebugWrapper<Rhs>) -> Option<core::cmp::Ordering> {
120        self.0.partial_cmp(&other.0)
121    }
122}
123impl<Lhs: PartialOrd<Rhs>, Rhs> PartialOrd<NoDebugWrapper<Rhs>> for NoDebugWrapper<Lhs> {
124    #[inline(always)]
125    fn partial_cmp(&self, other: &NoDebugWrapper<Rhs>) -> Option<core::cmp::Ordering> {
126        self.0.partial_cmp(&other.0)
127    }
128}
129
130impl<T: Debug> Debug for DebugWrapper<T> {
131    #[inline(always)]
132    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
133        self.0.fmt(f)
134    }
135}
136impl<T> Debug for NoDebugWrapper<T> {
137    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
138        write!(
139            f,
140            "<object of type \"{}\" at address {:?}>",
141            core::any::type_name::<T>(),
142            self as *const _ as *const ()
143        )
144    }
145}
146
147#[doc(hidden)]
148pub struct DebugWrap;
149#[doc(hidden)]
150pub struct NoDebugWrap;
151
152impl DebugWrap {
153    #[inline(always)]
154    pub fn do_wrap<T: Debug>(self, value: &T) -> &DebugWrapper<T> {
155        unsafe { &*(value as *const T as *const _) }
156    }
157}
158impl NoDebugWrap {
159    #[inline(always)]
160    pub fn do_wrap<T>(self, value: &T) -> &NoDebugWrapper<T> {
161        unsafe { &*(value as *const T as *const _) }
162    }
163}
164
165#[doc(hidden)]
166pub struct Wrapper<T>(pub T);
167
168impl<T: Debug> TryDebugWrap for &Wrapper<T> {
169    type Wrap = DebugWrap;
170
171    #[inline]
172    fn wrap(&self) -> Self::Wrap {
173        DebugWrap
174    }
175}
176impl<T> TryDebugWrap for Wrapper<T> {
177    type Wrap = NoDebugWrap;
178
179    #[inline]
180    fn wrap(&self) -> Self::Wrap {
181        NoDebugWrap
182    }
183}
184
185#[doc(hidden)]
186pub trait TryDebugWrap {
187    type Wrap;
188    fn wrap(&self) -> Self::Wrap;
189}
190
191#[doc(hidden)]
192pub mod expr {
193    #[derive(Copy, Clone)]
194    pub struct AndExpr<Lhs, Rhs> {
195        pub lhs: Lhs,
196        pub rhs: Rhs,
197    }
198
199    #[derive(Copy, Clone)]
200    pub struct OrExpr<Lhs, Rhs> {
201        pub lhs: Lhs,
202        pub rhs: Rhs,
203    }
204}
205
206use atomic::*;
207use expr::*;
208
209#[doc(hidden)]
210pub type PtrToDebug = for<'a> unsafe fn(*const ()) -> &'static dyn Debug;
211
212unsafe fn as_debug_vptr_impl<T: Debug>(ptr: *const ()) -> &'static dyn Debug {
213    core::mem::transmute::<&'_ dyn Debug, &'static dyn Debug>((&*(ptr as *const T)) as &dyn Debug)
214}
215
216#[doc(hidden)]
217#[inline(always)]
218pub const fn as_debug_vptr<T: Debug>() -> for<'a> unsafe fn(*const ()) -> &'static dyn Debug {
219    as_debug_vptr_impl::<T>
220}
221
222#[doc(hidden)]
223pub trait FromParts<'a> {
224    type Result;
225    type Source;
226    type VTable;
227    type Debug;
228    fn from_parts(
229        result: Self::Result,
230        source: &'a Self::Source,
231        vtable: &'a Self::VTable,
232        debug: &'a Self::Debug,
233        message: core::fmt::Arguments<'a>,
234    ) -> Self;
235}
236impl<'a, Result, Source, Debug, VTable> FromParts<'a>
237    for DebugMessage<'a, Result, Source, VTable, Debug>
238{
239    type Result = Result;
240    type Source = Source;
241    type Debug = Debug;
242    type VTable = VTable;
243    #[inline(always)]
244    fn from_parts(
245        result: Result,
246        source: &'a Source,
247        vtable: &'a VTable,
248        debug: &'a Debug,
249        message: core::fmt::Arguments<'a>,
250    ) -> Self {
251        Self {
252            result,
253            source,
254            debug,
255            vtable,
256            message,
257        }
258    }
259}
260
261#[doc(hidden)]
262pub struct DebugMessage<'a, Result, Source, VTable, Debug> {
263    pub result: Result,
264    pub source: &'a Source,
265    pub debug: &'a Debug,
266    pub vtable: &'a VTable,
267    pub message: core::fmt::Arguments<'a>,
268}
269
270impl Debug for DebugMessage<'_, bool, &'static str, (), bool> {
271    fn fmt(&self, f: &mut Formatter) -> Result {
272        let source = &self.source;
273        let debug = &self.debug;
274        write!(f, "Assertion failed: {source}\n")?;
275        write!(f, "- {source} = {debug:#?}")
276    }
277}
278
279impl Debug
280    for DebugMessage<
281        '_,
282        bool,
283        EqExpr<&'static str, &'static str>,
284        (PtrToDebug, PtrToDebug),
285        EqExpr<*const (), *const ()>,
286    >
287{
288    fn fmt(&self, f: &mut Formatter) -> Result {
289        let lhs_source = &self.source.lhs;
290        let rhs_source = &self.source.rhs;
291        let lhs = unsafe { self.vtable.0(self.debug.lhs) };
292        let rhs = unsafe { self.vtable.1(self.debug.rhs) };
293        write!(f, "Assertion failed: {lhs_source} == {rhs_source}\n")?;
294        write!(f, "- {lhs_source} = {lhs:#?}\n")?;
295        write!(f, "- {rhs_source} = {rhs:#?}")
296    }
297}
298impl Debug
299    for DebugMessage<
300        '_,
301        bool,
302        NeExpr<&'static str, &'static str>,
303        (PtrToDebug, PtrToDebug),
304        NeExpr<*const (), *const ()>,
305    >
306{
307    fn fmt(&self, f: &mut Formatter) -> Result {
308        let lhs_source = &self.source.lhs;
309        let rhs_source = &self.source.rhs;
310        let lhs = unsafe { self.vtable.0(self.debug.lhs) };
311        let rhs = unsafe { self.vtable.1(self.debug.rhs) };
312        write!(f, "Assertion failed: {lhs_source} != {rhs_source}\n")?;
313        write!(f, "- {lhs_source} = {lhs:#?}\n")?;
314        write!(f, "- {rhs_source} = {rhs:#?}")
315    }
316}
317impl Debug
318    for DebugMessage<
319        '_,
320        bool,
321        LtExpr<&'static str, &'static str>,
322        (PtrToDebug, PtrToDebug),
323        LtExpr<*const (), *const ()>,
324    >
325{
326    fn fmt(&self, f: &mut Formatter) -> Result {
327        let lhs_source = &self.source.lhs;
328        let rhs_source = &self.source.rhs;
329        let lhs = unsafe { self.vtable.0(self.debug.lhs) };
330        let rhs = unsafe { self.vtable.1(self.debug.rhs) };
331        write!(f, "Assertion failed: {lhs_source} < {rhs_source}\n")?;
332        write!(f, "- {lhs_source} = {lhs:#?}\n")?;
333        write!(f, "- {rhs_source} = {rhs:#?}")
334    }
335}
336impl Debug
337    for DebugMessage<
338        '_,
339        bool,
340        LeExpr<&'static str, &'static str>,
341        (PtrToDebug, PtrToDebug),
342        LeExpr<*const (), *const ()>,
343    >
344{
345    fn fmt(&self, f: &mut Formatter) -> Result {
346        let lhs_source = &self.source.lhs;
347        let rhs_source = &self.source.rhs;
348        let lhs = unsafe { self.vtable.0(self.debug.lhs) };
349        let rhs = unsafe { self.vtable.1(self.debug.rhs) };
350        write!(f, "Assertion failed: {lhs_source} <= {rhs_source}\n")?;
351        write!(f, "- {lhs_source} = {lhs:#?}\n")?;
352        write!(f, "- {rhs_source} = {rhs:#?}")
353    }
354}
355impl Debug
356    for DebugMessage<
357        '_,
358        bool,
359        GtExpr<&'static str, &'static str>,
360        (PtrToDebug, PtrToDebug),
361        GtExpr<*const (), *const ()>,
362    >
363{
364    fn fmt(&self, f: &mut Formatter) -> Result {
365        let lhs_source = &self.source.lhs;
366        let rhs_source = &self.source.rhs;
367        let lhs = unsafe { self.vtable.0(self.debug.lhs) };
368        let rhs = unsafe { self.vtable.1(self.debug.rhs) };
369        write!(f, "Assertion failed: {lhs_source} > {rhs_source}\n")?;
370        write!(f, "- {lhs_source} = {lhs:#?}\n")?;
371        write!(f, "- {rhs_source} = {rhs:#?}")
372    }
373}
374impl Debug
375    for DebugMessage<
376        '_,
377        bool,
378        GeExpr<&'static str, &'static str>,
379        (PtrToDebug, PtrToDebug),
380        GeExpr<*const (), *const ()>,
381    >
382{
383    fn fmt(&self, f: &mut Formatter) -> Result {
384        let lhs_source = &self.source.lhs;
385        let rhs_source = &self.source.rhs;
386        let lhs = unsafe { self.vtable.0(self.debug.lhs) };
387        let rhs = unsafe { self.vtable.1(self.debug.rhs) };
388        write!(f, "Assertion failed: {lhs_source} >= {rhs_source}\n")?;
389        write!(f, "- {lhs_source} = {lhs:#?}\n")?;
390        write!(f, "- {rhs_source} = {rhs:#?}")
391    }
392}
393
394impl<
395        'a,
396        LhsResult: Eval,
397        RhsResult: Eval,
398        LhsSource,
399        RhsSource,
400        LhsVTable,
401        RhsVTable,
402        LhsDebug,
403        RhsDebug,
404    > Debug
405    for DebugMessage<
406        'a,
407        AndExpr<LhsResult, RhsResult>,
408        AndExpr<LhsSource, RhsSource>,
409        (&'static LhsVTable, &'static RhsVTable),
410        AndExpr<LhsDebug, RhsDebug>,
411    >
412where
413    DebugMessage<'a, LhsResult, LhsSource, LhsVTable, LhsDebug>: Debug,
414    DebugMessage<'a, RhsResult, RhsSource, RhsVTable, RhsDebug>: Debug,
415{
416    fn fmt(&self, f: &mut Formatter) -> Result {
417        let lhs = DebugMessage {
418            result: self.result.lhs,
419            source: &self.source.lhs,
420            vtable: self.vtable.0,
421            debug: &self.debug.lhs,
422            message: core::format_args!(""),
423        };
424        let rhs = DebugMessage {
425            result: self.result.rhs,
426            source: &self.source.rhs,
427            vtable: self.vtable.1,
428            debug: &self.debug.rhs,
429            message: core::format_args!(""),
430        };
431
432        let lhs_eval = lhs.result.eval();
433        let rhs_eval = rhs.result.eval();
434        if !(lhs_eval && rhs_eval) {
435            if !lhs_eval {
436                lhs.fmt(f)?;
437                if !rhs_eval {
438                    f.write_str("\n")?;
439                }
440            }
441            if !rhs_eval {
442                rhs.fmt(f)?;
443            }
444        }
445        Ok(())
446    }
447}
448
449impl<
450        'a,
451        LhsResult: Eval,
452        RhsResult: Eval,
453        LhsSource,
454        RhsSource,
455        LhsVTable,
456        RhsVTable,
457        LhsDebug,
458        RhsDebug,
459    > Debug
460    for DebugMessage<
461        'a,
462        OrExpr<LhsResult, RhsResult>,
463        OrExpr<LhsSource, RhsSource>,
464        (&'static LhsVTable, &'static RhsVTable),
465        OrExpr<LhsDebug, RhsDebug>,
466    >
467where
468    DebugMessage<'a, LhsResult, LhsSource, LhsVTable, LhsDebug>: Debug,
469    DebugMessage<'a, RhsResult, RhsSource, RhsVTable, RhsDebug>: Debug,
470{
471    fn fmt(&self, f: &mut Formatter) -> Result {
472        let lhs = DebugMessage {
473            result: self.result.lhs,
474            source: &self.source.lhs,
475            vtable: self.vtable.0,
476            debug: &self.debug.lhs,
477            message: core::format_args!(""),
478        };
479        let rhs = DebugMessage {
480            result: self.result.rhs,
481            source: &self.source.rhs,
482            vtable: self.vtable.1,
483            debug: &self.debug.rhs,
484            message: core::format_args!(""),
485        };
486
487        let lhs_eval = lhs.result.eval();
488        let rhs_eval = rhs.result.eval();
489        if !(lhs_eval || rhs_eval) {
490            if !lhs_eval {
491                lhs.fmt(f)?;
492                if !rhs_eval {
493                    f.write_str("\n")?;
494                }
495            }
496            if !rhs_eval {
497                rhs.fmt(f)?;
498            }
499        }
500        Ok(())
501    }
502}
503
504impl<'a, Result: Copy, Source, VTable, Debug> core::fmt::Debug
505    for DebugMessage<
506        'a,
507        Result,
508        Finalize<Source, u32, u32, &'static str>,
509        VTable,
510        Finalize<Debug, (), (), ()>,
511    >
512where
513    DebugMessage<'a, Result, Source, VTable, Debug>: core::fmt::Debug,
514{
515    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
516        let inner = DebugMessage {
517            result: self.result,
518            source: &self.source.expr,
519            debug: &self.debug.expr,
520            vtable: self.vtable,
521            message: format_args!(""),
522        };
523        let message = self.message;
524        write!(
525            f,
526            "Assertion failed at {}:{}:{}\n",
527            self.source.file, self.source.line, self.source.col
528        )?;
529        match message.as_str() {
530            Some(s) if s.len() == 0 => {}
531            _ => write!(f, "{message:#?}\n")?,
532        }
533        inner.fmt(f)
534    }
535}
536
537#[doc(hidden)]
538pub trait Eval: Copy {
539    fn eval(&self) -> bool;
540}
541
542impl Eval for bool {
543    #[inline(always)]
544    fn eval(&self) -> bool {
545        *self
546    }
547}
548impl<Lhs: Eval, Rhs: Eval> Eval for AndExpr<Lhs, Rhs> {
549    #[inline(always)]
550    fn eval(&self) -> bool {
551        self.lhs.eval() && self.rhs.eval()
552    }
553}
554impl<Lhs: Eval, Rhs: Eval> Eval for OrExpr<Lhs, Rhs> {
555    #[inline(always)]
556    fn eval(&self) -> bool {
557        self.lhs.eval() || self.rhs.eval()
558    }
559}
560
561#[doc(hidden)]
562pub trait DynDebug {
563    type VTable: Copy + 'static;
564    const VTABLE: &'static Self::VTable;
565}
566
567impl DynDebug for bool {
568    type VTable = ();
569    const VTABLE: &'static Self::VTable = &();
570}
571impl<Lhs: Debug, Rhs: Debug> DynDebug for EqExpr<&Lhs, &Rhs> {
572    type VTable = (PtrToDebug, PtrToDebug);
573    const VTABLE: &'static Self::VTable = &(as_debug_vptr::<Lhs>(), as_debug_vptr::<Rhs>());
574}
575impl<Lhs: Debug, Rhs: Debug> DynDebug for NeExpr<&Lhs, &Rhs> {
576    type VTable = (PtrToDebug, PtrToDebug);
577    const VTABLE: &'static Self::VTable = &(as_debug_vptr::<Lhs>(), as_debug_vptr::<Rhs>());
578}
579impl<Lhs: Debug, Rhs: Debug> DynDebug for LtExpr<&Lhs, &Rhs> {
580    type VTable = (PtrToDebug, PtrToDebug);
581    const VTABLE: &'static Self::VTable = &(as_debug_vptr::<Lhs>(), as_debug_vptr::<Rhs>());
582}
583impl<Lhs: Debug, Rhs: Debug> DynDebug for LeExpr<&Lhs, &Rhs> {
584    type VTable = (PtrToDebug, PtrToDebug);
585    const VTABLE: &'static Self::VTable = &(as_debug_vptr::<Lhs>(), as_debug_vptr::<Rhs>());
586}
587impl<Lhs: Debug, Rhs: Debug> DynDebug for GeExpr<&Lhs, &Rhs> {
588    type VTable = (PtrToDebug, PtrToDebug);
589    const VTABLE: &'static Self::VTable = &(as_debug_vptr::<Lhs>(), as_debug_vptr::<Rhs>());
590}
591impl<Lhs: Debug, Rhs: Debug> DynDebug for GtExpr<&Lhs, &Rhs> {
592    type VTable = (PtrToDebug, PtrToDebug);
593    const VTABLE: &'static Self::VTable = &(as_debug_vptr::<Lhs>(), as_debug_vptr::<Rhs>());
594}
595impl<Lhs: DynDebug, Rhs: DynDebug> DynDebug for AndExpr<Lhs, Rhs> {
596    type VTable = (&'static Lhs::VTable, &'static Rhs::VTable);
597    const VTABLE: &'static Self::VTable = &(Lhs::VTABLE, Rhs::VTABLE);
598}
599impl<Lhs: DynDebug, Rhs: DynDebug> DynDebug for OrExpr<Lhs, Rhs> {
600    type VTable = (&'static Lhs::VTable, &'static Rhs::VTable);
601    const VTABLE: &'static Self::VTable = &(Lhs::VTABLE, Rhs::VTABLE);
602}
603impl<E: DynDebug> DynDebug for Finalize<E, (), (), ()> {
604    type VTable = E::VTable;
605    const VTABLE: &'static Self::VTable = E::VTABLE;
606}
607
608#[doc(hidden)]
609pub trait Expr {
610    type Result: Eval;
611
612    fn eval_expr(&self) -> bool;
613    fn result(&self) -> Self::Result;
614}
615
616impl Expr for bool {
617    type Result = bool;
618
619    #[inline(always)]
620    fn eval_expr(&self) -> bool {
621        *self
622    }
623
624    #[inline(always)]
625    fn result(&self) -> Self::Result {
626        *self
627    }
628}
629
630impl<Lhs: PartialEq<Rhs>, Rhs> Expr for EqExpr<Lhs, Rhs> {
631    type Result = bool;
632
633    #[inline(always)]
634    fn eval_expr(&self) -> bool {
635        self.result()
636    }
637
638    #[inline(always)]
639    fn result(&self) -> Self::Result {
640        self.lhs == self.rhs
641    }
642}
643
644impl<Lhs: PartialEq<Rhs>, Rhs> Expr for NeExpr<Lhs, Rhs> {
645    type Result = bool;
646
647    #[inline(always)]
648    fn eval_expr(&self) -> bool {
649        self.result()
650    }
651
652    #[inline(always)]
653    fn result(&self) -> Self::Result {
654        self.lhs != self.rhs
655    }
656}
657
658impl<Lhs: PartialOrd<Rhs>, Rhs> Expr for LtExpr<Lhs, Rhs> {
659    type Result = bool;
660
661    #[inline(always)]
662    fn eval_expr(&self) -> bool {
663        self.result()
664    }
665
666    #[inline(always)]
667    fn result(&self) -> Self::Result {
668        self.lhs < self.rhs
669    }
670}
671
672impl<Lhs: PartialOrd<Rhs>, Rhs> Expr for LeExpr<Lhs, Rhs> {
673    type Result = bool;
674
675    #[inline(always)]
676    fn eval_expr(&self) -> bool {
677        self.result()
678    }
679
680    #[inline(always)]
681    fn result(&self) -> Self::Result {
682        self.lhs <= self.rhs
683    }
684}
685
686impl<Lhs: PartialOrd<Rhs>, Rhs> Expr for GtExpr<Lhs, Rhs> {
687    type Result = bool;
688
689    #[inline(always)]
690    fn eval_expr(&self) -> bool {
691        self.result()
692    }
693
694    #[inline(always)]
695    fn result(&self) -> Self::Result {
696        self.lhs > self.rhs
697    }
698}
699
700impl<Lhs: PartialOrd<Rhs>, Rhs> Expr for GeExpr<Lhs, Rhs> {
701    type Result = bool;
702
703    #[inline(always)]
704    fn eval_expr(&self) -> bool {
705        self.result()
706    }
707
708    #[inline(always)]
709    fn result(&self) -> Self::Result {
710        self.lhs >= self.rhs
711    }
712}
713
714#[inline(always)]
715#[doc(hidden)]
716pub fn marker<T>(_: &T) -> PhantomData<T> {
717    PhantomData
718}
719
720impl<Lhs: Expr, Rhs: Expr> Expr for AndExpr<Lhs, Rhs> {
721    type Result = AndExpr<Lhs::Result, Rhs::Result>;
722
723    #[inline(always)]
724    fn eval_expr(&self) -> bool {
725        self.lhs.eval_expr() && self.rhs.eval_expr()
726    }
727
728    #[inline(always)]
729    fn result(&self) -> Self::Result {
730        AndExpr {
731            lhs: self.lhs.result(),
732            rhs: self.rhs.result(),
733        }
734    }
735}
736
737impl<Lhs: Expr, Rhs: Expr> Expr for OrExpr<Lhs, Rhs> {
738    type Result = OrExpr<Lhs::Result, Rhs::Result>;
739
740    #[inline(always)]
741    fn eval_expr(&self) -> bool {
742        self.lhs.eval_expr() || self.rhs.eval_expr()
743    }
744
745    #[inline(always)]
746    fn result(&self) -> Self::Result {
747        OrExpr {
748            lhs: self.lhs.result(),
749            rhs: self.rhs.result(),
750        }
751    }
752}
753
754impl<E: Expr> Expr for Finalize<E, (), (), ()> {
755    type Result = E::Result;
756
757    #[inline(always)]
758    fn eval_expr(&self) -> bool {
759        self.expr.eval_expr()
760    }
761
762    #[inline(always)]
763    fn result(&self) -> Self::Result {
764        self.expr.result()
765    }
766}
767
768impl<E> Expr for &Finalize<E, (), (), ()> {
769    type Result = bool;
770
771    #[inline(always)]
772    fn eval_expr(&self) -> bool {
773        unimplemented!()
774    }
775
776    #[inline(always)]
777    fn result(&self) -> Self::Result {
778        unimplemented!()
779    }
780}
781
782impl<E: Expr> Expr for &&Finalize<E, (), (), ()> {
783    type Result = E::Result;
784
785    #[inline(always)]
786    fn eval_expr(&self) -> bool {
787        self.expr.eval_expr()
788    }
789
790    #[inline(always)]
791    fn result(&self) -> Self::Result {
792        self.expr.result()
793    }
794}
795
796#[inline(always)]
797#[doc(hidden)]
798pub const fn vtable_for<T: DynDebug>(_: &T) -> &'static T::VTable {
799    T::VTABLE
800}
801
802#[cold]
803#[inline(never)]
804#[doc(hidden)]
805#[track_caller]
806pub fn panic_failed_assert<'a, M: core::fmt::Debug + FromParts<'a>>(
807    __marker: PhantomData<M>,
808    result: M::Result,
809    source: &'a M::Source,
810    vtable: &'a M::VTable,
811    debug: &'a M::Debug,
812) -> ! {
813    panic!(
814        "{:#?}",
815        M::from_parts(result, source, vtable, debug, core::format_args!(""))
816    )
817}
818
819#[cold]
820#[inline(never)]
821#[doc(hidden)]
822#[track_caller]
823pub fn panic_failed_assert_with_message<'a, M: core::fmt::Debug + FromParts<'a>>(
824    __marker: PhantomData<M>,
825    message: core::fmt::Arguments<'a>,
826    result: M::Result,
827    source: &'a M::Source,
828    vtable: &'a M::VTable,
829    debug: &'a M::Debug,
830) -> ! {
831    panic!(
832        "{:#?}",
833        M::from_parts(result, source, vtable, debug, message)
834    )
835}
836
837#[cfg(test)]
838mod tests {
839    use super::*;
840
841    macro_rules! test_expr {
842        ($e: expr,  $debug: expr, $source: expr $(,)?) => {{
843            let e = $e;
844            if !e.eval_expr() {
845                let message = $crate::DebugMessage {
846                    result: e.result(),
847                    source: $source,
848                    vtable: vtable_for(&e),
849                    debug: $debug,
850                    message: format_args!(""),
851                };
852                let __marker = $crate::marker(&message);
853                $crate::panic_failed_assert(
854                    __marker,
855                    message.result,
856                    message.source,
857                    message.vtable,
858                    message.debug,
859                );
860            }
861        }};
862    }
863
864    #[test]
865    #[should_panic]
866    fn test_bool_expr() {
867        test_expr!(false, &false, &"oops");
868    }
869
870    #[test]
871    #[should_panic]
872    fn test_eq_expr() {
873        test_expr!(
874            EqExpr {
875                lhs: &0i32,
876                rhs: &1i32,
877            },
878            &EqExpr {
879                lhs: (&0i32) as *const _ as *const (),
880                rhs: (&1i32) as *const _ as *const (),
881            },
882            &EqExpr { lhs: "a", rhs: "b" },
883        );
884    }
885
886    #[test]
887    #[should_panic]
888    fn test_and_expr() {
889        test_expr!(
890            AndExpr {
891                lhs: false,
892                rhs: OrExpr {
893                    lhs: EqExpr { lhs: &4, rhs: &4 },
894                    rhs: EqExpr {
895                        lhs: &0i32,
896                        rhs: &1i32,
897                    },
898                },
899            },
900            &AndExpr {
901                lhs: false,
902                rhs: OrExpr {
903                    lhs: EqExpr {
904                        lhs: (&4i32) as *const _ as _,
905                        rhs: (&4i32) as *const _ as _,
906                    },
907                    rhs: EqExpr {
908                        lhs: (&0i32) as *const _ as _,
909                        rhs: (&1i32) as *const _ as _,
910                    },
911                },
912            },
913            &AndExpr {
914                lhs: "some_bool",
915                rhs: OrExpr {
916                    lhs: EqExpr { lhs: "c", rhs: "d" },
917                    rhs: EqExpr { lhs: "a", rhs: "b" },
918                },
919            },
920        );
921    }
922
923    mod macro_export {
924        use super::*;
925
926        #[test]
927        #[should_panic]
928        fn test_assert() {
929            assert!(false);
930        }
931
932        #[cfg(not(debug_assertions))]
933        #[test]
934        fn test_debug_assert() {
935            debug_assert!(false);
936        }
937
938        #[cfg(debug_assertions)]
939        #[test]
940        #[should_panic]
941        fn test_debug_assert() {
942            debug_assert!(false);
943        }
944    }
945}