pci_driver/regions/
struct_macros.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3/* ---------------------------------------------------------------------------------------------- */
4
5/// TODO: Document.
6///
7/// The optional length is important mostly to make
8/// [`PciRegionSnapshot`](crate::regions::PciRegionSnapshot) only copy the relevant part instead of
9/// a lot more.
10///
11/// TODO: Validate field offsets against length.
12#[macro_export]
13macro_rules! pci_struct {
14    (
15        $(
16            $(#[$attr:meta])*
17            $vis:vis struct $name:ident<$lifetime:lifetime> $(: $length:literal)? {
18                $(
19                    $(#[$field_attr:meta])*
20                    $field_name:ident @ $field_offset:literal :
21                    $($field_type:ident)::+$(<$($field_generics:tt),+ $(,)?>)?
22                ),* $(,)?
23            }
24        )*
25    ) => {
26        $(
27            $(#[$attr])*
28            #[derive(Clone, Copy)]
29            $vis struct $name<$lifetime> {
30                subregion: $crate::regions::PciSubregion<$lifetime>,
31            }
32
33            impl<'a> $crate::regions::BackedByPciSubregion<'a> for $name<'a> {
34                fn backed_by(as_subregion: impl $crate::regions::AsPciSubregion<'a>) -> Self {
35                    let subregion = $crate::regions::AsPciSubregion::subregion(&as_subregion, ..$($length)?);
36                    $name { subregion }
37                }
38            }
39
40            impl<'a> $crate::regions::AsPciSubregion<'a> for $name<'a> {
41                fn as_subregion(&self) -> $crate::regions::PciSubregion<'a> {
42                    self.subregion
43                }
44            }
45
46            $crate::_pci_struct_impl! {
47                impl $name<$lifetime> {
48                    $(
49                        $(#[$field_attr])*
50                        $field_name @ $field_offset :
51                        $($field_type)::+$(<$($field_generics),+>)?
52                    ),*
53                }
54            }
55        )*
56    };
57}
58
59/// This macro is __internal__. It should __not__ be used outside of the `pci-driver` crate.
60#[doc(hidden)]
61#[macro_export]
62macro_rules! _pci_struct_impl {
63    (
64        impl $name:ident<$lifetime:lifetime> {
65            $(
66                $(#[$field_attr:meta])*
67                $field_name:ident @ $field_offset:literal :
68                $($field_type:ident)::+$(<$($field_generics:tt),+ $(,)?>)?
69            ),* $(,)?
70        }
71    ) => {
72        impl ::std::fmt::Debug for $name<'_> {
73            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
74                let mut debug_struct = f.debug_struct(::std::stringify!($name));
75                $( debug_struct.field(::std::stringify!($field_name), &self.$field_name()); )*
76                debug_struct.finish()
77            }
78        }
79
80        impl<$lifetime> $name<$lifetime> {
81            $(
82                $(#[$field_attr])*
83                pub fn $field_name(&self) -> $($field_type)::+$(<$($field_generics),+>)? {
84                    let subregion = $crate::regions::AsPciSubregion::subregion(self, $field_offset..);
85                    $crate::regions::BackedByPciSubregion::backed_by(subregion)
86                }
87            )*
88        }
89    };
90}
91
92/* ---------------------------------------------------------------------------------------------- */