Skip to main content

typhoon_errors_macro/
lib.rs

1use {
2    proc_macro::TokenStream,
3    quote::{quote, ToTokens},
4    syn::parse_macro_input,
5    typhoon_syn::Errors,
6};
7
8/// Derive macro for generating error implementations
9///
10/// Usage:
11/// ```rust
12/// # use {
13/// #    pinocchio::error::{ProgramError, ToStr},
14/// #    typhoon_errors::Error,
15/// #    typhoon_errors_macro::TyphoonError
16/// # };
17/// #[derive(TyphoonError)]
18/// pub enum MyError {
19///     #[msg("Error: Invalid owner")]
20///     InvalidOwner = 200,
21///     #[msg("Error: Insufficient funds")]
22///     InsufficientFunds,
23/// }
24/// ```
25#[proc_macro_derive(TyphoonError, attributes(msg))]
26pub fn typhoon_error(input: TokenStream) -> TokenStream {
27    let errors_token = parse_macro_input!(input as Errors);
28
29    let name = &errors_token.name;
30
31    let (to_str_arms, try_from_arms) = errors_token
32        .variants
33        .iter()
34        .map(|v| {
35            let variant_name = &v.name;
36            let msg = &v.msg;
37            let discriminant = &v.discriminant;
38            (
39                quote!(#name::#variant_name => #msg,),
40                quote!(#discriminant => Ok(#name::#variant_name),),
41            )
42        })
43        .collect::<(Vec<_>, Vec<_>)>();
44
45    quote! {
46        impl TryFrom<u32> for #name {
47            type Error = ProgramError;
48
49            fn try_from(value: u32) -> Result<Self, Self::Error> {
50                match value {
51                    #(#try_from_arms)*
52                    _ => Err(ProgramError::InvalidArgument),
53                }
54            }
55        }
56
57        impl ToStr for #name {
58            fn to_str(&self) -> &'static str
59            {
60                match self {
61                    #(#to_str_arms)*
62                }
63            }
64        }
65
66        impl From<#name> for Error {
67            fn from(value: #name) -> Self {
68                Error::new(ProgramError::Custom(value as u32))
69            }
70        }
71    }
72    .into_token_stream()
73    .into()
74}