use jam_types::{
simple_result_code::InvokeOutcomeCode, SimpleResult, SimpleResultCode, LOWEST_ERROR,
};
#[derive(Debug)]
pub enum ApiError {
OutOfBounds,
IndexUnknown,
StorageFull,
BadCore,
NoCash,
GasLimitTooLow,
GasLimitTooHigh,
ActionInvalid,
}
impl From<u64> for ApiError {
fn from(code: SimpleResult) -> Self {
match code {
c if c == SimpleResultCode::OutOfBounds as u64 => ApiError::OutOfBounds,
c if c == SimpleResultCode::IndexUnknown as u64 => ApiError::IndexUnknown,
c if c == SimpleResultCode::StorageFull as u64 => ApiError::StorageFull,
c if c == SimpleResultCode::BadCore as u64 => ApiError::BadCore,
c if c == SimpleResultCode::NoCash as u64 => ApiError::NoCash,
c if c == SimpleResultCode::GasLimitTooLow as u64 => ApiError::GasLimitTooLow,
c if c == SimpleResultCode::GasLimitTooHigh as u64 => ApiError::GasLimitTooHigh,
c if c == SimpleResultCode::ActionInvalid as u64 => ApiError::ActionInvalid,
_ => panic!("unknown error code: {}", code),
}
}
}
pub type ApiResult<T> = Result<T, ApiError>;
pub trait IntoApiResult<T> {
fn into_api_result(self) -> ApiResult<T>;
}
impl IntoApiResult<()> for SimpleResult {
fn into_api_result(self) -> ApiResult<()> {
if self == SimpleResultCode::Ok as u64 {
Ok(())
} else {
Err(self.into())
}
}
}
impl IntoApiResult<u64> for SimpleResult {
fn into_api_result(self) -> ApiResult<u64> {
if self < LOWEST_ERROR {
Ok(self)
} else {
Err(self.into())
}
}
}
impl IntoApiResult<u32> for SimpleResult {
fn into_api_result(self) -> ApiResult<u32> {
if self <= u32::MAX as _ {
Ok(self as u32)
} else if self < LOWEST_ERROR {
panic!("Our own API impl has resulted in success value which is out of range.");
} else {
Err(self.into())
}
}
}
impl IntoApiResult<Option<()>> for SimpleResult {
fn into_api_result(self) -> ApiResult<Option<()>> {
if self < LOWEST_ERROR {
Ok(Some(()))
} else if self == SimpleResultCode::Nothing as u64 {
Ok(None)
} else {
Err(self.into())
}
}
}
impl IntoApiResult<Option<u64>> for SimpleResult {
fn into_api_result(self) -> ApiResult<Option<u64>> {
if self < LOWEST_ERROR {
Ok(Some(self))
} else if self == SimpleResultCode::Nothing as u64 {
Ok(None)
} else {
Err(self.into())
}
}
}
pub enum InvokeOutcome {
Halt,
PageFault(u64),
HostCallFault(u64),
Panic,
OutOfGas,
}
pub type InvokeResult = ApiResult<InvokeOutcome>;
pub trait IntoInvokeResult {
fn into_invoke_result(self) -> InvokeResult;
}
impl IntoInvokeResult for [u64; 2] {
fn into_invoke_result(self) -> InvokeResult {
const STATUS_HALT: u64 = InvokeOutcomeCode::Halt as u64;
const STATUS_PANIC: u64 = InvokeOutcomeCode::Panic as u64;
const STATUS_FAULT: u64 = InvokeOutcomeCode::PageFault as u64;
const STATUS_HOST: u64 = InvokeOutcomeCode::HostCallFault as u64;
const STATUS_OOG: u64 = InvokeOutcomeCode::OutOfGas as u64;
match self {
[STATUS_HALT, _] => Ok(InvokeOutcome::Halt),
[STATUS_FAULT, address] => Ok(InvokeOutcome::PageFault(address)),
[STATUS_HOST, index] => Ok(InvokeOutcome::HostCallFault(index)),
[STATUS_PANIC, _] => Ok(InvokeOutcome::Panic),
[STATUS_OOG, _] => Ok(InvokeOutcome::OutOfGas),
[code, _] => Err(code.into()),
}
}
}
impl IntoInvokeResult for SimpleResult {
fn into_invoke_result(self) -> InvokeResult {
const STATUS_HALT: u64 = InvokeOutcomeCode::Halt as u64;
const STATUS_PANIC: u64 = InvokeOutcomeCode::Panic as u64;
const STATUS_FAULT: u64 = InvokeOutcomeCode::PageFault as u64;
const STATUS_HOST: u64 = InvokeOutcomeCode::HostCallFault as u64;
const STATUS_OOG: u64 = InvokeOutcomeCode::OutOfGas as u64;
match (self % (1 << 32), self / (1 << 32)) {
(STATUS_HALT, _) => Ok(InvokeOutcome::Halt),
(STATUS_FAULT, address) => Ok(InvokeOutcome::PageFault(address)),
(STATUS_HOST, index) => Ok(InvokeOutcome::HostCallFault(index)),
(STATUS_PANIC, _) => Ok(InvokeOutcome::Panic),
(STATUS_OOG, _) => Ok(InvokeOutcome::OutOfGas),
(code, _) => Err(code.into()),
}
}
}