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