use alloc::{fmt, vec::Vec};
use core::convert::{TryFrom, TryInto};
#[cfg(feature = "std")]
use thiserror::Error;
use crate::{
bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
AccessRights, CLType, CLTyped,
};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Error))]
#[repr(u8)]
pub enum Error {
#[cfg_attr(feature = "std", error("Insufficient funds"))]
InsufficientFunds = 0,
#[cfg_attr(feature = "std", error("Source not found"))]
SourceNotFound = 1,
#[cfg_attr(feature = "std", error("Destination not found"))]
DestNotFound = 2,
#[cfg_attr(feature = "std", error("Invalid URef"))]
InvalidURef = 3,
#[cfg_attr(feature = "std", error("Invalid AccessRights"))]
InvalidAccessRights = 4,
#[cfg_attr(feature = "std", error("Invalid non-empty purse creation"))]
InvalidNonEmptyPurseCreation = 5,
#[cfg_attr(feature = "std", error("Storage error"))]
Storage = 6,
#[cfg_attr(feature = "std", error("Purse not found"))]
PurseNotFound = 7,
#[cfg_attr(feature = "std", error("Missing key"))]
MissingKey = 8,
#[cfg_attr(feature = "std", error("Total supply not found"))]
TotalSupplyNotFound = 9,
#[cfg_attr(feature = "std", error("Failed to record transfer"))]
RecordTransferFailure = 10,
#[cfg_attr(feature = "std", error("Invalid attempt to reduce total supply"))]
InvalidTotalSupplyReductionAttempt = 11,
#[cfg_attr(feature = "std", error("Failed to create new uref"))]
NewURef = 12,
#[cfg_attr(feature = "std", error("Failed to put key"))]
PutKey = 13,
#[cfg_attr(feature = "std", error("Failed to write local key"))]
WriteLocal = 14,
#[cfg_attr(feature = "std", error("Failed to create a CLValue"))]
CLValue = 15,
#[cfg_attr(feature = "std", error("Failed to serialize data"))]
Serialize = 16,
#[cfg_attr(feature = "std", error("Invalid target purse"))]
EqualSourceAndTarget = 17,
#[doc(hidden)]
#[cfg_attr(feature = "std", error("GasLimit"))]
GasLimit = 18,
#[cfg(test)]
#[doc(hidden)]
#[cfg_attr(feature = "std", error("Sentinel error"))]
Sentinel,
}
#[cfg(test)]
const MAX_ERROR_VALUE: u8 = Error::Sentinel as u8;
impl From<PurseError> for Error {
fn from(purse_error: PurseError) -> Error {
match purse_error {
PurseError::InvalidURef => Error::InvalidURef,
PurseError::InvalidAccessRights(_) => {
Error::InvalidAccessRights
}
}
}
}
impl CLTyped for Error {
fn cl_type() -> CLType {
CLType::U8
}
}
#[doc(hidden)]
pub struct TryFromU8ForError(());
#[doc(hidden)]
impl TryFrom<u8> for Error {
type Error = TryFromU8ForError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
d if d == Error::InsufficientFunds as u8 => Ok(Error::InsufficientFunds),
d if d == Error::SourceNotFound as u8 => Ok(Error::SourceNotFound),
d if d == Error::DestNotFound as u8 => Ok(Error::DestNotFound),
d if d == Error::InvalidURef as u8 => Ok(Error::InvalidURef),
d if d == Error::InvalidAccessRights as u8 => Ok(Error::InvalidAccessRights),
d if d == Error::InvalidNonEmptyPurseCreation as u8 => {
Ok(Error::InvalidNonEmptyPurseCreation)
}
d if d == Error::Storage as u8 => Ok(Error::Storage),
d if d == Error::PurseNotFound as u8 => Ok(Error::PurseNotFound),
d if d == Error::MissingKey as u8 => Ok(Error::MissingKey),
d if d == Error::TotalSupplyNotFound as u8 => Ok(Error::TotalSupplyNotFound),
d if d == Error::RecordTransferFailure as u8 => Ok(Error::RecordTransferFailure),
d if d == Error::InvalidTotalSupplyReductionAttempt as u8 => {
Ok(Error::InvalidTotalSupplyReductionAttempt)
}
d if d == Error::NewURef as u8 => Ok(Error::NewURef),
d if d == Error::PutKey as u8 => Ok(Error::PutKey),
d if d == Error::WriteLocal as u8 => Ok(Error::WriteLocal),
d if d == Error::CLValue as u8 => Ok(Error::CLValue),
d if d == Error::Serialize as u8 => Ok(Error::Serialize),
d if d == Error::EqualSourceAndTarget as u8 => Ok(Error::EqualSourceAndTarget),
d if d == Error::GasLimit as u8 => Ok(Error::GasLimit),
_ => Err(TryFromU8ForError(())),
}
}
}
impl ToBytes for Error {
fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
let value = *self as u8;
value.to_bytes()
}
fn serialized_length(&self) -> usize {
U8_SERIALIZED_LENGTH
}
}
impl FromBytes for Error {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
let (value, rem): (u8, _) = FromBytes::from_bytes(bytes)?;
let error: Error = value
.try_into()
.map_err(|_| bytesrepr::Error::Formatting)?;
Ok((error, rem))
}
}
#[derive(Debug, Copy, Clone)]
pub enum PurseError {
InvalidURef,
InvalidAccessRights(Option<AccessRights>),
}
impl fmt::Display for PurseError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
PurseError::InvalidURef => write!(f, "invalid uref"),
PurseError::InvalidAccessRights(maybe_access_rights) => {
write!(f, "invalid access rights: {:?}", maybe_access_rights)
}
}
}
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use super::{Error, TryFromU8ForError, MAX_ERROR_VALUE};
#[test]
fn error_round_trips() {
for i in 0..=u8::max_value() {
match Error::try_from(i) {
Ok(error) if i < MAX_ERROR_VALUE => assert_eq!(error as u8, i),
Ok(error) => panic!(
"value of variant {} ({}) exceeds MAX_ERROR_VALUE ({})",
error, i, MAX_ERROR_VALUE
),
Err(TryFromU8ForError(())) if i >= MAX_ERROR_VALUE => (),
Err(TryFromU8ForError(())) => {
panic!("missing conversion from u8 to error value: {}", i)
}
}
}
}
}