aboutsummaryrefslogtreecommitdiff
path: root/rust/qemu-api-macros/src
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2025-05-13 13:04:41 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2025-06-03 22:44:40 +0200
commit214518614c1ce7eb7a002452cd43a7597f90d543 (patch)
tree094cc866ec80b46cb2c642eaf063d121fae4032b /rust/qemu-api-macros/src
parent9c8ff2a1ed51b52ac64b80d35bdbd239b7b5d8e5 (diff)
downloadqemu-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.rs44
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
}
}
})