error.rs 3.0 KB

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