typhoon_errors/
lib.rs

1#![no_std]
2
3mod error_code;
4mod extension;
5
6use pinocchio::program_error::{ProgramError, ToStr};
7pub use {error_code::*, extension::*};
8
9pub struct Error {
10    error: ProgramError,
11    account_name: Option<&'static str>,
12}
13
14impl Error {
15    #[inline(always)]
16    pub fn new(error: impl Into<ProgramError>) -> Self {
17        Error {
18            error: error.into(),
19            account_name: None,
20        }
21    }
22
23    #[inline(always)]
24    pub fn with_account(mut self, name: &'static str) -> Self {
25        self.account_name = Some(name);
26        self
27    }
28
29    #[inline(always)]
30    pub fn account_name(&self) -> Option<&str> {
31        self.account_name
32    }
33}
34
35impl ToStr for Error {
36    fn to_str<E>(&self) -> &'static str
37    where
38        E: 'static + ToStr + TryFrom<u32>,
39    {
40        if let ProgramError::Custom(code) = self.error {
41            if (100..200).contains(&code) {
42                return self.error.to_str::<ErrorCode>();
43            }
44        }
45        self.error.to_str::<E>()
46    }
47}
48
49impl From<ProgramError> for Error {
50    #[inline(always)]
51    fn from(error: ProgramError) -> Self {
52        Error {
53            error,
54            account_name: None,
55        }
56    }
57}
58
59impl From<ErrorCode> for Error {
60    #[inline(always)]
61    fn from(value: ErrorCode) -> Self {
62        Error {
63            error: value.into(),
64            account_name: None,
65        }
66    }
67}
68
69impl From<Error> for ProgramError {
70    #[inline(always)]
71    fn from(value: Error) -> Self {
72        value.error
73    }
74}
75
76#[macro_export]
77macro_rules! impl_error_logger {
78    ($error:ident) => {
79        #[cfg(feature = "logging")]
80        #[cold]
81        fn log_error(error: &Error) {
82            pinocchio::log::sol_log(error.to_str::<$error>());
83            if let Some(account_name) = error.account_name() {
84                let mut buffer = [bytes::UNINIT_BYTE; 50];
85                let total_len = core::cmp::min(account_name.len() + 16, 50);
86                bytes::write_bytes(&mut buffer[..16], b"Account origin: ");
87                bytes::write_bytes(&mut buffer[16..total_len], account_name.as_bytes());
88                pinocchio::log::sol_log(unsafe {
89                    core::str::from_utf8_unchecked(core::slice::from_raw_parts(
90                        buffer.as_ptr() as _,
91                        total_len,
92                    ))
93                });
94            }
95        }
96    };
97}