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            #[allow(clippy::cognitive_complexity)]
33            fn try_from(value: $repr) -> Result<Self, $crate::TpmProtocolError> {
34                $(
35                    if value == $value {
36                        return Ok(Self::$variant);
37                    }
38                )*
39                Err($crate::TpmProtocolError::VariantMissing)
40            }
41        }
42
43        impl core::fmt::Display for $name {
44            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
45                let s = match self {
46                    $(Self::$variant => $display),*
47                };
48                write!(f, "{}", s)
49            }
50        }
51
52        impl $crate::TpmSized for $name {
53            const SIZE: usize = core::mem::size_of::<$repr>();
54
55            fn len(&self) -> usize {
56                Self::SIZE
57            }
58        }
59
60        impl $crate::TpmMarshal for $name {
61            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
62                $crate::TpmMarshal::marshal(&(*self as $repr), writer)
63            }
64        }
65
66        impl $crate::TpmUnmarshal for $name {
67            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
68                let (val, buf) = <$repr>::unmarshal(buf)?;
69                let enum_val = Self::try_from(val)?;
70                Ok((enum_val, buf))
71            }
72        }
73    };
74}