xref: /qemu/rust/qemu-api/src/assertions.rs (revision b103cc6e74ac92f070a0e004bd84334e845c20b5)
1 // Copyright 2024, Red Hat Inc.
2 // Author(s): Paolo Bonzini <pbonzini@redhat.com>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 #![doc(hidden)]
6 //! This module provides macros to check the equality of types and
7 //! the type of `struct` fields.  This can be useful to ensure that
8 //! types match the expectations of C code.
9 //!
10 //! Documentation is hidden because it only exposes macros, which
11 //! are exported directly from `qemu_api`.
12 
13 // Based on https://stackoverflow.com/questions/64251852/x/70978292#70978292
14 // (stackoverflow answers are released under MIT license).
15 
16 #[doc(hidden)]
17 pub trait EqType {
18     type Itself;
19 }
20 
21 impl<T> EqType for T {
22     type Itself = T;
23 }
24 
25 /// Assert that two types are the same.
26 ///
27 /// # Examples
28 ///
29 /// ```
30 /// # use qemu_api::assert_same_type;
31 /// # use std::ops::Deref;
32 /// assert_same_type!(u32, u32);
33 /// assert_same_type!(<Box<u32> as Deref>::Target, u32);
34 /// ```
35 ///
36 /// Different types will cause a compile failure
37 ///
38 /// ```compile_fail
39 /// # use qemu_api::assert_same_type;
40 /// assert_same_type!(&Box<u32>, &u32);
41 /// ```
42 #[macro_export]
43 macro_rules! assert_same_type {
44     ($t1:ty, $t2:ty) => {
45         const _: () = {
46             #[allow(unused)]
47             fn assert_same_type(v: $t1) {
48                 fn types_must_be_equal<T, U>(_: T)
49                 where
50                     T: $crate::assertions::EqType<Itself = U>,
51                 {
52                 }
53                 types_must_be_equal::<_, $t2>(v);
54             }
55         };
56     };
57 }
58 
59 /// Assert that a field of a struct has the given type.
60 ///
61 /// # Examples
62 ///
63 /// ```
64 /// # use qemu_api::assert_field_type;
65 /// pub struct A {
66 ///     field1: u32,
67 /// }
68 ///
69 /// assert_field_type!(A, field1, u32);
70 /// ```
71 ///
72 /// Different types will cause a compile failure
73 ///
74 /// ```compile_fail
75 /// # use qemu_api::assert_field_type;
76 /// # pub struct A { field1: u32 }
77 /// assert_field_type!(A, field1, i32);
78 /// ```
79 #[macro_export]
80 macro_rules! assert_field_type {
81     ($t:ty, $i:tt, $ti:ty) => {
82         const _: () = {
83             #[allow(unused)]
84             fn assert_field_type(v: $t) {
85                 fn types_must_be_equal<T, U>(_: T)
86                 where
87                     T: $crate::assertions::EqType<Itself = U>,
88                 {
89                 }
90                 types_must_be_equal::<_, $ti>(v.$i);
91             }
92         };
93     };
94 
95     ($t:ty, $i:tt, $ti:ty, num = $num:ident) => {
96         const _: () = {
97             #[allow(unused)]
98             fn assert_field_type(v: $t) {
99                 fn types_must_be_equal<T, U>(_: T)
100                 where
101                     T: $crate::assertions::EqType<Itself = U>,
102                 {
103                 }
104                 let index: usize = v.$num.try_into().unwrap();
105                 types_must_be_equal::<_, &$ti>(&v.$i[index]);
106             }
107         };
108     };
109 }
110 
111 /// Assert that an expression matches a pattern.  This can also be
112 /// useful to compare enums that do not implement `Eq`.
113 ///
114 /// # Examples
115 ///
116 /// ```
117 /// # use qemu_api::assert_match;
118 /// // JoinHandle does not implement `Eq`, therefore the result
119 /// // does not either.
120 /// let result: Result<std::thread::JoinHandle<()>, u32> = Err(42);
121 /// assert_match!(result, Err(42));
122 /// ```
123 #[macro_export]
124 macro_rules! assert_match {
125     ($a:expr, $b:pat) => {
126         assert!(
127             match $a {
128                 $b => true,
129                 _ => false,
130             },
131             "{} = {:?} does not match {}",
132             stringify!($a),
133             $a,
134             stringify!($b)
135         );
136     };
137 }
138 
139 /// Assert at compile time that an expression is true.  This is similar
140 /// to `const { assert!(...); }` but it works outside functions, as well as
141 /// on versions of Rust before 1.79.
142 ///
143 /// # Examples
144 ///
145 /// ```
146 /// # use qemu_api::static_assert;
147 /// static_assert!("abc".len() == 3);
148 /// ```
149 ///
150 /// ```compile_fail
151 /// # use qemu_api::static_assert;
152 /// static_assert!("abc".len() == 2); // does not compile
153 /// ```
154 #[macro_export]
155 macro_rules! static_assert {
156     ($x:expr) => {
157         const _: () = assert!($x);
158     };
159 }
160