nak: Special case Box in derive_from_variants

Reviewed-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37315>
This commit is contained in:
Mel Henning
2025-09-10 21:48:35 -04:00
committed by Marge Bot
parent 611c5ebce5
commit 6f6c309167
+41
View File
@@ -59,6 +59,32 @@ pub fn enum_derive_display_op(input: TokenStream) -> TokenStream {
}
}
fn into_box_inner_type<'a>(from_type: &'a syn::Type) -> Option<&'a syn::Type> {
let last = match from_type {
Type::Path(TypePath { path, .. }) => path.segments.last()?,
_ => return None,
};
if last.ident != "Box" {
return None;
}
let PathArguments::AngleBracketed(AngleBracketedGenericArguments {
args,
..
}) = &last.arguments
else {
panic!("Expected Box<T> (with angle brackets)");
};
for arg in args {
if let GenericArgument::Type(inner_type) = arg {
return Some(inner_type);
}
}
panic!("Expected Box to use a type argument");
}
#[proc_macro_derive(FromVariants)]
pub fn derive_from_variants(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
@@ -74,6 +100,9 @@ pub fn derive_from_variants(input: TokenStream) -> TokenStream {
_ => panic!("Expected Op(OpFoo)"),
};
assert!(from_type.len() == 1, "Expected Op(OpFoo)");
let from_type = &from_type.first().unwrap().ty;
let quote = quote! {
impl From<#from_type> for #enum_type {
fn from (op: #from_type) -> #enum_type {
@@ -83,6 +112,18 @@ pub fn derive_from_variants(input: TokenStream) -> TokenStream {
};
impls.extend(quote);
if let Some(inner_type) = into_box_inner_type(from_type) {
let quote = quote! {
impl From<#inner_type> for #enum_type {
fn from(value: #inner_type) -> Self {
From::from(Box::new(value))
}
}
};
impls.extend(quote);
}
}
}