use alloc::vec::Vec;
use core::{fmt, str};
pub use gcore::errors::{Error as CoreError, *};
pub use scale_info::scale::Error as CodecError;
pub type Result<T, E = Error> = core::result::Result<T, E>;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Error {
Core(CoreError),
Convert(ConversionError),
Decode(CodecError),
Gstd(UsageError),
ErrorReply(ErrorReplyPayload, ErrorReplyReason),
UnsupportedReply(Vec<u8>),
Timeout(u32, u32),
}
impl Error {
pub fn timed_out(&self) -> bool {
matches!(self, Error::Timeout(..))
}
pub fn error_reply_str(&self) -> Option<&str> {
if let Self::ErrorReply(payload, _) = self {
payload.try_as_str()
} else {
None
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Core(e) => fmt::Display::fmt(e, f),
Error::Convert(e) => write!(f, "Conversion error: {e:?}"),
Error::Decode(e) => write!(f, "Scale codec decoding error: {e}"),
Error::Gstd(e) => write!(f, "`Gstd` API error: {e:?}"),
Error::ErrorReply(err, reason) => write!(f, "Received reply '{err}' due to {reason:?}"),
Error::UnsupportedReply(payload) => {
write!(f, "Received unsupported reply '0x{}'", hex::encode(payload))
}
Error::Timeout(expected, now) => {
write!(f, "Timeout has occurred: expected at {expected}, now {now}")
}
}
}
}
impl From<CoreError> for Error {
fn from(err: CoreError) -> Self {
Self::Core(err)
}
}
impl From<ConversionError> for Error {
fn from(err: ConversionError) -> Self {
Self::Convert(err)
}
}
#[derive(Clone, Eq, PartialEq)]
pub struct ErrorReplyPayload(pub Vec<u8>);
impl ErrorReplyPayload {
pub fn try_as_str(&self) -> Option<&str> {
str::from_utf8(&self.0).ok()
}
#[track_caller]
pub fn as_str(&self) -> &str {
str::from_utf8(&self.0).expect("Failed to create `str`")
}
}
impl From<Vec<u8>> for ErrorReplyPayload {
fn from(value: Vec<u8>) -> Self {
Self(value)
}
}
impl fmt::Debug for ErrorReplyPayload {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.try_as_str()
.map(|v| write!(f, "{v}"))
.unwrap_or_else(|| write!(f, "0x{}", hex::encode(&self.0)))
}
}
impl fmt::Display for ErrorReplyPayload {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum UsageError {
EmptyWaitDuration,
ZeroSystemReservationAmount,
ZeroMxLockDuration,
ZeroReplyDeposit,
}
impl fmt::Display for UsageError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UsageError::EmptyWaitDuration => write!(f, "Wait duration can not be zero"),
UsageError::ZeroSystemReservationAmount => {
write!(f, "System reservation amount can not be zero in config")
}
UsageError::ZeroMxLockDuration => write!(f, "Mutex lock duration can not be zero"),
UsageError::ZeroReplyDeposit => {
write!(f, "Reply deposit can not be zero when setting reply hook")
}
}
}
}