blob: 3be9bd60b5325b6ef3523db3c2741ecf11ecac99 [file] [log] [blame]
// SPDX-License-Identifier: MIT OR Apache-2.0
// Copyright (c) 2025 Opinsys Oy
// Copyright (c) 2024-2025 Jarkko Sakkinen
//! The chain of `if`-statements is a deliberate design choice as patterns in
//! a `match`-statement is too restricted for arbitrary expressions (e.g, see
//! `TpmRc` for an example).
#[macro_export]
macro_rules! tpm_enum {
(
$(#[$enum_meta:meta])*
$vis:vis enum $name:ident($repr:ty) {
$(
$(#[$variant_meta:meta])*
($variant:ident, $value:expr, $display:literal)
),* $(,)?
}
) => {
$(#[$enum_meta])*
#[repr($repr)]
$vis enum $name {
$(
$(#[$variant_meta])*
$variant = $value
),*
}
impl TryFrom<$repr> for $name {
type Error = ();
#[allow(clippy::cognitive_complexity)]
fn try_from(value: $repr) -> Result<Self, ()> {
$(
if value == $value {
return Ok(Self::$variant);
}
)*
Err(())
}
}
impl core::fmt::Display for $name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let s = match self {
$(Self::$variant => $display),*
};
write!(f, "{}", s)
}
}
impl core::str::FromStr for $name {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
$($display => Ok(Self::$variant),)*
_ => Err(()),
}
}
}
impl $crate::TpmSized for $name {
const SIZE: usize = core::mem::size_of::<$repr>();
fn len(&self) -> usize {
Self::SIZE
}
}
impl $crate::TpmMarshal for $name {
fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
$crate::TpmMarshal::marshal(&(*self as $repr), writer)
}
}
impl $crate::TpmUnmarshal for $name {
fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
let (val, buf) = <$repr>::unmarshal(buf)?;
let enum_val = Self::try_from(val).map_err(|()| $crate::TpmError::InvalidDiscriminant (stringify!($name), val.into()))?;
Ok((enum_val, buf))
}
}
};
}