1extern crate alloc;
8
9use bytecheck::CheckBytes;
10use rkyv::{Archive, Deserialize, Serialize};
11
12use alloc::string::String;
13
14use core::fmt::{Display, Formatter};
15use core::str;
16
17#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
26#[archive_attr(derive(CheckBytes))]
27pub enum ContractError {
28 Panic(String),
29 OutOfGas,
30 DoesNotExist,
31 Unknown,
32}
33
34impl ContractError {
35 #[cfg(feature = "abi")]
38 pub(crate) fn from_parts(code: i32, slice: &[u8]) -> Self {
39 fn get_msg(slice: &[u8]) -> String {
40 let msg_len = {
41 let mut msg_len_bytes = [0u8; 4];
42 msg_len_bytes.copy_from_slice(&slice[..4]);
43 u32::from_le_bytes(msg_len_bytes)
44 } as usize;
45
46 let msg = unsafe {
49 use alloc::string::ToString;
50 let msg_bytes = &slice[4..4 + msg_len];
51 let msg_str = str::from_utf8_unchecked(msg_bytes);
52 msg_str.to_string()
53 };
54
55 msg
56 }
57
58 match code {
59 -1 => Self::Panic(get_msg(slice)),
60 -2 => Self::OutOfGas,
61 -3 => Self::DoesNotExist,
62 i32::MIN => Self::Unknown,
63 _ => unreachable!("The host must guarantee that the code is valid"),
64 }
65 }
66
67 pub fn to_parts(&self, slice: &mut [u8]) -> i32 {
69 fn put_msg(msg: &str, slice: &mut [u8]) {
70 let msg_bytes = msg.as_bytes();
71 let msg_len = msg_bytes.len();
72
73 let mut msg_len_bytes = [0u8; 4];
74 msg_len_bytes.copy_from_slice(&(msg_len as u32).to_le_bytes());
75
76 slice[..4].copy_from_slice(&msg_len_bytes);
77 slice[4..4 + msg_len].copy_from_slice(msg_bytes);
78 }
79
80 match self {
81 Self::Panic(msg) => {
82 put_msg(msg, slice);
83 -1
84 }
85 Self::OutOfGas => -2,
86 Self::DoesNotExist => -3,
87 Self::Unknown => i32::MIN,
88 }
89 }
90}
91
92impl From<ContractError> for i32 {
93 fn from(err: ContractError) -> Self {
94 match err {
95 ContractError::Panic(_) => -1,
96 ContractError::OutOfGas => -2,
97 ContractError::DoesNotExist => -3,
98 ContractError::Unknown => i32::MIN,
99 }
100 }
101}
102
103impl Display for ContractError {
104 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
105 match self {
106 ContractError::Panic(msg) => write!(f, "Panic: {msg}"),
107 ContractError::OutOfGas => write!(f, "OutOfGas"),
108 ContractError::DoesNotExist => {
109 write!(f, "Contract does not exist")
110 }
111 ContractError::Unknown => write!(f, "Unknown"),
112 }
113 }
114}