xref: /qemu/rust/qemu-api/src/assertions.rs (revision dc1ed8f256c446cbf33e090f0e214d0311a771a7)
17f65d4e5SPaolo Bonzini // Copyright 2024, Red Hat Inc.
27f65d4e5SPaolo Bonzini // Author(s): Paolo Bonzini <pbonzini@redhat.com>
37f65d4e5SPaolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later
47f65d4e5SPaolo Bonzini 
5ebacd14aSPaolo Bonzini #![doc(hidden)]
67f65d4e5SPaolo Bonzini //! This module provides macros to check the equality of types and
77f65d4e5SPaolo Bonzini //! the type of `struct` fields.  This can be useful to ensure that
87f65d4e5SPaolo Bonzini //! types match the expectations of C code.
9ebacd14aSPaolo Bonzini //!
10ebacd14aSPaolo Bonzini //! Documentation is hidden because it only exposes macros, which
11ebacd14aSPaolo Bonzini //! are exported directly from `qemu_api`.
127f65d4e5SPaolo Bonzini 
137f65d4e5SPaolo Bonzini // Based on https://stackoverflow.com/questions/64251852/x/70978292#70978292
147f65d4e5SPaolo Bonzini // (stackoverflow answers are released under MIT license).
157f65d4e5SPaolo Bonzini 
167f65d4e5SPaolo Bonzini #[doc(hidden)]
177f65d4e5SPaolo Bonzini pub trait EqType {
187f65d4e5SPaolo Bonzini     type Itself;
197f65d4e5SPaolo Bonzini }
207f65d4e5SPaolo Bonzini 
217f65d4e5SPaolo Bonzini impl<T> EqType for T {
227f65d4e5SPaolo Bonzini     type Itself = T;
237f65d4e5SPaolo Bonzini }
247f65d4e5SPaolo Bonzini 
257f65d4e5SPaolo Bonzini /// Assert that two types are the same.
267f65d4e5SPaolo Bonzini ///
277f65d4e5SPaolo Bonzini /// # Examples
287f65d4e5SPaolo Bonzini ///
297f65d4e5SPaolo Bonzini /// ```
307f65d4e5SPaolo Bonzini /// # use qemu_api::assert_same_type;
317f65d4e5SPaolo Bonzini /// # use std::ops::Deref;
327f65d4e5SPaolo Bonzini /// assert_same_type!(u32, u32);
337f65d4e5SPaolo Bonzini /// assert_same_type!(<Box<u32> as Deref>::Target, u32);
347f65d4e5SPaolo Bonzini /// ```
357f65d4e5SPaolo Bonzini ///
367f65d4e5SPaolo Bonzini /// Different types will cause a compile failure
377f65d4e5SPaolo Bonzini ///
387f65d4e5SPaolo Bonzini /// ```compile_fail
397f65d4e5SPaolo Bonzini /// # use qemu_api::assert_same_type;
407f65d4e5SPaolo Bonzini /// assert_same_type!(&Box<u32>, &u32);
417f65d4e5SPaolo Bonzini /// ```
427f65d4e5SPaolo Bonzini #[macro_export]
437f65d4e5SPaolo Bonzini macro_rules! assert_same_type {
447f65d4e5SPaolo Bonzini     ($t1:ty, $t2:ty) => {
457f65d4e5SPaolo Bonzini         const _: () = {
467f65d4e5SPaolo Bonzini             #[allow(unused)]
477f65d4e5SPaolo Bonzini             fn assert_same_type(v: $t1) {
487f65d4e5SPaolo Bonzini                 fn types_must_be_equal<T, U>(_: T)
497f65d4e5SPaolo Bonzini                 where
507f65d4e5SPaolo Bonzini                     T: $crate::assertions::EqType<Itself = U>,
517f65d4e5SPaolo Bonzini                 {
527f65d4e5SPaolo Bonzini                 }
537f65d4e5SPaolo Bonzini                 types_must_be_equal::<_, $t2>(v);
547f65d4e5SPaolo Bonzini             }
557f65d4e5SPaolo Bonzini         };
567f65d4e5SPaolo Bonzini     };
577f65d4e5SPaolo Bonzini }
587f65d4e5SPaolo Bonzini 
597f65d4e5SPaolo Bonzini /// Assert that a field of a struct has the given type.
607f65d4e5SPaolo Bonzini ///
617f65d4e5SPaolo Bonzini /// # Examples
627f65d4e5SPaolo Bonzini ///
637f65d4e5SPaolo Bonzini /// ```
647f65d4e5SPaolo Bonzini /// # use qemu_api::assert_field_type;
657f65d4e5SPaolo Bonzini /// pub struct A {
667f65d4e5SPaolo Bonzini ///     field1: u32,
677f65d4e5SPaolo Bonzini /// }
687f65d4e5SPaolo Bonzini ///
697f65d4e5SPaolo Bonzini /// assert_field_type!(A, field1, u32);
707f65d4e5SPaolo Bonzini /// ```
717f65d4e5SPaolo Bonzini ///
727f65d4e5SPaolo Bonzini /// Different types will cause a compile failure
737f65d4e5SPaolo Bonzini ///
747f65d4e5SPaolo Bonzini /// ```compile_fail
757f65d4e5SPaolo Bonzini /// # use qemu_api::assert_field_type;
767f65d4e5SPaolo Bonzini /// # pub struct A { field1: u32 }
777f65d4e5SPaolo Bonzini /// assert_field_type!(A, field1, i32);
787f65d4e5SPaolo Bonzini /// ```
797f65d4e5SPaolo Bonzini #[macro_export]
807f65d4e5SPaolo Bonzini macro_rules! assert_field_type {
81*fff99a88SPaolo Bonzini     (@internal $param_name:ident, $ti:ty, $t:ty, $($field:tt)*) => {
827f65d4e5SPaolo Bonzini         const _: () = {
837f65d4e5SPaolo Bonzini             #[allow(unused)]
84*fff99a88SPaolo Bonzini             fn assert_field_type($param_name: &$t) {
85*fff99a88SPaolo Bonzini                 fn types_must_be_equal<T, U>(_: &T)
867f65d4e5SPaolo Bonzini                 where
877f65d4e5SPaolo Bonzini                     T: $crate::assertions::EqType<Itself = U>,
887f65d4e5SPaolo Bonzini                 {
897f65d4e5SPaolo Bonzini                 }
90*fff99a88SPaolo Bonzini                 types_must_be_equal::<_, $ti>(&$($field)*);
917f65d4e5SPaolo Bonzini             }
927f65d4e5SPaolo Bonzini         };
937f65d4e5SPaolo Bonzini     };
9461825825SZhao Liu 
95*fff99a88SPaolo Bonzini     ($t:ty, $i:tt, $ti:ty) => {
96*fff99a88SPaolo Bonzini         $crate::assert_field_type!(@internal v, $ti, $t, v.$i);
9761825825SZhao Liu     };
98*fff99a88SPaolo Bonzini 
99*fff99a88SPaolo Bonzini     ($t:ty, $i:tt, $ti:ty, num = $num:ident) => {
100*fff99a88SPaolo Bonzini         $crate::assert_field_type!(@internal v, $ti, $t, v.$i[0]);
10161825825SZhao Liu     };
1027f65d4e5SPaolo Bonzini }
1038a420dd1SPaolo Bonzini 
1048a420dd1SPaolo Bonzini /// Assert that an expression matches a pattern.  This can also be
1058a420dd1SPaolo Bonzini /// useful to compare enums that do not implement `Eq`.
1068a420dd1SPaolo Bonzini ///
1078a420dd1SPaolo Bonzini /// # Examples
1088a420dd1SPaolo Bonzini ///
1098a420dd1SPaolo Bonzini /// ```
1108a420dd1SPaolo Bonzini /// # use qemu_api::assert_match;
1118a420dd1SPaolo Bonzini /// // JoinHandle does not implement `Eq`, therefore the result
1128a420dd1SPaolo Bonzini /// // does not either.
1138a420dd1SPaolo Bonzini /// let result: Result<std::thread::JoinHandle<()>, u32> = Err(42);
1148a420dd1SPaolo Bonzini /// assert_match!(result, Err(42));
1158a420dd1SPaolo Bonzini /// ```
1168a420dd1SPaolo Bonzini #[macro_export]
1178a420dd1SPaolo Bonzini macro_rules! assert_match {
1188a420dd1SPaolo Bonzini     ($a:expr, $b:pat) => {
1198a420dd1SPaolo Bonzini         assert!(
1208a420dd1SPaolo Bonzini             match $a {
1218a420dd1SPaolo Bonzini                 $b => true,
1228a420dd1SPaolo Bonzini                 _ => false,
1238a420dd1SPaolo Bonzini             },
1248a420dd1SPaolo Bonzini             "{} = {:?} does not match {}",
1258a420dd1SPaolo Bonzini             stringify!($a),
1268a420dd1SPaolo Bonzini             $a,
1278a420dd1SPaolo Bonzini             stringify!($b)
1288a420dd1SPaolo Bonzini         );
1298a420dd1SPaolo Bonzini     };
1308a420dd1SPaolo Bonzini }
1319d116f42SPaolo Bonzini 
1329d116f42SPaolo Bonzini /// Assert at compile time that an expression is true.  This is similar
1339d116f42SPaolo Bonzini /// to `const { assert!(...); }` but it works outside functions, as well as
1349d116f42SPaolo Bonzini /// on versions of Rust before 1.79.
1359d116f42SPaolo Bonzini ///
1369d116f42SPaolo Bonzini /// # Examples
1379d116f42SPaolo Bonzini ///
1389d116f42SPaolo Bonzini /// ```
1399d116f42SPaolo Bonzini /// # use qemu_api::static_assert;
1409d116f42SPaolo Bonzini /// static_assert!("abc".len() == 3);
1419d116f42SPaolo Bonzini /// ```
1429d116f42SPaolo Bonzini ///
1439d116f42SPaolo Bonzini /// ```compile_fail
1449d116f42SPaolo Bonzini /// # use qemu_api::static_assert;
1459d116f42SPaolo Bonzini /// static_assert!("abc".len() == 2); // does not compile
1469d116f42SPaolo Bonzini /// ```
1479d116f42SPaolo Bonzini #[macro_export]
1489d116f42SPaolo Bonzini macro_rules! static_assert {
1499d116f42SPaolo Bonzini     ($x:expr) => {
1509d116f42SPaolo Bonzini         const _: () = assert!($x);
1519d116f42SPaolo Bonzini     };
1529d116f42SPaolo Bonzini }
153