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