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    (
12        $(#[$enum_meta:meta])*
13        $vis:vis enum $name:ident($repr:ty) {
14            $(
15                $(#[$variant_meta:meta])*
16                ($variant:ident, $value:expr, $display:literal)
17            ),* $(,)?
18        }
19    ) => {
20        $(#[$enum_meta])*
21        #[repr($repr)]
22        $vis enum $name {
23            $(
24                $(#[$variant_meta])*
25                $variant = $value
26            ),*
27        }
28
29        impl TryFrom<$repr> for $name {
30            type Error = $crate::TpmProtocolError;
31
32            fn try_from(value: $repr) -> Result<Self, $crate::TpmProtocolError> {
33                match value {
34                    $(
35                        _ if value == $value => Ok(Self::$variant),
36                    )*
37                    _ => Err($crate::TpmProtocolError::VariantMissing),
38                }
39            }
40        }
41
42        impl core::fmt::Display for $name {
43            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44                let s = match self {
45                    $(Self::$variant => $display),*
46                };
47                write!(f, "{}", s)
48            }
49        }
50
51        impl $crate::TpmSized for $name {
52            const SIZE: usize = core::mem::size_of::<$repr>();
53
54            fn len(&self) -> usize {
55                Self::SIZE
56            }
57        }
58
59        impl $crate::TpmMarshal for $name {
60            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
61                $crate::TpmMarshal::marshal(&(*self as $repr), writer)
62            }
63        }
64
65        impl $crate::TpmUnmarshal for $name {
66            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
67                let (val, buf) = <$repr>::unmarshal(buf)?;
68                let enum_val = Self::try_from(val)?;
69                Ok((enum_val, buf))
70            }
71        }
72    };
73}