1#![no_std]
2
3use core::fmt;
4
5#[doc(hidden)]
6pub use equator_macro as imp;
7
8#[macro_export]
9macro_rules! assert {
10 ($($tokens: tt)*) => {
11 $crate::imp::assert!($crate, $($tokens)*)
12 };
13}
14
15#[macro_export]
16macro_rules! debug_assert {
17 ($($tokens: tt)*) => {
18 if cfg!(debug_assertions) {
19 $crate::imp::assert!($crate, $($tokens)*)
20 }
21 };
22}
23
24#[doc(hidden)]
25pub mod decompose;
26#[doc(hidden)]
27pub mod spec;
28#[doc(hidden)]
29pub mod structures;
30#[doc(hidden)]
31pub mod traits;
32
33#[doc(hidden)]
34pub mod expr {
35 #[derive(Copy, Clone, Debug)]
36 #[repr(C)]
37 pub struct CmpExpr<Cmp, Lhs, Rhs> {
38 pub cmp: Cmp,
39 pub lhs: Lhs,
40 pub rhs: Rhs,
41 }
42
43 #[derive(Copy, Clone, Debug)]
44 #[repr(C)]
45 pub struct CustomCmpExpr<Cmp, Lhs, Rhs> {
46 pub cmp: Cmp,
47 pub lhs: Lhs,
48 pub rhs: Rhs,
49 }
50
51 #[derive(Copy, Clone, Debug)]
52 pub struct AndExpr<Lhs, Rhs> {
53 pub lhs: Lhs,
54 pub rhs: Rhs,
55 }
56
57 #[derive(Copy, Clone, Debug)]
58 pub struct OrExpr<Lhs, Rhs> {
59 pub lhs: Lhs,
60 pub rhs: Rhs,
61 }
62}
63
64pub trait CmpError<C, Lhs: ?Sized, Rhs: ?Sized>: Sized {
65 type Error;
66}
67
68pub trait CmpDisplay<C, Lhs: ?Sized, Rhs: ?Sized> {
69 fn fmt(
70 &self,
71 cmp: &C,
72 lhs: &Lhs,
73 lhs_source: &str,
74 lhs_debug: &dyn fmt::Debug,
75 rhs: &Rhs,
76 rhs_source: &str,
77 rhs_debug: &dyn fmt::Debug,
78 f: &mut fmt::Formatter,
79 ) -> fmt::Result;
80}
81
82pub trait Cmp<Lhs: ?Sized, Rhs: ?Sized>: CmpError<Self, Lhs, Rhs> {
83 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> Result<(), Self::Error>;
84}
85
86#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
87pub struct Eq;
88#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
89pub struct Ne;
90#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
91pub struct Le;
92#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
93pub struct Ge;
94#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
95pub struct Lt;
96#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
97pub struct Gt;
98
99#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
100pub struct EqError;
101#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
102pub struct NeError;
103#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
104pub struct LeError;
105#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
106pub struct GeError;
107#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
108pub struct LtError;
109#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
110pub struct GtError;
111
112fn display_cmp_impl(
113 cmp: &str,
114 lhs: &dyn fmt::Debug,
115 lhs_source: &str,
116 rhs: &dyn fmt::Debug,
117 rhs_source: &str,
118 f: &mut fmt::Formatter,
119) -> fmt::Result {
120 write!(f, "Assertion failed: {lhs_source} {cmp} {rhs_source}\n")?;
121 write!(f, "- {lhs_source} = {lhs:#?}\n")?;
122 write!(f, "- {rhs_source} = {rhs:#?}")
123}
124
125impl<Lhs: ?Sized, Rhs: ?Sized> CmpError<Eq, Lhs, Rhs> for Eq {
126 type Error = EqError;
127}
128impl<Lhs: ?Sized, Rhs: ?Sized> CmpDisplay<Eq, Lhs, Rhs> for EqError {
129 fn fmt(
130 &self,
131 cmp: &Eq,
132 lhs: &Lhs,
133 lhs_source: &str,
134 lhs_debug: &dyn fmt::Debug,
135 rhs: &Rhs,
136 rhs_source: &str,
137 rhs_debug: &dyn fmt::Debug,
138 f: &mut fmt::Formatter,
139 ) -> fmt::Result {
140 _ = (lhs, rhs, cmp);
141 display_cmp_impl("==", lhs_debug, lhs_source, rhs_debug, rhs_source, f)
142 }
143}
144
145impl<Lhs: ?Sized, Rhs: ?Sized> CmpError<Ne, Lhs, Rhs> for Ne {
146 type Error = NeError;
147}
148impl<Lhs: ?Sized, Rhs: ?Sized> CmpDisplay<Ne, Lhs, Rhs> for NeError {
149 fn fmt(
150 &self,
151 cmp: &Ne,
152 lhs: &Lhs,
153 lhs_source: &str,
154 lhs_debug: &dyn fmt::Debug,
155 rhs: &Rhs,
156 rhs_source: &str,
157 rhs_debug: &dyn fmt::Debug,
158 f: &mut fmt::Formatter,
159 ) -> fmt::Result {
160 _ = (lhs, rhs, cmp);
161 display_cmp_impl("!=", lhs_debug, lhs_source, rhs_debug, rhs_source, f)
162 }
163}
164
165impl<Lhs: ?Sized, Rhs: ?Sized> CmpError<Lt, Lhs, Rhs> for Lt {
166 type Error = LtError;
167}
168impl<Lhs: ?Sized, Rhs: ?Sized> CmpDisplay<Lt, Lhs, Rhs> for LtError {
169 fn fmt(
170 &self,
171 cmp: &Lt,
172 lhs: &Lhs,
173 lhs_source: &str,
174 lhs_debug: &dyn fmt::Debug,
175 rhs: &Rhs,
176 rhs_source: &str,
177 rhs_debug: &dyn fmt::Debug,
178 f: &mut fmt::Formatter,
179 ) -> fmt::Result {
180 _ = (lhs, rhs, cmp);
181 display_cmp_impl("<", lhs_debug, lhs_source, rhs_debug, rhs_source, f)
182 }
183}
184
185impl<Lhs: ?Sized, Rhs: ?Sized> CmpError<Gt, Lhs, Rhs> for Gt {
186 type Error = GtError;
187}
188impl<Lhs: ?Sized, Rhs: ?Sized> CmpDisplay<Gt, Lhs, Rhs> for GtError {
189 fn fmt(
190 &self,
191 cmp: &Gt,
192 lhs: &Lhs,
193 lhs_source: &str,
194 lhs_debug: &dyn fmt::Debug,
195 rhs: &Rhs,
196 rhs_source: &str,
197 rhs_debug: &dyn fmt::Debug,
198 f: &mut fmt::Formatter,
199 ) -> fmt::Result {
200 _ = (lhs, rhs, cmp);
201 display_cmp_impl(">", lhs_debug, lhs_source, rhs_debug, rhs_source, f)
202 }
203}
204
205impl<Lhs: ?Sized, Rhs: ?Sized> CmpError<Le, Lhs, Rhs> for Le {
206 type Error = LeError;
207}
208impl<Lhs: ?Sized, Rhs: ?Sized> CmpDisplay<Le, Lhs, Rhs> for LeError {
209 fn fmt(
210 &self,
211 cmp: &Le,
212 lhs: &Lhs,
213 lhs_source: &str,
214 lhs_debug: &dyn fmt::Debug,
215 rhs: &Rhs,
216 rhs_source: &str,
217 rhs_debug: &dyn fmt::Debug,
218 f: &mut fmt::Formatter,
219 ) -> fmt::Result {
220 _ = (lhs, rhs, cmp);
221 display_cmp_impl("<=", lhs_debug, lhs_source, rhs_debug, rhs_source, f)
222 }
223}
224
225impl<Lhs: ?Sized, Rhs: ?Sized> CmpError<Ge, Lhs, Rhs> for Ge {
226 type Error = GeError;
227}
228impl<Lhs: ?Sized, Rhs: ?Sized> CmpDisplay<Ge, Lhs, Rhs> for GeError {
229 fn fmt(
230 &self,
231 cmp: &Ge,
232 lhs: &Lhs,
233 lhs_source: &str,
234 lhs_debug: &dyn fmt::Debug,
235 rhs: &Rhs,
236 rhs_source: &str,
237 rhs_debug: &dyn fmt::Debug,
238 f: &mut fmt::Formatter,
239 ) -> fmt::Result {
240 _ = (lhs, rhs, cmp);
241 display_cmp_impl(">=", lhs_debug, lhs_source, rhs_debug, rhs_source, f)
242 }
243}
244
245impl<Rhs: ?Sized, Lhs: ?Sized + PartialEq<Rhs>> Cmp<Lhs, Rhs> for Eq {
246 #[inline(always)]
247 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> Result<(), EqError> {
248 if *lhs == *rhs {
249 Ok(())
250 } else {
251 Err(EqError)
252 }
253 }
254}
255impl<Rhs: ?Sized, Lhs: ?Sized + PartialEq<Rhs>> Cmp<Lhs, Rhs> for Ne {
256 #[inline(always)]
257 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> Result<(), NeError> {
258 if *lhs != *rhs {
259 Ok(())
260 } else {
261 Err(NeError)
262 }
263 }
264}
265impl<Rhs: ?Sized, Lhs: ?Sized + PartialOrd<Rhs>> Cmp<Lhs, Rhs> for Le {
266 #[inline(always)]
267 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> Result<(), LeError> {
268 if *lhs <= *rhs {
269 Ok(())
270 } else {
271 Err(LeError)
272 }
273 }
274}
275impl<Rhs: ?Sized, Lhs: ?Sized + PartialOrd<Rhs>> Cmp<Lhs, Rhs> for Ge {
276 #[inline(always)]
277 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> Result<(), GeError> {
278 if *lhs >= *rhs {
279 Ok(())
280 } else {
281 Err(GeError)
282 }
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) -> Result<(), LtError> {
288 if *lhs < *rhs {
289 Ok(())
290 } else {
291 Err(LtError)
292 }
293 }
294}
295impl<Rhs: ?Sized, Lhs: ?Sized + PartialOrd<Rhs>> Cmp<Lhs, Rhs> for Gt {
296 #[inline(always)]
297 fn test(&self, lhs: &Lhs, rhs: &Rhs) -> Result<(), GtError> {
298 if *lhs > *rhs {
299 Ok(())
300 } else {
301 Err(GtError)
302 }
303 }
304}
305
306#[doc(hidden)]
307pub struct CmpExpr;
308#[doc(hidden)]
309pub struct CustomCmpExpr<E>(pub core::marker::PhantomData<E>);
310#[doc(hidden)]
311pub struct AndExpr<L, R>(pub L, pub R);
312#[doc(hidden)]
313pub struct OrExpr<L, R>(pub L, pub R);
314
315#[doc(hidden)]
316pub struct Message<'a>(pub core::fmt::Arguments<'a>);
317#[doc(hidden)]
318pub struct NoMessage;
319
320impl From<NoMessage> for core::fmt::Arguments<'_> {
321 fn from(_: NoMessage) -> Self {
322 core::format_args!("")
323 }
324}
325
326impl<'a> From<Message<'a>> for core::fmt::Arguments<'a> {
327 fn from(t: Message<'a>) -> Self {
328 t.0
329 }
330}
331
332#[cold]
333#[inline(never)]
334#[doc(hidden)]
335#[track_caller]
336pub fn panic_failed_assert<'a, M: Into<core::fmt::Arguments<'a>>, D: decompose::Recompose>(
337 __marker: core::marker::PhantomData<D>,
338 debug_lhs: D::DebugLhs,
339 debug_rhs: D::DebugRhs,
340 debug_cmp: D::DebugCmp,
341 source: &'static structures::WithSource<D::Source, &'static D::VTable>,
342 message: M,
343) -> ! {
344 panic!(
345 "{:#?}",
346 structures::DebugMessage::<D> {
347 source,
348 debug_lhs,
349 debug_rhs,
350 debug_cmp,
351 message: message.into(),
352 }
353 )
354}
355
356#[cfg(test)]
357mod tests {
358 use super::*;
359
360 #[test]
361 #[should_panic]
362 fn test_assert() {
363 assert!(false);
364 }
365
366 #[cfg(debug_assertions)]
367 #[test]
368 #[should_panic]
369 fn test_debug_assert() {
370 debug_assert!(false);
371 }
372}