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}
73