[go: up one dir, main page]

equator/
lib.rs

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// pub mod decompose;
191#[doc(hidden)]
192// pub mod spec;
193#[doc(hidden)]
194// pub mod structures;
195#[doc(hidden)]
196// pub mod traits;
197#[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}