error.rs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  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 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 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 => #msg
  30. }
  31. })
  32. .collect();
  33. quote! {
  34. type Result<T> = std::result::Result<T, Error>;
  35. #[derive(thiserror::Error, Debug)]
  36. pub enum Error {
  37. #[error(transparent)]
  38. ProgramError(#[from] ProgramError),
  39. #[error(transparent)]
  40. ErrorCode(#[from] #enum_name),
  41. }
  42. #[derive(Debug, Clone, Copy)]
  43. #[repr(u32)]
  44. #error_enum
  45. impl std::fmt::Display for #enum_name {
  46. fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
  47. match self {
  48. #(#variant_dispatch),*
  49. }
  50. }
  51. }
  52. impl std::error::Error for #enum_name {}
  53. impl std::convert::From<Error> for ProgramError {
  54. fn from(e: Error) -> ProgramError {
  55. // Errors 0-100 are reserved for the framework.
  56. let error_offset = 100u32;
  57. match e {
  58. Error::ProgramError(e) => e,
  59. Error::ErrorCode(c) => ProgramError::Custom(c as u32 + error_offset),
  60. }
  61. }
  62. }
  63. impl std::convert::From<#enum_name> for ProgramError {
  64. fn from(e: #enum_name) -> ProgramError {
  65. let err: Error = e.into();
  66. err.into()
  67. }
  68. }
  69. }
  70. }