Skip to main content

tpm2_protocol/macro/
enum.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) 2025 Opinsys Oy
3// Copyright (c) 2024-2025 Jarkko Sakkinen
4
5//! The chain of `if`-statements is a deliberate design choice as patterns in
6//! a `match`-statement is too restricted for arbitrary expressions (e.g, see
7//! `TpmRc` for an example).
8
9#[macro_export]
10macro_rules! tpm_enum {
11    (@impl $(#[$enum_meta:meta])* $vis:vis enum $name:ident($wrapper:ty, $repr:ty) {
12        $(
13            $(#[$variant_meta:meta])*
14            ($variant:ident, $value:expr, $display:literal)
15        ),* $(,)?
16    }) => {
17        $(#[$enum_meta])*
18        #[repr($repr)]
19        $vis enum $name {
20            $(
21                $(#[$variant_meta])*
22                $variant = $value
23            ),*
24        }
25
26        impl TryFrom<$repr> for $name {
27            type Error = $crate::TpmProtocolError;
28
29            fn try_from(value: $repr) -> Result<Self, $crate::TpmProtocolError> {
30                match value {
31                    $(
32                        _ if value == $value => Ok(Self::$variant),
33                    )*
34                    _ => Err($crate::TpmProtocolError::VariantNotAvailable),
35                }
36            }
37        }
38
39        impl $name {
40            #[must_use]
41            pub const fn value(self) -> $repr {
42                self as $repr
43            }
44        }
45
46        impl core::fmt::Display for $name {
47            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48                let s = match self {
49                    $(Self::$variant => $display),*
50                };
51                write!(f, "{}", s)
52            }
53        }
54
55        impl $crate::TpmSized for $name {
56            const SIZE: usize = core::mem::size_of::<$repr>();
57
58            fn len(&self) -> usize {
59                Self::SIZE
60            }
61        }
62
63        impl $crate::TpmMarshal for $name {
64            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
65                let value = <$wrapper>::from(*self as $repr);
66                $crate::TpmMarshal::marshal(&value, writer)
67            }
68        }
69
70        impl $crate::TpmUnmarshal for $name {
71            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
72                let (val, buf) = <$wrapper as $crate::TpmUnmarshal>::unmarshal(buf)?;
73                let raw: $repr = val.into();
74                let enum_val = Self::try_from(raw)?;
75                Ok((enum_val, buf))
76            }
77        }
78    };
79
80    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmUint8) { $($rest:tt)* }) => {
81        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmUint8, u8) { $($rest)* });
82    };
83    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmInt8) { $($rest:tt)* }) => {
84        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmInt8, i8) { $($rest)* });
85    };
86    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmUint16) { $($rest:tt)* }) => {
87        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmUint16, u16) { $($rest)* });
88    };
89    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmUint32) { $($rest:tt)* }) => {
90        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmUint32, u32) { $($rest)* });
91    };
92    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmInt32) { $($rest:tt)* }) => {
93        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmInt32, i32) { $($rest)* });
94    };
95    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmUint64) { $($rest:tt)* }) => {
96        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmUint64, u64) { $($rest)* });
97    };
98}