Skip to main content

riffdb_types/
execution.rs

1//! Closed deterministic execution-failure vocabulary.
2
3use std::error::Error;
4use std::fmt;
5
6/// A dependency-validated deterministic command execution failure.
7///
8/// Zero is reserved for wire-level unspecified values and is never represented
9/// by this type.
10#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
11#[repr(u32)]
12pub enum ExecutionFailureCode {
13    /// Checked arithmetic could not produce a valid contract value.
14    ArithmeticFault = 1,
15    /// A fixed deterministic execution budget was exhausted.
16    ResourceLimit = 2,
17    /// Another entity already owns one exact declared unique value.
18    UniqueConflict = 3,
19}
20
21impl ExecutionFailureCode {
22    /// Every valid v1 execution-failure code.
23    pub const ALL: [Self; 3] = [
24        Self::ArithmeticFault,
25        Self::ResourceLimit,
26        Self::UniqueConflict,
27    ];
28
29    /// Returns the stable v1 numeric code.
30    #[must_use]
31    pub const fn code(self) -> u32 {
32        self as u32
33    }
34}
35
36impl From<ExecutionFailureCode> for u32 {
37    fn from(value: ExecutionFailureCode) -> Self {
38        value.code()
39    }
40}
41
42impl TryFrom<u32> for ExecutionFailureCode {
43    type Error = ExecutionFailureCodeError;
44
45    fn try_from(value: u32) -> Result<Self, Self::Error> {
46        match value {
47            1 => Ok(Self::ArithmeticFault),
48            2 => Ok(Self::ResourceLimit),
49            3 => Ok(Self::UniqueConflict),
50            _ => Err(ExecutionFailureCodeError { value }),
51        }
52    }
53}
54
55/// A safe failure to decode a closed execution-failure code.
56#[derive(Clone, Copy, Debug, Eq, PartialEq)]
57pub struct ExecutionFailureCodeError {
58    value: u32,
59}
60
61impl ExecutionFailureCodeError {
62    /// Returns the rejected numeric value.
63    #[must_use]
64    pub const fn value(self) -> u32 {
65        self.value
66    }
67}
68
69impl fmt::Display for ExecutionFailureCodeError {
70    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
71        formatter.write_str("execution failure code is unspecified or unknown")
72    }
73}
74
75impl Error for ExecutionFailureCodeError {}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn v1_codes_round_trip_and_zero_is_not_representable() {
83        for code in ExecutionFailureCode::ALL {
84            assert_eq!(ExecutionFailureCode::try_from(code.code()), Ok(code));
85        }
86
87        assert_eq!(
88            ExecutionFailureCode::try_from(0)
89                .expect_err("zero is the wire unspecified value")
90                .value(),
91            0
92        );
93        assert_eq!(
94            ExecutionFailureCode::try_from(4)
95                .expect_err("unknown values fail closed")
96                .value(),
97            4
98        );
99        assert_eq!(
100            ExecutionFailureCode::try_from(u32::MAX)
101                .expect_err("unknown values fail closed")
102                .value(),
103            u32::MAX
104        );
105    }
106}