ic_response_codes/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
#![doc = include_str!("../README.md")]
use std::error::Error;
/// Classifies why an API request or inter-canister call in the IC is rejected.
///
/// # Note
///
/// Zero (0) is not a valid reject code.
/// Converting 0 into this enum will return an error.
///
/// See [Reject codes](https://internetcomputer.org/docs/current/references/ic-interface-spec/#reject-codes) for more details.
#[repr(u32)]
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum RejectCode {
/// Fatal system error, retry unlikely to be useful.
SysFatal = 1,
/// Transient system error, retry might be possible.
SysTransient = 2,
/// Invalid destination (e.g. canister/account does not exist).
DestinationInvalid = 3,
/// Explicit reject by the canister.
CanisterReject = 4,
/// Canister error (e.g., trap, no response).
CanisterError = 5,
/// Response unknown; system stopped waiting for it (e.g., timed out, or system under high load).
SysUnknown = 6,
/// Unrecognized reject code.
///
/// # Note
///
/// This variant is not part of the IC interface spec, and is used to represent
/// reject codes that are not recognized by the library.
///
/// This variant is needed just in case the IC introduces new reject codes in the future.
/// If that happens, a Canister using existing library versions will still be able to convert
/// the new reject codes to this variant without panicking.
Unrecognized(u32),
}
/// Error type for [`RejectCode`] conversion.
///
/// The only case where this error can occur is when trying to convert a 0 to a [`RejectCode`].
#[derive(Clone, Copy, Debug)]
pub struct ZeroIsInvalidRejectCode;
impl std::fmt::Display for ZeroIsInvalidRejectCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "zero is invalid reject code")
}
}
impl Error for ZeroIsInvalidRejectCode {}
impl TryFrom<u32> for RejectCode {
type Error = ZeroIsInvalidRejectCode;
fn try_from(code: u32) -> Result<Self, Self::Error> {
match code {
0 => Err(ZeroIsInvalidRejectCode),
1 => Ok(RejectCode::SysFatal),
2 => Ok(RejectCode::SysTransient),
3 => Ok(RejectCode::DestinationInvalid),
4 => Ok(RejectCode::CanisterReject),
5 => Ok(RejectCode::CanisterError),
6 => Ok(RejectCode::SysUnknown),
_ => Ok(RejectCode::Unrecognized(code)),
}
}
}
impl From<RejectCode> for u32 {
fn from(code: RejectCode) -> u32 {
match code {
RejectCode::SysFatal => 1,
RejectCode::SysTransient => 2,
RejectCode::DestinationInvalid => 3,
RejectCode::CanisterReject => 4,
RejectCode::CanisterError => 5,
RejectCode::SysUnknown => 6,
RejectCode::Unrecognized(code) => code,
}
}
}
impl PartialEq<u32> for RejectCode {
fn eq(&self, other: &u32) -> bool {
let self_as_u32: u32 = (*self).into();
self_as_u32 == *other
}
}