use thiserror::Error;
#[derive(Debug, Default, PartialEq)]
#[non_exhaustive]
#[repr(u32)]
pub enum CommonResult {
#[default]
Success = 0,
NotFound = 1,
InvalidData = 2,
InvalidInput = 3,
TopicTooLong = 4,
TooManyTopics = 5,
PayloadTooLong = 6,
MessageTopicFull = 7,
MaxMessagesPerBlockExceeded = 8,
Internal = 9,
Other(u32),
}
pub const HOST_ERROR_SUCCESS: u32 = 0;
pub const HOST_ERROR_NOT_FOUND: u32 = 1;
pub const HOST_ERROR_INVALID_DATA: u32 = 2;
pub const HOST_ERROR_INVALID_INPUT: u32 = 3;
pub const HOST_ERROR_TOPIC_TOO_LONG: u32 = 4;
pub const HOST_ERROR_TOO_MANY_TOPICS: u32 = 5;
pub const HOST_ERROR_PAYLOAD_TOO_LONG: u32 = 6;
pub const HOST_ERROR_MESSAGE_TOPIC_FULL: u32 = 7;
pub const HOST_ERROR_MAX_MESSAGES_PER_BLOCK_EXCEEDED: u32 = 8;
pub const HOST_ERROR_INTERNAL: u32 = 9;
impl From<u32> for CommonResult {
fn from(value: u32) -> Self {
match value {
HOST_ERROR_SUCCESS => Self::Success,
HOST_ERROR_NOT_FOUND => Self::NotFound,
HOST_ERROR_INVALID_DATA => Self::InvalidData,
HOST_ERROR_INVALID_INPUT => Self::InvalidInput,
HOST_ERROR_TOPIC_TOO_LONG => Self::TopicTooLong,
HOST_ERROR_TOO_MANY_TOPICS => Self::TooManyTopics,
HOST_ERROR_PAYLOAD_TOO_LONG => Self::PayloadTooLong,
HOST_ERROR_MESSAGE_TOPIC_FULL => Self::MessageTopicFull,
HOST_ERROR_MAX_MESSAGES_PER_BLOCK_EXCEEDED => Self::MaxMessagesPerBlockExceeded,
HOST_ERROR_INTERNAL => Self::Internal,
other => Self::Other(other),
}
}
}
pub fn result_from_code(code: u32) -> Result<(), CommonResult> {
match code {
HOST_ERROR_SUCCESS => Ok(()),
other => Err(CommonResult::from(other)),
}
}
#[derive(Debug, Error)]
pub enum TrapCode {
#[error("call stack exhausted")]
StackOverflow,
#[error("out of bounds memory access")]
MemoryOutOfBounds,
#[error("undefined element: out of bounds table access")]
TableAccessOutOfBounds,
#[error("uninitialized element")]
IndirectCallToNull,
#[error("indirect call type mismatch")]
BadSignature,
#[error("integer overflow")]
IntegerOverflow,
#[error("integer divide by zero")]
IntegerDivisionByZero,
#[error("invalid conversion to integer")]
BadConversionToInteger,
#[error("unreachable")]
UnreachableCodeReached,
}
pub const CALLEE_SUCCEEDED: u32 = 0;
pub const CALLEE_REVERTED: u32 = 1;
pub const CALLEE_TRAPPED: u32 = 2;
pub const CALLEE_GAS_DEPLETED: u32 = 3;
pub const CALLEE_NOT_CALLABLE: u32 = 4;
pub const CALLEE_HOST_ERROR: u32 = 5;
#[derive(Debug, Error)]
pub enum CallError {
#[error("callee reverted")]
CalleeReverted,
#[error("callee trapped: {0}")]
CalleeTrapped(TrapCode),
#[error("callee gas depleted")]
CalleeGasDepleted,
#[error("not callable")]
NotCallable,
}
impl CallError {
#[must_use]
pub fn into_u32(self) -> u32 {
match self {
Self::CalleeReverted => CALLEE_REVERTED,
Self::CalleeTrapped(_) => CALLEE_TRAPPED,
Self::CalleeGasDepleted => CALLEE_GAS_DEPLETED,
Self::NotCallable => CALLEE_NOT_CALLABLE,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_u32_not_found() {
let error = CommonResult::from(HOST_ERROR_NOT_FOUND);
assert_eq!(error, CommonResult::NotFound);
}
#[test]
fn test_from_u32_invalid_data() {
let error = CommonResult::from(HOST_ERROR_INVALID_DATA);
assert_eq!(error, CommonResult::InvalidData);
}
#[test]
fn test_from_u32_invalid_input() {
let error = CommonResult::from(HOST_ERROR_INVALID_INPUT);
assert_eq!(error, CommonResult::InvalidInput);
}
#[test]
fn test_from_u32_other() {
let error = CommonResult::from(10);
assert_eq!(error, CommonResult::Other(10));
}
}