this_error_from_box/
lib.rs1use proc_macro::TokenStream;
4use quote::quote;
5use syn::{Data, DeriveInput, Fields, parse_macro_input};
6
7#[proc_macro_attribute]
8pub fn this_error_from_box(_attr: TokenStream, item: TokenStream) -> TokenStream {
9 let input = parse_macro_input!(item as DeriveInput);
10 let enum_name = &input.ident;
11 let mut from_impls = Vec::new();
12
13 if let Data::Enum(data_enum) = &input.data {
14 for variant in &data_enum.variants {
15 if let Fields::Unnamed(fields) = &variant.fields {
16 if fields.unnamed.len() == 1 {
17 let field = &fields.unnamed[0];
18 let mut has_from = false;
19 for attr in &field.attrs {
20 if attr.path().is_ident("from") {
21 has_from = true;
22 break;
23 }
24 }
25 if has_from {
26 if let syn::Type::Path(type_path) = &field.ty {
28 let segments = &type_path.path.segments;
29 let is_std_box = {
31 let segs: Vec<_> = type_path.path.segments.iter().map(|s| s.ident.to_string()).collect();
32 (segs == ["std", "boxed", "Box"])
33 || (segs == ["alloc", "boxed", "Box"])
34 || (segs == ["Box"]) };
36 if is_std_box {
37 if let syn::PathArguments::AngleBracketed(args) = &segments.last().unwrap().arguments {
38 if args.args.len() == 1 {
39 if let syn::GenericArgument::Type(inner_ty) = &args.args[0] {
40 let variant_ident = &variant.ident;
41 from_impls.push(quote! {
42 impl ::std::convert::From<#inner_ty> for #enum_name {
43 fn from(e: #inner_ty) -> Self {
44 #enum_name::#variant_ident(::std::boxed::Box::new(e))
45 }
46 }
47 });
48 }
49 }
50 }
51 }
52 }
53 }
54 }
55 }
56 }
57 }
58
59 let expanded = quote! {
60 #input
61 #(#from_impls)*
62 };
63 TokenStream::from(expanded)
64}