static_assertions/
assert_fields.rs

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