mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
utils_macros: Implement derive_control_flag
Add a new derive macro 'derive_control_flag' that is used in the next
commit to reimplement how the code deals with Secure Execution control
flags.
It implements Display, IntoEnumIterator and the ControlFlagTrait for
enums using unit variants only.
/// Trait for control flags that provide bit position information.
pub trait ControlFlagTrait {
/// Returns the bit position for this flag.
fn bit_position(self) -> u8;
}
Assisted-by: IBM Bob:1.0.4
Signed-off-by: Marc Hartmayer <marc@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
committed by
Steffen Eiden
parent
618e22e38b
commit
2d330cd45f
@@ -4,11 +4,150 @@
|
||||
|
||||
//! Procedural macros for the utils crate.
|
||||
//!
|
||||
//! This crate provides derive macros to reduce boilerplate in enum definitions.
|
||||
//! This crate provides derive macros to reduce boilerplate in enum definitions,
|
||||
//! particularly for control flags.
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
use syn::{parse_macro_input, Data, DeriveInput, Fields, Lit, Meta, MetaList};
|
||||
|
||||
/// Derive macro for control flag enums.
|
||||
///
|
||||
/// This macro generates implementations for `Display`, `IntoEnumIterator`, and `ControlFlagTrait`.
|
||||
/// It supports the `#[flag(display = "...", value = N)]` attribute to specify custom display
|
||||
/// strings and discriminant values.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use utils_macros::ControlFlag;
|
||||
///
|
||||
/// /// Trait for enums that can be iterated over.
|
||||
/// pub trait IntoEnumIterator: Sized {
|
||||
/// /// Returns an iterator over all variants of the enum.
|
||||
/// fn iter() -> impl Iterator<Item = Self>;
|
||||
/// }
|
||||
///
|
||||
/// /// Trait for control flags that provide bit position information.
|
||||
/// pub trait ControlFlagTrait {
|
||||
/// /// Returns the bit position for this flag.
|
||||
/// fn bit_position(self) -> u8;
|
||||
/// }
|
||||
///
|
||||
/// #[derive(ControlFlag)]
|
||||
/// pub enum PcfV1 {
|
||||
/// #[flag(display = "Confidential dump support", value = 34)]
|
||||
/// ConfidentialDump,
|
||||
///
|
||||
/// #[flag(display = "V1-specific flag", value = 35)]
|
||||
/// V1OnlyFlag,
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_derive(ControlFlag, attributes(flag))]
|
||||
pub fn derive_control_flag(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let name = &input.ident;
|
||||
|
||||
let variants = match &input.data {
|
||||
Data::Enum(data) => &data.variants,
|
||||
_ => panic!("ControlFlag can only be derived for enums"),
|
||||
};
|
||||
|
||||
// Extract variant information
|
||||
let mut variant_names = Vec::new();
|
||||
let mut variant_displays = Vec::new();
|
||||
let mut variant_values = Vec::new();
|
||||
|
||||
for variant in variants {
|
||||
if !matches!(variant.fields, Fields::Unit) {
|
||||
panic!("ControlFlag only supports unit variants");
|
||||
}
|
||||
|
||||
let variant_name = &variant.ident;
|
||||
variant_names.push(variant_name);
|
||||
|
||||
// Parse the #[flag(...)] attribute
|
||||
let mut display_str = variant_name.to_string();
|
||||
let mut value: Option<u8> = None;
|
||||
|
||||
for attr in &variant.attrs {
|
||||
if attr.path().is_ident("flag") {
|
||||
// Try to parse as MetaList
|
||||
if let Meta::List(MetaList { tokens, .. }) = &attr.meta {
|
||||
// Parse the tokens inside the list
|
||||
let parser = syn::meta::parser(|meta| {
|
||||
if meta.path.is_ident("display") {
|
||||
let val = meta.value()?;
|
||||
let lit: Lit = val.parse()?;
|
||||
if let Lit::Str(s) = lit {
|
||||
display_str = s.value();
|
||||
}
|
||||
} else if meta.path.is_ident("value") {
|
||||
let val = meta.value()?;
|
||||
let lit: Lit = val.parse()?;
|
||||
if let Lit::Int(i) = lit {
|
||||
value = Some(i.base10_parse()?);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
let _ = syn::parse::Parser::parse2(parser, tokens.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if value.is_none() {
|
||||
panic!(
|
||||
"ControlFlag variant {} must have a value attribute",
|
||||
variant_name
|
||||
);
|
||||
}
|
||||
|
||||
variant_displays.push(display_str);
|
||||
variant_values.push(value.unwrap());
|
||||
}
|
||||
|
||||
let expanded = quote! {
|
||||
impl #name {
|
||||
/// Returns the bit position value for this flag.
|
||||
pub const fn flag_value(&self) -> u8 {
|
||||
match self {
|
||||
#(Self::#variant_names => #variant_values),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControlFlagTrait for #name {
|
||||
fn bit_position(self) -> u8 {
|
||||
self.flag_value()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for #name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
#(Self::#variant_names => #variant_displays),*
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoEnumIterator for #name {
|
||||
fn iter() -> impl Iterator<Item = Self> {
|
||||
[
|
||||
#(Self::#variant_names),*
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
/// Derive `std::fmt::Display` for enums implementing `clap::ValueEnum`.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user