interledger_packet/
error.rs

1use std::fmt;
2use std::str;
3
4#[derive(Clone, Copy, Eq, PartialEq)]
5pub struct ErrorCode([u8; 3]);
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub enum ErrorClass {
9    Final,
10    Temporary,
11    Relative,
12    Unknown,
13}
14
15impl ErrorCode {
16    #[inline]
17    pub const fn new(bytes: [u8; 3]) -> Self {
18        ErrorCode(bytes)
19    }
20
21    #[inline]
22    pub fn class(self) -> ErrorClass {
23        match self.0[0] {
24            b'F' => ErrorClass::Final,
25            b'T' => ErrorClass::Temporary,
26            b'R' => ErrorClass::Relative,
27            _ => ErrorClass::Unknown,
28        }
29    }
30
31    // Error codes from: <https://github.com/interledger/rfcs/blob/master/0027-interledger-protocol-4/0027-interledger-protocol-4.md#error-codes>
32
33    // Final errors:
34    pub const F00_BAD_REQUEST: Self = ErrorCode(*b"F00");
35    pub const F01_INVALID_PACKET: Self = ErrorCode(*b"F01");
36    pub const F02_UNREACHABLE: Self = ErrorCode(*b"F02");
37    pub const F03_INVALID_AMOUNT: Self = ErrorCode(*b"F03");
38    pub const F04_INSUFFICIENT_DESTINATION_AMOUNT: Self = ErrorCode(*b"F04");
39    pub const F05_WRONG_CONDITION: Self = ErrorCode(*b"F05");
40    pub const F06_UNEXPECTED_PAYMENT: Self = ErrorCode(*b"F06");
41    pub const F07_CANNOT_RECEIVE: Self = ErrorCode(*b"F07");
42    pub const F08_AMOUNT_TOO_LARGE: Self = ErrorCode(*b"F08");
43    pub const F09_INVALID_PEER_RESPONSE: Self = ErrorCode(*b"F09");
44    pub const F99_APPLICATION_ERROR: Self = ErrorCode(*b"F99");
45
46    // Temporary errors:
47    pub const T00_INTERNAL_ERROR: Self = ErrorCode(*b"T00");
48    pub const T01_PEER_UNREACHABLE: Self = ErrorCode(*b"T01");
49    pub const T02_PEER_BUSY: Self = ErrorCode(*b"T02");
50    pub const T03_CONNECTOR_BUSY: Self = ErrorCode(*b"T03");
51    pub const T04_INSUFFICIENT_LIQUIDITY: Self = ErrorCode(*b"T04");
52    pub const T05_RATE_LIMITED: Self = ErrorCode(*b"T05");
53    pub const T99_APPLICATION_ERROR: Self = ErrorCode(*b"T99");
54
55    // Relative errors:
56    pub const R00_TRANSFER_TIMED_OUT: Self = ErrorCode(*b"R00");
57    pub const R01_INSUFFICIENT_SOURCE_AMOUNT: Self = ErrorCode(*b"R01");
58    pub const R02_INSUFFICIENT_TIMEOUT: Self = ErrorCode(*b"R02");
59    pub const R99_APPLICATION_ERROR: Self = ErrorCode(*b"R99");
60}
61
62impl From<ErrorCode> for [u8; 3] {
63    fn from(error_code: ErrorCode) -> Self {
64        error_code.0
65    }
66}
67
68impl fmt::Debug for ErrorCode {
69    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
70        formatter
71            .debug_tuple("ErrorCode")
72            .field(&str::from_utf8(&self.0[..]).map_err(|_| fmt::Error)?)
73            .finish()
74    }
75}
76
77impl fmt::Display for ErrorCode {
78    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
79        let as_str = str::from_utf8(&self.0[..]).map_err(|_| fmt::Error)?;
80        formatter.write_str(as_str)
81    }
82}
83
84#[cfg(test)]
85mod test_error_code {
86    use super::*;
87
88    #[test]
89    fn test_class() {
90        assert_eq!(ErrorCode::F00_BAD_REQUEST.class(), ErrorClass::Final);
91        assert_eq!(ErrorCode::T00_INTERNAL_ERROR.class(), ErrorClass::Temporary);
92        assert_eq!(
93            ErrorCode::R00_TRANSFER_TIMED_OUT.class(),
94            ErrorClass::Relative
95        );
96        assert_eq!(ErrorCode::new(*b"???").class(), ErrorClass::Unknown);
97    }
98
99    #[test]
100    fn test_debug_printing() {
101        assert_eq!(
102            format!("{:?}", ErrorCode::F00_BAD_REQUEST),
103            String::from("ErrorCode(\"F00\")")
104        );
105    }
106
107    #[test]
108    fn test_final_error_values() {
109        assert_eq!(
110            format!("{}", ErrorCode::F00_BAD_REQUEST),
111            String::from("F00")
112        );
113        assert_eq!(
114            format!("{}", ErrorCode::F01_INVALID_PACKET),
115            String::from("F01")
116        );
117        assert_eq!(
118            format!("{}", ErrorCode::F02_UNREACHABLE),
119            String::from("F02")
120        );
121        assert_eq!(
122            format!("{}", ErrorCode::F03_INVALID_AMOUNT),
123            String::from("F03")
124        );
125        assert_eq!(
126            format!("{}", ErrorCode::F04_INSUFFICIENT_DESTINATION_AMOUNT),
127            String::from("F04")
128        );
129        assert_eq!(
130            format!("{}", ErrorCode::F05_WRONG_CONDITION),
131            String::from("F05")
132        );
133        assert_eq!(
134            format!("{}", ErrorCode::F06_UNEXPECTED_PAYMENT),
135            String::from("F06")
136        );
137        assert_eq!(
138            format!("{}", ErrorCode::F07_CANNOT_RECEIVE),
139            String::from("F07")
140        );
141        assert_eq!(
142            format!("{}", ErrorCode::F08_AMOUNT_TOO_LARGE),
143            String::from("F08")
144        );
145        assert_eq!(
146            format!("{}", ErrorCode::F09_INVALID_PEER_RESPONSE),
147            String::from("F09")
148        );
149        assert_eq!(
150            format!("{}", ErrorCode::F99_APPLICATION_ERROR),
151            String::from("F99")
152        );
153    }
154
155    #[test]
156    fn test_temporary_error_values() {
157        assert_eq!(
158            format!("{}", ErrorCode::T00_INTERNAL_ERROR),
159            String::from("T00")
160        );
161        assert_eq!(
162            format!("{}", ErrorCode::T01_PEER_UNREACHABLE),
163            String::from("T01")
164        );
165        assert_eq!(format!("{}", ErrorCode::T02_PEER_BUSY), String::from("T02"));
166        assert_eq!(
167            format!("{}", ErrorCode::T03_CONNECTOR_BUSY),
168            String::from("T03")
169        );
170        assert_eq!(
171            format!("{}", ErrorCode::T04_INSUFFICIENT_LIQUIDITY),
172            String::from("T04")
173        );
174        assert_eq!(
175            format!("{}", ErrorCode::T05_RATE_LIMITED),
176            String::from("T05")
177        );
178        assert_eq!(
179            format!("{}", ErrorCode::T99_APPLICATION_ERROR),
180            String::from("T99")
181        );
182    }
183
184    #[test]
185    fn test_relative_error_values() {
186        assert_eq!(
187            format!("{}", ErrorCode::R00_TRANSFER_TIMED_OUT),
188            String::from("R00")
189        );
190        assert_eq!(
191            format!("{}", ErrorCode::R01_INSUFFICIENT_SOURCE_AMOUNT),
192            String::from("R01")
193        );
194        assert_eq!(
195            format!("{}", ErrorCode::R02_INSUFFICIENT_TIMEOUT),
196            String::from("R02")
197        );
198        assert_eq!(
199            format!("{}", ErrorCode::R99_APPLICATION_ERROR),
200            String::from("R99")
201        );
202    }
203}