use std::error::Error;
use std::fmt;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum ExecutionFailureCode {
ArithmeticFault = 1,
ResourceLimit = 2,
UniqueConflict = 3,
}
impl ExecutionFailureCode {
pub const ALL: [Self; 3] = [
Self::ArithmeticFault,
Self::ResourceLimit,
Self::UniqueConflict,
];
#[must_use]
pub const fn code(self) -> u32 {
self as u32
}
}
impl From<ExecutionFailureCode> for u32 {
fn from(value: ExecutionFailureCode) -> Self {
value.code()
}
}
impl TryFrom<u32> for ExecutionFailureCode {
type Error = ExecutionFailureCodeError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::ArithmeticFault),
2 => Ok(Self::ResourceLimit),
3 => Ok(Self::UniqueConflict),
_ => Err(ExecutionFailureCodeError { value }),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ExecutionFailureCodeError {
value: u32,
}
impl ExecutionFailureCodeError {
#[must_use]
pub const fn value(self) -> u32 {
self.value
}
}
impl fmt::Display for ExecutionFailureCodeError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("execution failure code is unspecified or unknown")
}
}
impl Error for ExecutionFailureCodeError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn v1_codes_round_trip_and_zero_is_not_representable() {
for code in ExecutionFailureCode::ALL {
assert_eq!(ExecutionFailureCode::try_from(code.code()), Ok(code));
}
assert_eq!(
ExecutionFailureCode::try_from(0)
.expect_err("zero is the wire unspecified value")
.value(),
0
);
assert_eq!(
ExecutionFailureCode::try_from(4)
.expect_err("unknown values fail closed")
.value(),
4
);
assert_eq!(
ExecutionFailureCode::try_from(u32::MAX)
.expect_err("unknown values fail closed")
.value(),
u32::MAX
);
}
}