diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2025-05-13 13:04:41 +0200 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2025-06-03 22:44:40 +0200 |
commit | 214518614c1ce7eb7a002452cd43a7597f90d543 (patch) | |
tree | 094cc866ec80b46cb2c642eaf063d121fae4032b /rust/qemu-api-macros/src | |
parent | 9c8ff2a1ed51b52ac64b80d35bdbd239b7b5d8e5 (diff) | |
download | qemu-214518614c1ce7eb7a002452cd43a7597f90d543.zip qemu-214518614c1ce7eb7a002452cd43a7597f90d543.tar.gz qemu-214518614c1ce7eb7a002452cd43a7597f90d543.tar.bz2 |
rust: qemu-api-macros: add from_bits and into_bits to #[derive(TryInto)]
These const functions make it possible to use enums easily together
with the bitfield-struct crate.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'rust/qemu-api-macros/src')
-rw-r--r-- | rust/qemu-api-macros/src/lib.rs | 44 |
1 files changed, 36 insertions, 8 deletions
diff --git a/rust/qemu-api-macros/src/lib.rs b/rust/qemu-api-macros/src/lib.rs index ceb79f0..1034707 100644 --- a/rust/qemu-api-macros/src/lib.rs +++ b/rust/qemu-api-macros/src/lib.rs @@ -193,23 +193,51 @@ fn get_variants(input: &DeriveInput) -> Result<&Punctuated<Variant, Comma>, Macr } #[rustfmt::skip::macros(quote)] +fn derive_tryinto_body( + name: &Ident, + variants: &Punctuated<Variant, Comma>, + repr: &Path, +) -> Result<proc_macro2::TokenStream, MacroError> { + let discriminants: Vec<&Ident> = variants.iter().map(|f| &f.ident).collect(); + + Ok(quote! { + #(const #discriminants: #repr = #name::#discriminants as #repr;)*; + match value { + #(#discriminants => Ok(#name::#discriminants),)* + _ => Err(value), + } + }) +} + +#[rustfmt::skip::macros(quote)] fn derive_tryinto_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> { let repr = get_repr_uN(&input, "#[derive(TryInto)]")?; - let name = &input.ident; - let variants = get_variants(&input)?; - let discriminants: Vec<&Ident> = variants.iter().map(|f| &f.ident).collect(); + let body = derive_tryinto_body(name, get_variants(&input)?, &repr)?; + let errmsg = format!("invalid value for {name}"); Ok(quote! { + impl #name { + #[allow(dead_code)] + pub const fn into_bits(self) -> #repr { + self as #repr + } + + #[allow(dead_code)] + pub const fn from_bits(value: #repr) -> Self { + match ({ + #body + }) { + Ok(x) => x, + Err(_) => panic!(#errmsg) + } + } + } impl core::convert::TryFrom<#repr> for #name { type Error = #repr; fn try_from(value: #repr) -> Result<Self, Self::Error> { - #(const #discriminants: #repr = #name::#discriminants as #repr;)*; - match value { - #(#discriminants => Ok(Self::#discriminants),)* - _ => Err(value), - } + #body } } }) |