1bcab3026Sopenharmony_ci/// Asserts that the type has the given fields.
2bcab3026Sopenharmony_ci///
3bcab3026Sopenharmony_ci/// # Examples
4bcab3026Sopenharmony_ci///
5bcab3026Sopenharmony_ci/// One common use case is when types have fields defined multiple times as a
6bcab3026Sopenharmony_ci/// result of `#[cfg]`. This can be an issue when exposing a public API.
7bcab3026Sopenharmony_ci///
8bcab3026Sopenharmony_ci/// ```
9bcab3026Sopenharmony_ci/// # #[macro_use] extern crate static_assertions;
10bcab3026Sopenharmony_ci/// pub struct Ty {
11bcab3026Sopenharmony_ci///     #[cfg(windows)]
12bcab3026Sopenharmony_ci///     pub val1: u8,
13bcab3026Sopenharmony_ci///     #[cfg(not(windows))]
14bcab3026Sopenharmony_ci///     pub val1: usize,
15bcab3026Sopenharmony_ci///
16bcab3026Sopenharmony_ci///     #[cfg(unix)]
17bcab3026Sopenharmony_ci///     pub val2: u32,
18bcab3026Sopenharmony_ci///     #[cfg(not(unix))]
19bcab3026Sopenharmony_ci///     pub val2: usize,
20bcab3026Sopenharmony_ci/// }
21bcab3026Sopenharmony_ci///
22bcab3026Sopenharmony_ci/// // Always have `val2` regardless of OS
23bcab3026Sopenharmony_ci/// assert_fields!(Ty: val2);
24bcab3026Sopenharmony_ci/// ```
25bcab3026Sopenharmony_ci///
26bcab3026Sopenharmony_ci/// This macro even works with `enum` variants:
27bcab3026Sopenharmony_ci///
28bcab3026Sopenharmony_ci/// ```
29bcab3026Sopenharmony_ci/// # #[macro_use] extern crate static_assertions; fn main() {}
30bcab3026Sopenharmony_ci/// enum Data {
31bcab3026Sopenharmony_ci///     Val {
32bcab3026Sopenharmony_ci///         id: i32,
33bcab3026Sopenharmony_ci///         name: String,
34bcab3026Sopenharmony_ci///         bytes: [u8; 128],
35bcab3026Sopenharmony_ci///     },
36bcab3026Sopenharmony_ci///     Ptr(*const u8),
37bcab3026Sopenharmony_ci/// }
38bcab3026Sopenharmony_ci///
39bcab3026Sopenharmony_ci/// assert_fields!(Data::Val: id, bytes);
40bcab3026Sopenharmony_ci/// ```
41bcab3026Sopenharmony_ci///
42bcab3026Sopenharmony_ci/// The following example fails to compile because [`Range`] does not have a field named `middle`:
43bcab3026Sopenharmony_ci///
44bcab3026Sopenharmony_ci/// ```compile_fail
45bcab3026Sopenharmony_ci/// # #[macro_use] extern crate static_assertions; fn main() {}
46bcab3026Sopenharmony_ci/// use std::ops::Range;
47bcab3026Sopenharmony_ci///
48bcab3026Sopenharmony_ci/// assert_fields!(Range<u32>: middle);
49bcab3026Sopenharmony_ci/// ```
50bcab3026Sopenharmony_ci///
51bcab3026Sopenharmony_ci/// [`Range`]: https://doc.rust-lang.org/std/ops/struct.Range.html
52bcab3026Sopenharmony_ci#[macro_export]
53bcab3026Sopenharmony_cimacro_rules! assert_fields {
54bcab3026Sopenharmony_ci    ($t:ident::$v:ident: $($f:ident),+) => {
55bcab3026Sopenharmony_ci        #[allow(unknown_lints, unneeded_field_pattern)]
56bcab3026Sopenharmony_ci        const _: fn() = || {
57bcab3026Sopenharmony_ci            #[allow(dead_code, unreachable_patterns)]
58bcab3026Sopenharmony_ci            fn assert(value: $t) {
59bcab3026Sopenharmony_ci                match value {
60bcab3026Sopenharmony_ci                    $($t::$v { $f: _, .. } => {},)+
61bcab3026Sopenharmony_ci                    _ => {}
62bcab3026Sopenharmony_ci                }
63bcab3026Sopenharmony_ci            }
64bcab3026Sopenharmony_ci        };
65bcab3026Sopenharmony_ci    };
66bcab3026Sopenharmony_ci    ($t:path: $($f:ident),+) => {
67bcab3026Sopenharmony_ci        #[allow(unknown_lints, unneeded_field_pattern)]
68bcab3026Sopenharmony_ci        const _: fn() = || {
69bcab3026Sopenharmony_ci            $(let $t { $f: _, .. };)+
70bcab3026Sopenharmony_ci        };
71bcab3026Sopenharmony_ci    };
72bcab3026Sopenharmony_ci}
73