extern crate alloc;
use bytecheck::CheckBytes;
use rkyv::{Archive, Deserialize, Serialize};
use alloc::string::String;
use core::fmt::{Display, Formatter};
use core::str;
#[derive(Debug, Clone, Archive, Serialize, Deserialize)]
#[archive_attr(derive(CheckBytes))]
pub enum ContractError {
Panic(String),
OutOfGas,
Unknown,
}
impl ContractError {
#[cfg(feature = "abi")]
pub(crate) fn from_parts(code: i32, slice: &[u8]) -> Self {
fn get_msg(slice: &[u8]) -> String {
let msg_len = {
let mut msg_len_bytes = [0u8; 4];
msg_len_bytes.copy_from_slice(&slice[..4]);
u32::from_le_bytes(msg_len_bytes)
} as usize;
let msg = unsafe {
use alloc::string::ToString;
let msg_bytes = &slice[4..4 + msg_len];
let msg_str = str::from_utf8_unchecked(msg_bytes);
msg_str.to_string()
};
msg
}
match code {
-1 => Self::Panic(get_msg(slice)),
-2 => Self::OutOfGas,
i32::MIN => Self::Unknown,
_ => unreachable!("The host must guarantee that the code is valid"),
}
}
pub fn to_parts(&self, slice: &mut [u8]) -> i32 {
fn put_msg(msg: &str, slice: &mut [u8]) {
let msg_bytes = msg.as_bytes();
let msg_len = msg_bytes.len();
let mut msg_len_bytes = [0u8; 4];
msg_len_bytes.copy_from_slice(&(msg_len as u32).to_le_bytes());
slice[..4].copy_from_slice(&msg_len_bytes);
slice[4..4 + msg_len].copy_from_slice(msg_bytes);
}
match self {
Self::Panic(msg) => {
put_msg(msg, slice);
-1
}
Self::OutOfGas => -2,
Self::Unknown => i32::MIN,
}
}
}
impl From<ContractError> for i32 {
fn from(err: ContractError) -> Self {
match err {
ContractError::Panic(_) => -1,
ContractError::OutOfGas => -2,
ContractError::Unknown => i32::MIN,
}
}
}
impl Display for ContractError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
ContractError::Panic(msg) => write!(f, "Panic: {msg}"),
ContractError::OutOfGas => write!(f, "OutOfGas"),
ContractError::Unknown => write!(f, "Unknown"),
}
}
}