equator/
lib.rs

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}