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#[doc(hidden)]
10#[macro_export]
11macro_rules! tpm_enum {
12    (@impl $(#[$enum_meta:meta])* $vis:vis enum $name:ident($wrapper:ty, $repr:ty) {
13        $(
14            $(#[$variant_meta:meta])*
15            ($variant:ident, $value:expr, $display:literal)
16        ),* $(,)?
17    }) => {
18        $(#[$enum_meta])*
19        #[repr($repr)]
20        #[non_exhaustive]
21        $vis enum $name {
22            $(
23                $(#[$variant_meta])*
24                $variant = $value
25            ),*
26        }
27
28        impl TryFrom<$repr> for $name {
29            type Error = $crate::TpmError;
30
31            #[allow(clippy::cast_lossless, clippy::cast_sign_loss)]
32            fn try_from(value: $repr) -> Result<Self, $crate::TpmError> {
33                match value {
34                    $(
35                        _ if value == $value => Ok(Self::$variant),
36                    )*
37                    _ => Err($crate::TpmError::VariantNotAvailable { offset: 0, value: value as u64 }),
38                }
39            }
40        }
41
42        impl $name {
43            #[must_use]
44            pub const fn value(self) -> $repr {
45                self as $repr
46            }
47        }
48
49        impl core::fmt::Display for $name {
50            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51                let s = match self {
52                    $(Self::$variant => $display),*
53                };
54                write!(f, "{}", s)
55            }
56        }
57
58        impl $crate::TpmSized for $name {
59            const SIZE: usize = core::mem::size_of::<$repr>();
60
61            fn len(&self) -> usize {
62                Self::SIZE
63            }
64        }
65
66        impl $crate::TpmMarshal for $name {
67            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
68                let value = <$wrapper>::from(*self as $repr);
69                $crate::TpmMarshal::marshal(&value, writer)
70            }
71        }
72
73        impl<'a> $crate::TpmField<'a> for $name {
74            type View = Self;
75
76            fn cast_prefix_field(buf: &'a [u8]) -> $crate::TpmResult<(Self::View, &'a [u8])> {
77                let (value, buf) = <$wrapper as $crate::TpmCast>::cast_prefix(buf)?;
78                let raw: $repr = value.value();
79                let enum_val = Self::try_from(raw)?;
80
81                Ok((enum_val, buf))
82            }
83        }
84    };
85
86    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmUint8) { $($rest:tt)* }) => {
87        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmUint8, u8) { $($rest)* });
88    };
89    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmInt8) { $($rest:tt)* }) => {
90        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmInt8, i8) { $($rest)* });
91    };
92    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmUint16) { $($rest:tt)* }) => {
93        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmUint16, u16) { $($rest)* });
94    };
95    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmUint32) { $($rest:tt)* }) => {
96        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmUint32, u32) { $($rest)* });
97    };
98    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmInt32) { $($rest:tt)* }) => {
99        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmInt32, i32) { $($rest)* });
100    };
101    ($(#[$meta:meta])* $vis:vis enum $name:ident(TpmUint64) { $($rest:tt)* }) => {
102        tpm_enum!(@impl $(#[$meta])* $vis enum $name($crate::basic::TpmUint64, u64) { $($rest)* });
103    };
104}