anchor_syn/codegen/
error.rs

1use crate::Error;
2use quote::quote;
3
4pub fn generate(error: Error) -> proc_macro2::TokenStream {
5    let error_enum = &error.raw_enum;
6    let enum_name = &error.ident;
7    // Each arm of the `match` statement for implementing `std::fmt::Display`
8    // on the user defined error code.
9    let display_variant_dispatch: Vec<proc_macro2::TokenStream> = error
10        .raw_enum
11        .variants
12        .iter()
13        .enumerate()
14        .map(|(idx, variant)| {
15            let ident = &variant.ident;
16            let error_code = &error.codes[idx];
17            let display_msg = match &error_code.msg {
18                None => {
19                    quote! {
20                        <Self as std::fmt::Debug>::fmt(self, fmt)
21                    }
22                }
23                Some(msg) => {
24                    quote! {
25                        write!(fmt, #msg)
26                    }
27                }
28            };
29            quote! {
30                #enum_name::#ident => #display_msg
31            }
32        })
33        .collect();
34
35    // Each arm of the `match` statement for implementing the `name` function
36    // on the user defined error code.
37    let name_variant_dispatch: Vec<proc_macro2::TokenStream> = error
38        .raw_enum
39        .variants
40        .iter()
41        .map(|variant| {
42            let ident = &variant.ident;
43            let ident_name = ident.to_string();
44            quote! {
45                #enum_name::#ident => #ident_name.to_string()
46            }
47        })
48        .collect();
49
50    let offset = match &error.args {
51        None => quote! { anchor_lang::error::ERROR_CODE_OFFSET},
52        Some(args) => {
53            let offset = &args.offset;
54            quote! { #offset }
55        }
56    };
57
58    let ret = quote! {
59        #[derive(std::fmt::Debug, Clone, Copy)]
60        #[repr(u32)]
61        #error_enum
62
63        impl #enum_name {
64            /// Gets the name of this [#enum_name].
65            pub fn name(&self) -> String {
66                match self {
67                    #(#name_variant_dispatch),*
68                }
69            }
70        }
71
72        impl From<#enum_name> for u32 {
73            fn from(e: #enum_name) -> u32 {
74                e as u32 + #offset
75            }
76        }
77
78        impl From<#enum_name> for anchor_lang::error::Error {
79            fn from(error_code: #enum_name) -> anchor_lang::error::Error {
80                anchor_lang::error::Error::from(
81                    anchor_lang::error::AnchorError {
82                        error_name: error_code.name(),
83                        error_code_number: error_code.into(),
84                        error_msg: error_code.to_string(),
85                        error_origin: None,
86                        compared_values: None
87                    }
88                )
89            }
90        }
91
92        impl std::fmt::Display for #enum_name {
93            fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
94                match self {
95                    #(#display_variant_dispatch),*
96                }
97            }
98        }
99    };
100
101    #[cfg(feature = "idl-build")]
102    {
103        let idl_print = crate::idl::gen_idl_print_fn_error(&error);
104        return quote! {
105            #ret
106            #idl_print
107        };
108    };
109
110    #[allow(unreachable_code)]
111    ret
112}