const_format/macros/assertions/
assertc_macros.rs

1macro_rules! with_shared_docs {(
2    $(#[$before_clarification:meta])*
3    ;clarification
4    $(#[$before_syntax:meta])*
5    ;syntax
6    $(#[$after_syntax:meta])*
7    ;error_message
8    $(#[$after_error_message:meta])*
9    ;limitations
10    $item:item
11) => (
12    $(#[$before_clarification])*
13    ///
14    /// This macro requires the `"assertc"` feature to be exported.
15    ///
16    $(#[$before_syntax])*
17    ///
18    /// This macro uses [the same syntax](./fmt/index.html#fmtsyntax)
19    /// for the format string and supports the same formatting arguments as the
20    /// [`formatc`] macro.
21    ///
22    $(#[$after_syntax])*
23    $(#[$after_error_message])*
24    /// # Limitations
25    ///
26    /// This macro has these limitations:
27    ///
28    /// - It can only use constants that involve concrete types,
29    /// so while a `Type::<u8>::FOO` in an argument would be fine,
30    /// `Type::<T>::FOO` would not be (`T` being a type parameter).
31    ///
32    /// - Integer arguments must have a type inferrable from context,
33    /// [as described in the integer arguments section in the root module
34    /// ](./index.html#integer-args).
35    ///
36    /// [`PWrapper`]: ./struct.PWrapper.html
37    /// [`formatc`]: ./macro.formatc.html
38    /// [`FormatMarker`]: ./marker_traits/trait.FormatMarker.html
39    ///
40    $item
41)}
42
43////////////////////////////////////////////////////////////////////////////////
44
45with_shared_docs! {
46    /// Compile-time assertions with formatting.
47    ///
48    ;clarification
49    ;syntax
50    ;error_message
51    ;limitations
52    ///
53    /// # Examples
54    ///
55    /// ### Passing assertion
56    ///
57    /// ```rust
58    ///
59    /// use const_format::assertc;
60    ///
61    /// use std::mem::size_of;
62    ///
63    /// assertc!(
64    ///     size_of::<&str>() == size_of::<&[u8]>(),
65    ///     "The size of `&str`({} bytes) and `&[u8]`({} bytes) aren't the same?!?!",
66    ///     size_of::<&str>(),
67    ///     size_of::<&[u8]>(),
68    /// );
69    ///
70    /// # fn main(){}
71    /// ```
72    ///
73    /// ### Failing assertion
74    ///
75    /// This example demonstrates a failing assertion,
76    /// and how the compiler error looks like as of 2023-10-14.
77    ///
78    /// ```compile_fail
79    ///
80    /// use const_format::assertc;
81    ///
82    /// const L: u64 = 2;
83    /// const R: u64 = 2;
84    ///
85    /// assertc!(L + R == 5, "{} plus {} isn't 5, buddy", L,  R);
86    ///
87    /// # fn main(){}
88    /// ```
89    ///
90    /// This is the compiler output:
91    ///
92    /// ```text
93    /// error[E0080]: evaluation of constant value failed
94    ///   --> const_format/src/macros/assertions/assertc_macros.rs:109:10
95    ///    |
96    /// 11 | assertc!(L + R == 5, "{} plus {} isn't 5, buddy", L,  R);
97    ///    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at '
98    /// assertion failed.
99    /// 2 plus 2 isn't 5, buddy
100    /// ', const_format/src/macros/assertions/assertc_macros.rs:11:10
101    /// ```
102    ///
103    #[cfg_attr(feature = "__docsrs", doc(cfg(feature = "assertc")))]
104    #[macro_export]
105    macro_rules! assertc {
106        ($($parameters:tt)*) => (
107            $crate::__assertc_inner!{
108                __formatc_if_impl
109                ($($parameters)*)
110                ($($parameters)*)
111            }
112        );
113    }
114}
115
116////////////////////////////////////////////////////////////////////////////////
117
118macro_rules! assert_eq_docs {
119    (
120        $(#[$documentation:meta])*
121        ;documentation
122        $item:item
123    ) => (
124        with_shared_docs! {
125            $(#[$documentation])*
126            ;clarification
127            /// # Arguments
128            ///
129            /// This macro accepts these types for comparison and debug printing:
130            ///
131            /// - Standard library types for which  [`PWrapper`] wrapping that type
132            /// has a `const_eq` method.
133            /// This includes all integer types, `&str`, slices/arrays of integers/`&str`,
134            /// Options of integers/`&str`, etc.
135            ///
136            /// - non-standard-library types that implement [`FormatMarker`] with debug formatting<br>
137            /// and have a `const fn const_eq(&self, other:&Self) -> bool` inherent method,
138            ///
139            ;syntax
140            ;error_message
141            ;limitations
142            $item
143        }
144    )
145}
146
147assert_eq_docs! {
148    /// Compile-time equality assertion with formatting.
149    ///
150    ;documentation
151    ///
152    /// # Examples
153    ///
154    /// ### Passing assertion
155    ///
156    /// ```rust
157    ///
158    /// use const_format::assertc_eq;
159    ///
160    /// use std::mem::size_of;
161    ///
162    /// assertc_eq!(size_of::<usize>(), size_of::<[usize;1]>());
163    ///
164    /// const TWO: u32 = 2;
165    /// assertc_eq!(TWO, TWO, "Oh no {} doesn't equal itself!!", TWO);
166    ///
167    /// # fn main(){}
168    /// ```
169    ///
170    /// ### Failing assertion
171    ///
172    /// This example demonstrates a failing assertion,
173    /// and how the compiler error looks like as of 2023-10-14.
174    ///
175    /// ```compile_fail
176    ///
177    /// use const_format::assertc_eq;
178    ///
179    /// use std::mem::size_of;
180    ///
181    /// assertc_eq!(size_of::<u32>(), size_of::<u8>());
182    ///
183    /// # fn main(){}
184    /// ```
185    ///
186    /// This is the compiler output:
187    ///
188    /// ```text
189    /// error[E0080]: evaluation of constant value failed
190    ///   --> const_format/src/macros/assertions/assertc_macros.rs:222:13
191    ///    |
192    /// 10 | assertc_eq!(size_of::<u32>(), size_of::<u8>());
193    ///    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at '
194    /// assertion failed: `(left == right)`
195    ///  left: `4`
196    /// right: `1`', const_format/src/macros/assertions/assertc_macros.rs:10:13
197    /// ```
198    ///
199    /// ### Comparing user-defined types
200    ///
201    /// This example demonstrates how you can assert that two values of a
202    /// user-defined type are equal.
203    ///
204    #[cfg_attr(feature = "derive", doc = "```compile_fail")]
205    #[cfg_attr(not(feature = "derive"), doc = "```ignore")]
206    ///
207    /// use const_format::{Formatter, PWrapper};
208    /// use const_format::{ConstDebug, assertc_eq, try_};
209    ///
210    /// const POINT: Point = Point{ x: 5, y: 8, z: 13 };
211    /// const OTHER_POINT: Point = Point{ x: 21, y: 34, z: 55 };
212    ///
213    /// assertc_eq!(POINT, OTHER_POINT);
214    ///
215    /// #[derive(ConstDebug)]
216    /// pub struct Point {
217    ///     pub x: u32,
218    ///     pub y: u32,
219    ///     pub z: u32,
220    /// }
221    ///
222    /// impl Point {
223    ///     pub const fn const_eq(&self, other: &Self) -> bool {
224    ///         self.x == other.x &&
225    ///         self.y == other.y &&
226    ///         self.z == other.z
227    ///     }
228    /// }
229    /// ```
230    ///
231    /// This is the compiler output:
232    ///
233    /// ```text
234    /// error[E0080]: evaluation of constant value failed
235    ///   --> src/macros/assertions.rs:331:14
236    ///    |
237    /// 12 |  assertc_eq!(POINT, OTHER_POINT);
238    ///    |              ^^^^^^^^^^^^^^^^^^ the evaluated program panicked at '
239    /// assertion failed: `(left == right)`
240    ///  left: `Point {
241    ///     x: 5,
242    ///     y: 8,
243    ///     z: 13,
244    /// }`
245    /// right: `Point {
246    ///     x: 21,
247    ///     y: 34,
248    ///     z: 55,
249    /// }`', src/macros/assertions.rs:12:14
250    ///
251    /// error: aborting due to previous error
252    ///
253    /// ```
254    ///
255    #[cfg_attr(feature = "__docsrs", doc(cfg(feature = "assertc")))]
256    #[macro_export]
257    macro_rules! assertc_eq {
258        ($($parameters:tt)*) => (
259            $crate::__assertc_equality_inner!{
260                ($($parameters)*)
261                ($($parameters)*)
262                ( == )
263                ("==")
264            }
265        );
266    }
267}
268
269assert_eq_docs! {
270    /// Compile-time inequality assertion with formatting.
271    ///
272    ;documentation
273    ///
274    /// # Examples
275    ///
276    /// ### Passing assertion
277    ///
278    /// ```rust
279    ///
280    /// use const_format::assertc_ne;
281    ///
282    /// use std::mem::size_of;
283    ///
284    /// assertc_ne!(size_of::<u32>(), size_of::<[u32; 2]>());
285    ///
286    /// const TWO: u32 = 2;
287    /// const THREE: u32 = 3;
288    /// assertc_ne!(TWO, THREE, "Oh no {} somehow equals {}!!", TWO, THREE);
289    ///
290    /// # fn main(){}
291    /// ```
292    ///
293    /// ### Failing assertion
294    ///
295    /// This example demonstrates a failing assertion,
296    /// and how the compiler error looks like as of 2023-10-14.
297    ///
298    /// ```compile_fail
299    ///
300    /// use const_format::assertc_ne;
301    ///
302    /// use std::mem::size_of;
303    ///
304    /// type Foo = u32;
305    ///
306    /// assertc_ne!(size_of::<u32>(), size_of::<Foo>());
307    ///
308    /// # fn main(){}
309    /// ```
310    ///
311    /// This is the compiler output:
312    ///
313    /// ```text
314    /// error[E0080]: evaluation of constant value failed
315    ///   --> const_format/src/macros/assertions/assertc_macros.rs:350:13
316    ///    |
317    /// 12 | assertc_ne!(size_of::<u32>(), size_of::<Foo>());
318    ///    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at '
319    /// assertion failed: `(left != right)`
320    ///  left: `4`
321    /// right: `4`', const_format/src/macros/assertions/assertc_macros.rs:12:13
322    /// ```
323    ///
324    /// ### Comparing user-defined types
325    ///
326    /// This example demonstrates how you can assert that two values of a
327    /// user-defined type are unequal.
328    ///
329    #[cfg_attr(feature = "derive", doc = "```compile_fail")]
330    #[cfg_attr(not(feature = "derive"), doc = "```ignore")]
331    ///
332    /// use const_format::{Formatter, PWrapper};
333    /// use const_format::{ConstDebug, assertc_ne, try_};
334    ///
335    /// const POINT: Point = Point{ x: 5, y: 8, z: 13 };
336    ///
337    /// assertc_ne!(POINT, POINT);
338    ///
339    /// #[derive(ConstDebug)]
340    /// pub struct Point {
341    ///     pub x: u32,
342    ///     pub y: u32,
343    ///     pub z: u32,
344    /// }
345    ///
346    /// impl Point {
347    ///     pub const fn const_eq(&self, other: &Self) -> bool {
348    ///         self.x == other.x &&
349    ///         self.y == other.y &&
350    ///         self.z == other.z
351    ///     }
352    /// }
353    /// ```
354    ///
355    /// This is the compiler output:
356    ///
357    /// ```text
358    /// error[E0080]: evaluation of constant value failed
359    ///   --> src/macros/assertions.rs:451:14
360    ///    |
361    /// 11 |  assertc_ne!(POINT, POINT);
362    ///    |              ^^^^^^^^^^^^ the evaluated program panicked at '
363    /// assertion failed: `(left != right)`
364    ///  left: `Point {
365    ///     x: 5,
366    ///     y: 8,
367    ///     z: 13,
368    /// }`
369    /// right: `Point {
370    ///     x: 5,
371    ///     y: 8,
372    ///     z: 13,
373    /// }`', src/macros/assertions.rs:11:14
374    ///
375    /// error: aborting due to previous error
376    ///
377    /// ```
378    ///
379    #[cfg_attr(feature = "__docsrs", doc(cfg(feature = "assertc")))]
380    #[macro_export]
381    macro_rules! assertc_ne {
382        ($($parameters:tt)*) => (
383            $crate::__assertc_equality_inner!{
384                ($($parameters)*)
385                ($($parameters)*)
386                ( != )
387                ("!=")
388            }
389        );
390    }
391}
392
393#[doc(hidden)]
394#[macro_export]
395macro_rules! __assertc_equality_inner {
396    (
397        ($($parameters:tt)*)
398        (
399            $left:expr,
400            $right:expr
401            $(, $fmt_literal:expr $(,$fmt_arg:expr)*)? $(,)?
402        )
403        ($($op:tt)*)
404        ($op_str:expr)
405    )=>{
406        const _: () = {
407            use $crate::__cf_osRcTFl4A;
408            use $crate::pmr::respan_to as __cf_respan_to;
409
410            const LEFT: $crate::pmr::bool = {
411                // Have to use `respan_to` to make the `multiple coerce found` error
412                // point at the `$left` argument here.
413                use $crate::coerce_to_fmt as __cf_coerce_to_fmt;
414                match [&$left, &$right] {
415                    __cf_respan_to!(($left) [left, right]) =>
416                        __cf_respan_to!(($left) __cf_coerce_to_fmt!(left).const_eq(right)),
417                }
418            };
419            const RIGHT: $crate::pmr::bool = true;
420
421            $crate::__assertc_common!{
422                __formatc_if_impl
423                ($($parameters)*)
424                (LEFT $($op)* RIGHT)
425                (
426                    concat!(
427                        "\nassertion failed: `(left ",
428                        $op_str,
429                        " right)`\n",
430                        " left: `{left_NHPMWYD3NJA:#?}`\n\
431                         right: `{right_NHPMWYD3NJA:#?}`",
432                        $("\n", $fmt_literal, "\n")?
433                    ),
434                    $($($fmt_arg,)*)?
435                    left_NHPMWYD3NJA = $left,
436                    right_NHPMWYD3NJA = $right
437                )
438            }
439        };
440    }
441}