1#![no_std]
2
3use core::fmt;
4
5#[doc(hidden)]
6pub use equator_macro as imp;
7
8#[macro_export]
9#[doc(hidden)]
10macro_rules! fmt_imp {
11 () => {
12 ()
13 };
14 ($($tt:tt)*) => {
15 ::core::format_args!($($tt)*)
16 };
17}
18
19#[macro_export]
20#[doc(hidden)]
21macro_rules! source_imp {
22 (all()) => { () };
23 (any()) => { () };
24
25 (all(($($head:tt)*))) => { $crate::source_imp!($($head)*) };
26 (any(($($head:tt)*))) => { $crate::source_imp!($($head)*) };
27
28 (all(($($head:tt)*) $($tail:tt)+)) => {
29 const{$crate::expr::AndExpr {
30 lhs: &$crate::source_imp!($($head)*),
31 rhs: &$crate::source_imp!(all($($tail)+)),
32 }}
33 };
34 (any(($($head:tt)*) $($tail:tt)+)) => {
35 const{$crate::expr::OrExpr {
36 lhs: &$crate::source_imp!($($head)*),
37 rhs: &$crate::source_imp!(any($($tail)+)),
38 }}
39 };
40
41 (<($lhs: expr, $rhs: expr)) => {
42 const{$crate::expr::CmpExpr {
43 cmp: "<",
44 lhs: ::core::stringify!($lhs),
45 rhs: ::core::stringify!($rhs),
46 }}
47 };
48 (>($lhs: expr, $rhs: expr)) => {
49 const{$crate::expr::CmpExpr {
50 cmp: ">",
51 lhs: ::core::stringify!($lhs),
52 rhs: ::core::stringify!($rhs),
53 }}
54 };
55 (<=($lhs: expr, $rhs: expr)) => {
56 const{$crate::expr::CmpExpr {
57 cmp: "<=",
58 lhs: ::core::stringify!($lhs),
59 rhs: ::core::stringify!($rhs),
60 }}
61 };
62 (>=($lhs: expr, $rhs: expr)) => {
63 const{$crate::expr::CmpExpr {
64 cmp: ">=",
65 lhs: ::core::stringify!($lhs),
66 rhs: ::core::stringify!($rhs),
67 }}
68 };
69 (==($lhs: expr, $rhs: expr)) => {
70 const{$crate::expr::CmpExpr {
71 cmp: "==",
72 lhs: ::core::stringify!($lhs),
73 rhs: ::core::stringify!($rhs),
74 }}
75 };
76 (!=($lhs: expr, $rhs: expr)) => {
77 const{$crate::expr::CmpExpr {
78 cmp: "!=",
79 lhs: ::core::stringify!($lhs),
80 rhs: ::core::stringify!($rhs),
81 }}
82 };
83 ($test:expr,($lhs: expr, $rhs: expr)) => {const{$crate::expr::CmpExpr {
84 cmp: ::core::stringify!($test),
85 lhs: ::core::stringify!($lhs),
86 rhs: ::core::stringify!($rhs),
87 }}};
88 ($test:expr,~($lhs: expr, $rhs: expr)) => {const{$crate::expr::CmpExpr {
89 cmp: "~",
90 lhs: ::core::stringify!($lhs),
91 rhs: ::core::stringify!($rhs),
92 }}};
93 ($cond:expr) => { ::core::stringify!($cond) };
94}
95
96#[macro_export]
97#[doc(hidden)]
98macro_rules! assert_imp {
99 (all()) => { true };
100 (any()) => { false };
101
102 (all(($($head:tt)*))) => { $crate::assert_imp!($($head)*) };
103 (any(($($head:tt)*))) => { $crate::assert_imp!($($head)*) };
104
105 (all(($($head:tt)*) $($tail:tt)+)) => {
106 $crate::expr::AndExpr {
107 lhs: $crate::assert_imp!($($head)*),
108 rhs: $crate::assert_imp!(all($($tail)+)),
109 }
110 };
111 (any(($($head:tt)*) $($tail:tt)+)) => {
112 $crate::expr::OrExpr {
113 lhs: $crate::assert_imp!($($head)*),
114 rhs: $crate::assert_imp!(any($($tail)+)),
115 }
116 };
117
118 (<($lhs: expr, $rhs: expr)) => {
119 $crate::expr::CmpExpr {
120 cmp: &$crate::Lt,
121 lhs: $crate::Ref{inner: &$lhs}.get(),
122 rhs: $crate::Ref{inner: &$rhs}.get(),
123 }
124 };
125 (>($lhs: expr, $rhs: expr)) => {
126 $crate::expr::CmpExpr {
127 cmp: &$crate::Gt,
128 lhs: $crate::Ref{inner: &$lhs}.get(),
129 rhs: $crate::Ref{inner: &$rhs}.get(),
130 }
131 };
132 (<=($lhs: expr, $rhs: expr)) => {
133 $crate::expr::CmpExpr {
134 cmp: &$crate::Le,
135 lhs: $crate::Ref{inner: &$lhs}.get(),
136 rhs: $crate::Ref{inner: &$rhs}.get(),
137 }
138 };
139 (>=($lhs: expr, $rhs: expr)) => {
140 $crate::expr::CmpExpr {
141 cmp: &$crate::Ge,
142 lhs: $crate::Ref{inner: &$lhs}.get(),
143 rhs: $crate::Ref{inner: &$rhs}.get(),
144 }
145 };
146 (==($lhs: expr, $rhs: expr)) => {
147 $crate::expr::CmpExpr {
148 cmp: &$crate::Eq,
149 lhs: $crate::Ref{inner: &$lhs}.get(),
150 rhs: $crate::Ref{inner: &$rhs}.get(),
151 }
152 };
153 (!=($lhs: expr, $rhs: expr)) => {
154 $crate::expr::CmpExpr {
155 cmp: &$crate::Ne,
156 lhs: $crate::Ref{inner: &$lhs}.get(),
157 rhs: $crate::Ref{inner: &$rhs}.get(),
158 }
159 };
160 ($test:expr,($lhs: expr, $rhs: expr)) => {$crate::expr::CmpExpr {
161 cmp: &$test,
162 lhs: $crate::Ref{inner: &$lhs}.get(),
163 rhs: $crate::Ref{inner: &$rhs}.get(),
164 }};
165 ($test:expr,~($lhs: expr, $rhs: expr)) => {$crate::expr::CmpExpr {
166 cmp: &$test,
167 lhs: $crate::Ref{inner: &$lhs}.get(),
168 rhs: $crate::Ref{inner: &$rhs}.get(),
169 }};
170 ($cond:expr) => { $cond };
171}
172
173#[macro_export]
174macro_rules! assert {
175 ($($tokens: tt)*) => {
176 $crate::imp::assert!(($crate) $($tokens)*)
177 };
178}
179
180#[macro_export]
181macro_rules! debug_assert {
182 ($($tokens: tt)*) => {
183 if cfg!(debug_assertions) {
184 $crate::imp::assert!(($crate) $($tokens)*)
185 }
186 };
187}
188
189#[doc(hidden)]
190#[doc(hidden)]
192#[doc(hidden)]
194#[doc(hidden)]
196#[doc(hidden)]
198pub mod expr {
199 #[derive(Copy, Clone, Debug)]
200 #[repr(C)]
201 pub struct CmpExpr<Cmp, Lhs, Rhs> {
202 pub cmp: Cmp,
203 pub lhs: Lhs,
204 pub rhs: Rhs,
205 }
206
207 #[derive(Copy, Clone)]
208 #[repr(C)]
209 pub struct Cmp {
210 pub cmp: *const (),
211 pub lhs: core::mem::MaybeUninit<*const ()>,
212 pub rhs: core::mem::MaybeUninit<*const ()>,
213 }
214
215 #[derive(Copy, Clone)]
216 #[repr(C)]
217 pub struct CustomCmp {
218 pub cmp: *const (),
219 pub lhs: *const (),
220 pub rhs: *const (),
221 }
222
223 #[derive(Copy, Clone, Debug)]
224 #[repr(C)]
225 pub struct CustomCmpExpr<Cmp, Lhs, Rhs> {
226 pub cmp: Cmp,
227 pub lhs: Lhs,
228 pub rhs: Rhs,
229 }
230
231 #[derive(Copy, Clone, Debug)]
232 pub struct AndExpr<Lhs, Rhs> {
233 pub lhs: Lhs,
234 pub rhs: Rhs,
235 }
236
237 #[derive(Copy, Clone, Debug)]
238 pub struct OrExpr<Lhs, Rhs> {
239 pub lhs: Lhs,
240 pub rhs: Rhs,
241 }
242}
243
244pub trait Cmp<Lhs: ?Sized, Rhs: ?Sized> {
245 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> bool;
246}
247
248#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
249pub struct Eq;
250#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
251pub struct Ne;
252#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
253pub struct Le;
254#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
255pub struct Ge;
256#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
257pub struct Lt;
258#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
259pub struct Gt;
260
261impl<Rhs: ?Sized, Lhs: ?Sized + PartialEq<Rhs>> Cmp<Lhs, Rhs> for Eq {
262 #[inline(always)]
263 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> bool {
264 *lhs == *rhs
265 }
266}
267impl<Rhs: ?Sized, Lhs: ?Sized + PartialEq<Rhs>> Cmp<Lhs, Rhs> for Ne {
268 #[inline(always)]
269 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> bool {
270 *lhs != *rhs
271 }
272}
273impl<Rhs: ?Sized, Lhs: ?Sized + PartialOrd<Rhs>> Cmp<Lhs, Rhs> for Le {
274 #[inline(always)]
275 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> bool {
276 *lhs <= *rhs
277 }
278}
279impl<Rhs: ?Sized, Lhs: ?Sized + PartialOrd<Rhs>> Cmp<Lhs, Rhs> for Ge {
280 #[inline(always)]
281 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> bool {
282 *lhs >= *rhs
283 }
284}
285impl<Rhs: ?Sized, Lhs: ?Sized + PartialOrd<Rhs>> Cmp<Lhs, Rhs> for Lt {
286 #[inline(always)]
287 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> bool {
288 *lhs < *rhs
289 }
290}
291impl<Rhs: ?Sized, Lhs: ?Sized + PartialOrd<Rhs>> Cmp<Lhs, Rhs> for Gt {
292 #[inline(always)]
293 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> bool {
294 *lhs > *rhs
295 }
296}
297
298#[doc(hidden)]
299pub struct CmpExpr;
300#[doc(hidden)]
301pub struct CustomCmpExpr<E>(pub core::marker::PhantomData<E>);
302#[doc(hidden)]
303pub struct AndExpr<L, R>(pub L, pub R);
304#[doc(hidden)]
305pub struct OrExpr<L, R>(pub L, pub R);
306
307#[doc(hidden)]
308pub struct Message<'a>(pub core::fmt::Arguments<'a>);
309#[doc(hidden)]
310pub struct NoMessage;
311
312impl From<NoMessage> for core::fmt::Arguments<'_> {
313 fn from(_: NoMessage) -> Self {
314 core::format_args!("")
315 }
316}
317
318impl<'a> From<Message<'a>> for core::fmt::Arguments<'a> {
319 fn from(t: Message<'a>) -> Self {
320 t.0
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use super::*;
327
328 #[test]
329 #[should_panic]
330 fn test_assert() {
331 assert!(false);
332 }
333
334 #[cfg(debug_assertions)]
335 #[test]
336 #[should_panic]
337 fn test_debug_assert() {
338 debug_assert!(false);
339 }
340}
341
342pub trait Panic: Copy {
343 type Lhs: Copy;
344 type Rhs: Copy;
345 type Cmp: Copy;
346 type Source: 'static;
347 type VTable: 'static;
348 type Result: Copy;
349
350 fn into_parts(self) -> (Self::Lhs, Self::Rhs, Self::Cmp);
351 unsafe fn from_parts(lhs: Self::Lhs, rhs: Self::Rhs, cmp: Self::Cmp) -> Self;
352 fn explain(self, source: &Self::Source, result: Self::Result, vtable: &'static Self::VTable, f: &mut fmt::Formatter) -> fmt::Result;
353 fn test(&self, vtable: &'static Self::VTable) -> Self::Result;
354 fn reduce(result: Self::Result) -> bool;
355}
356
357pub trait Test: Sized {
358 type Panic: Panic;
359 const VTABLE: &'static <Self::Panic as Panic>::VTable;
360
361 fn test(&self) -> bool;
362 fn as_dyn(self) -> Self::Panic;
363}
364
365pub trait Fmt<'a>: Sized {
366 fn fmt(&self) -> &core::fmt::Arguments<'a>;
367}
368
369impl<'a> Fmt<'a> for () {
370 #[inline(always)]
371 fn fmt(&self) -> &core::fmt::Arguments<'a> {
372 const { &format_args!("") }
373 }
374}
375
376impl<'a> Fmt<'a> for core::fmt::Arguments<'a> {
377 #[inline(always)]
378 fn fmt(&self) -> &core::fmt::Arguments<'a> {
379 self
380 }
381}
382
383impl Panic for bool {
384 type Cmp = ();
385 type Lhs = bool;
386 type Result = bool;
387 type Rhs = ();
388 type Source = &'static str;
389 type VTable = ();
390
391 #[inline(always)]
392 fn into_parts(self) -> (Self::Lhs, Self::Rhs, Self::Cmp) {
393 (self, (), ())
394 }
395
396 #[inline(always)]
397 unsafe fn from_parts(lhs: Self::Lhs, _: Self::Rhs, _: Self::Cmp) -> Self {
398 lhs
399 }
400
401 fn explain(self, source: &Self::Source, result: Self::Result, _: &'static Self::VTable, f: &mut fmt::Formatter) -> fmt::Result {
402 write!(f, "Assertion failed: {source}\n")?;
403 write!(f, "- {source} = {result:#?}")
404 }
405
406 fn test(&self, _: &'static Self::VTable) -> Self::Result {
407 *self
408 }
409
410 fn reduce(result: Self::Result) -> bool {
411 result
412 }
413}
414
415impl Test for bool {
416 type Panic = bool;
417
418 const VTABLE: &'static <Self::Panic as Panic>::VTable = &();
419
420 #[inline(always)]
421 fn test(&self) -> bool {
422 *self
423 }
424
425 #[inline(always)]
426 fn as_dyn(self) -> Self::Panic {
427 self
428 }
429}
430
431impl Panic for expr::Cmp {
432 type Cmp = *const ();
433 type Lhs = core::mem::MaybeUninit<*const ()>;
434 type Result = bool;
435 type Rhs = core::mem::MaybeUninit<*const ()>;
436 type Source = expr::CmpExpr<&'static str, &'static str, &'static str>;
437 type VTable = expr::CmpExpr<
438 fn(*const (), core::mem::MaybeUninit<*const ()>, core::mem::MaybeUninit<*const ()>) -> bool,
439 fn(core::mem::MaybeUninit<*const ()>, f: &mut fmt::Formatter<'_>) -> fmt::Result,
440 fn(core::mem::MaybeUninit<*const ()>, f: &mut fmt::Formatter<'_>) -> fmt::Result,
441 >;
442
443 #[inline(always)]
444 fn into_parts(self) -> (Self::Lhs, Self::Rhs, Self::Cmp) {
445 (self.lhs, self.rhs, self.cmp)
446 }
447
448 #[inline(always)]
449 unsafe fn from_parts(lhs: Self::Lhs, rhs: Self::Rhs, cmp: Self::Cmp) -> Self {
450 Self { cmp, lhs, rhs }
451 }
452
453 fn explain(self, source: &Self::Source, _: Self::Result, vtable: &'static Self::VTable, f: &mut fmt::Formatter) -> fmt::Result {
454 let expr::CmpExpr { lhs, rhs, cmp } = *source;
455 write!(f, "Assertion failed: {lhs} {cmp} {rhs}\n")?;
456 write!(f, "- {lhs} = ")?;
457 (vtable.lhs)(self.lhs, f)?;
458 write!(f, "\n- {rhs} = ")?;
459 (vtable.rhs)(self.rhs, f)
460 }
461
462 fn test(&self, vtable: &'static Self::VTable) -> Self::Result {
463 (vtable.cmp)(self.cmp, self.lhs, self.rhs)
464 }
465
466 fn reduce(result: Self::Result) -> bool {
467 result
468 }
469}
470
471impl<C: Cmp<L, R>, L: fmt::Debug, R: fmt::Debug> Test for expr::CmpExpr<&C, &L, &R> {
472 type Panic = expr::Cmp;
473
474 const VTABLE: &'static <Self::Panic as Panic>::VTable = &const {
475 unsafe {
476 if const {
477 size_of::<L>() <= size_of::<core::mem::MaybeUninit<*const ()>>()
478 && size_of::<R>() <= size_of::<core::mem::MaybeUninit<*const ()>>()
479 && !core::mem::needs_drop::<L>()
480 && !core::mem::needs_drop::<R>()
481 } {
482 expr::CmpExpr {
483 cmp: core::mem::transmute(
484 (|c, l, r| C::test(c, &*(&raw const l as *const L), &*(&raw const r as *const R)))
485 as fn(&C, core::mem::MaybeUninit<*const ()>, core::mem::MaybeUninit<*const ()>) -> bool,
486 ),
487 lhs: core::mem::transmute(
488 (|x, f| L::fmt(&*(&raw const x as *const L), f))
489 as fn(core::mem::MaybeUninit<*const ()>, &mut fmt::Formatter<'_>) -> fmt::Result,
490 ),
491 rhs: core::mem::transmute(
492 (|x, f| R::fmt(&*(&raw const x as *const R), f))
493 as fn(core::mem::MaybeUninit<*const ()>, &mut fmt::Formatter<'_>) -> fmt::Result,
494 ),
495 }
496 } else {
497 expr::CmpExpr {
498 cmp: core::mem::transmute(C::test as fn(&C, &L, &R) -> bool),
499 lhs: core::mem::transmute(L::fmt as fn(&L, &mut fmt::Formatter<'_>) -> fmt::Result),
500 rhs: core::mem::transmute(R::fmt as fn(&R, &mut fmt::Formatter<'_>) -> fmt::Result),
501 }
502 }
503 }
504 };
505
506 #[inline(always)]
507 fn test(&self) -> bool {
508 self.cmp.test(&self.lhs, &self.rhs)
509 }
510
511 #[inline(always)]
512 fn as_dyn(self) -> Self::Panic {
513 if const {
514 size_of::<L>() <= size_of::<core::mem::MaybeUninit<*const ()>>()
515 && size_of::<R>() <= size_of::<core::mem::MaybeUninit<*const ()>>()
516 && !core::mem::needs_drop::<L>()
517 && !core::mem::needs_drop::<R>()
518 } {
519 let mut uninit = expr::Cmp {
520 cmp: self.cmp as *const C as *const (),
521 lhs: core::mem::MaybeUninit::zeroed(),
522 rhs: core::mem::MaybeUninit::zeroed(),
523 };
524 unsafe {
525 (&raw mut uninit.lhs as *mut L).write((&raw const *self.lhs).read());
526 (&raw mut uninit.rhs as *mut R).write((&raw const *self.rhs).read());
527 }
528 uninit
529 } else {
530 expr::Cmp {
531 cmp: self.cmp as *const C as *const (),
532 lhs: core::mem::MaybeUninit::new(self.lhs as *const L as *const ()),
533 rhs: core::mem::MaybeUninit::new(self.rhs as *const R as *const ()),
534 }
535 }
536 }
537}
538
539impl<L: Panic, R: Panic> Panic for expr::AndExpr<L, R> {
540 type Cmp = expr::AndExpr<L::Cmp, R::Cmp>;
541 type Lhs = expr::AndExpr<L::Lhs, R::Lhs>;
542 type Result = expr::AndExpr<L::Result, R::Result>;
543 type Rhs = expr::AndExpr<L::Rhs, R::Rhs>;
544 type Source = expr::AndExpr<&'static L::Source, &'static R::Source>;
545 type VTable = expr::AndExpr<&'static L::VTable, &'static R::VTable>;
546
547 #[inline(always)]
548 fn into_parts(self) -> (Self::Lhs, Self::Rhs, Self::Cmp) {
549 let lhs = self.lhs.into_parts();
550 let rhs = self.rhs.into_parts();
551
552 (
553 expr::AndExpr { lhs: lhs.0, rhs: rhs.0 },
554 expr::AndExpr { lhs: lhs.1, rhs: rhs.1 },
555 expr::AndExpr { lhs: lhs.2, rhs: rhs.2 },
556 )
557 }
558
559 #[inline(always)]
560 unsafe fn from_parts(lhs: Self::Lhs, rhs: Self::Rhs, cmp: Self::Cmp) -> Self {
561 Self {
562 lhs: L::from_parts(lhs.lhs, rhs.lhs, cmp.lhs),
563 rhs: R::from_parts(lhs.rhs, rhs.rhs, cmp.rhs),
564 }
565 }
566
567 fn explain(self, source: &Self::Source, result: Self::Result, vtable: &'static Self::VTable, f: &mut fmt::Formatter) -> fmt::Result {
568 let lhs_eval = L::reduce(result.lhs);
569 let rhs_eval = R::reduce(result.rhs);
570 if !(lhs_eval && rhs_eval) {
571 if !lhs_eval {
572 self.lhs.explain(source.lhs, result.lhs, vtable.lhs, f)?;
573 if !rhs_eval {
574 f.write_str("\n")?;
575 }
576 }
577 if !rhs_eval {
578 self.rhs.explain(source.rhs, result.rhs, vtable.rhs, f)?;
579 }
580 }
581 Ok(())
582 }
583
584 fn test(&self, vtable: &'static Self::VTable) -> Self::Result {
585 Self::Result {
586 lhs: self.lhs.test(vtable.lhs),
587 rhs: self.rhs.test(vtable.rhs),
588 }
589 }
590
591 fn reduce(result: Self::Result) -> bool {
592 L::reduce(result.lhs) && R::reduce(result.rhs)
593 }
594}
595
596impl<L: Test, R: Test> Test for expr::AndExpr<L, R> {
597 type Panic = expr::AndExpr<L::Panic, R::Panic>;
598
599 const VTABLE: &'static <Self::Panic as Panic>::VTable = &const {
600 expr::AndExpr {
601 lhs: L::VTABLE,
602 rhs: R::VTABLE,
603 }
604 };
605
606 #[inline(always)]
607 fn test(&self) -> bool {
608 self.lhs.test() & self.rhs.test()
609 }
610
611 #[inline(always)]
612 fn as_dyn(self) -> Self::Panic {
613 Self::Panic {
614 lhs: self.lhs.as_dyn(),
615 rhs: self.rhs.as_dyn(),
616 }
617 }
618}
619
620impl<L: Panic, R: Panic> Panic for expr::OrExpr<L, R> {
621 type Cmp = expr::OrExpr<L::Cmp, R::Cmp>;
622 type Lhs = expr::OrExpr<L::Lhs, R::Lhs>;
623 type Result = expr::OrExpr<L::Result, R::Result>;
624 type Rhs = expr::OrExpr<L::Rhs, R::Rhs>;
625 type Source = expr::OrExpr<&'static L::Source, &'static R::Source>;
626 type VTable = expr::OrExpr<&'static L::VTable, &'static R::VTable>;
627
628 #[inline(always)]
629 fn into_parts(self) -> (Self::Lhs, Self::Rhs, Self::Cmp) {
630 let lhs = self.lhs.into_parts();
631 let rhs = self.rhs.into_parts();
632
633 (
634 expr::OrExpr { lhs: lhs.0, rhs: rhs.0 },
635 expr::OrExpr { lhs: lhs.1, rhs: rhs.1 },
636 expr::OrExpr { lhs: lhs.2, rhs: rhs.2 },
637 )
638 }
639
640 #[inline(always)]
641 unsafe fn from_parts(lhs: Self::Lhs, rhs: Self::Rhs, cmp: Self::Cmp) -> Self {
642 Self {
643 lhs: L::from_parts(lhs.lhs, rhs.lhs, cmp.lhs),
644 rhs: R::from_parts(lhs.rhs, rhs.rhs, cmp.rhs),
645 }
646 }
647
648 fn explain(self, source: &Self::Source, result: Self::Result, vtable: &'static Self::VTable, f: &mut fmt::Formatter) -> fmt::Result {
649 let lhs_eval = L::reduce(result.lhs);
650 let rhs_eval = R::reduce(result.rhs);
651 if !(lhs_eval || rhs_eval) {
652 self.lhs.explain(source.lhs, result.lhs, vtable.lhs, f)?;
653 self.rhs.explain(source.rhs, result.rhs, vtable.rhs, f)?;
654 }
655 Ok(())
656 }
657
658 fn test(&self, vtable: &'static Self::VTable) -> Self::Result {
659 Self::Result {
660 lhs: self.lhs.test(vtable.lhs),
661 rhs: self.rhs.test(vtable.rhs),
662 }
663 }
664
665 fn reduce(result: Self::Result) -> bool {
666 L::reduce(result.lhs) || R::reduce(result.rhs)
667 }
668}
669
670impl<L: Test, R: Test> Test for expr::OrExpr<L, R> {
671 type Panic = expr::OrExpr<L::Panic, R::Panic>;
672
673 const VTABLE: &'static <Self::Panic as Panic>::VTable = &const {
674 expr::OrExpr {
675 lhs: L::VTABLE,
676 rhs: R::VTABLE,
677 }
678 };
679
680 #[inline(always)]
681 fn test(&self) -> bool {
682 self.lhs.test() | self.rhs.test()
683 }
684
685 #[inline(always)]
686 fn as_dyn(self) -> Self::Panic {
687 Self::Panic {
688 lhs: self.lhs.as_dyn(),
689 rhs: self.rhs.as_dyn(),
690 }
691 }
692}
693
694#[track_caller]
695#[inline(always)]
696pub fn do_panic<'a, T: Test>(source: &'static WithSource<<T::Panic as Panic>::Source>, test: T, fmt: impl Fmt<'a>) {
697 let success = test.test();
698 let panic = test.as_dyn();
699 let (lhs, rhs, cmp) = panic.into_parts();
700 if !success {
701 do_panic_impl::<T::Panic>(lhs, rhs, cmp, source, T::VTABLE, fmt.fmt())
702 }
703}
704
705#[track_caller]
706#[inline(never)]
707fn do_panic_impl<'a, P: Panic>(
708 lhs: P::Lhs,
709 rhs: P::Rhs,
710 cmp: P::Cmp,
711 source: &'static WithSource<P::Source>,
712 vtable: &'static P::VTable,
713 fmt: &core::fmt::Arguments<'_>,
714) -> ! {
715 struct Debug<'a, P: Panic> {
716 lhs: P::Lhs,
717 rhs: P::Rhs,
718 cmp: P::Cmp,
719 source: &'static WithSource<P::Source>,
720 vtable: &'static P::VTable,
721 fmt: &'a core::fmt::Arguments<'a>,
722 }
723 impl<P: Panic> fmt::Debug for Debug<'_, P> {
724 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
725 let Self {
726 lhs,
727 rhs,
728 cmp,
729 source,
730 vtable,
731 fmt,
732 } = self;
733
734 write!(f, "Assertion failed at {}:{}:{}\n", source.file, source.line, source.col)?;
735 if fmt.as_str() != Some("") {
736 write!(f, "{fmt:#?}\n")?;
737 }
738 let p = unsafe { P::from_parts(*lhs, *rhs, *cmp) };
739
740 let result = p.test(vtable);
741 p.explain(&source.source, result, vtable, f)
742 }
743 }
744
745 panic!(
746 "{:#?}",
747 Debug::<P> {
748 lhs,
749 rhs,
750 cmp,
751 source,
752 vtable,
753 fmt
754 }
755 );
756}
757
758pub struct Ref<'a, T: ?Sized> {
759 pub inner: &'a T,
760}
761
762impl<'a, T> Ref<'a, T> {
763 #[inline(always)]
764 pub const fn get(&self) -> &'a T {
765 self.inner
766 }
767}
768
769impl<'a, T> Ref<'a, [T]> {
770 #[inline(always)]
771 pub const fn get(&self) -> &&'a [T] {
772 &self.inner
773 }
774}
775
776#[derive(Copy, Clone)]
777pub struct WithSource<S> {
778 pub source: S,
779 pub file: &'static str,
780 pub line: u32,
781 pub col: u32,
782}