1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum Code {
15 Ok = 0x00,
16 UnknownNextPeer = 0x01,
17 TemporaryRelayFailure = 0x02,
18 RelayDisabled = 0x03,
19 NodeNotFoundAtTargetRelay = 0x04,
20 TargetRealmRefused = 0x05,
21 LoopDetected = 0x06,
22 ExpiryTooSoon = 0x07,
23 UpstreamCongestion = 0x08,
24 InvalidPathHeader = 0x09,
25 CryptoPuzzleInvalid = 0x0A,
26 RealmNotAuthoritativeHere = 0x0B,
27 Tombstoned = 0x0C,
28 PayloadTooLarge = 0x0D,
29 SignatureInvalid = 0x0E,
30 UnknownError = 0x0F,
31 Unauthorized = 0x10,
34}
35
36impl Code {
41 pub fn as_u8(self) -> u8 {
42 self as u8
43 }
44
45 pub fn name(self) -> &'static str {
46 match self {
47 Code::Ok => "ok",
48 Code::UnknownNextPeer => "unknown_next_peer",
49 Code::TemporaryRelayFailure => "temporary_relay_failure",
50 Code::RelayDisabled => "relay_disabled",
51 Code::NodeNotFoundAtTargetRelay => "node_not_found_at_target_relay",
52 Code::TargetRealmRefused => "target_realm_refused",
53 Code::LoopDetected => "loop_detected",
54 Code::ExpiryTooSoon => "expiry_too_soon",
55 Code::UpstreamCongestion => "upstream_congestion",
56 Code::InvalidPathHeader => "invalid_path_header",
57 Code::CryptoPuzzleInvalid => "crypto_puzzle_invalid",
58 Code::RealmNotAuthoritativeHere => "realm_not_authoritative_here",
59 Code::Tombstoned => "tombstoned",
60 Code::PayloadTooLarge => "payload_too_large",
61 Code::SignatureInvalid => "signature_invalid",
62 Code::UnknownError => "unknown_error",
63 Code::Unauthorized => "unauthorized",
64 }
65 }
66
67 pub fn is_retryable(self) -> bool {
68 !matches!(
69 self,
70 Code::Ok
71 | Code::TargetRealmRefused
72 | Code::Tombstoned
73 | Code::PayloadTooLarge
74 | Code::Unauthorized
75 | Code::CryptoPuzzleInvalid
76 | Code::SignatureInvalid
77 )
78 }
79
80 pub fn from_u8(code: u8) -> Option<Code> {
81 Some(match code {
82 0x00 => Code::Ok,
83 0x01 => Code::UnknownNextPeer,
84 0x02 => Code::TemporaryRelayFailure,
85 0x03 => Code::RelayDisabled,
86 0x04 => Code::NodeNotFoundAtTargetRelay,
87 0x05 => Code::TargetRealmRefused,
88 0x06 => Code::LoopDetected,
89 0x07 => Code::ExpiryTooSoon,
90 0x08 => Code::UpstreamCongestion,
91 0x09 => Code::InvalidPathHeader,
92 0x0A => Code::CryptoPuzzleInvalid,
93 0x0B => Code::RealmNotAuthoritativeHere,
94 0x0C => Code::Tombstoned,
95 0x0D => Code::PayloadTooLarge,
96 0x0E => Code::SignatureInvalid,
97 0x0F => Code::UnknownError,
98 0x10 => Code::Unauthorized,
99 _ => return None,
100 })
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn round_trips_every_defined_code() {
110 for code in 0x00u8..=0x10 {
111 let parsed =
112 Code::from_u8(code).unwrap_or_else(|| panic!("code {code:#x} should be defined"));
113 assert_eq!(parsed.as_u8(), code);
114 }
115 }
116
117 #[test]
118 fn unknown_code_is_none() {
119 assert_eq!(Code::from_u8(0x11), None);
120 assert_eq!(Code::from_u8(0xFF), None);
121 }
122
123 #[test]
124 fn non_retryable_codes_match_the_reference_table() {
125 assert!(!Code::Ok.is_retryable());
127 assert!(!Code::TargetRealmRefused.is_retryable());
128 assert!(!Code::Tombstoned.is_retryable());
129 assert!(!Code::PayloadTooLarge.is_retryable());
130 assert!(!Code::Unauthorized.is_retryable());
131 assert!(!Code::CryptoPuzzleInvalid.is_retryable());
132 assert!(!Code::SignatureInvalid.is_retryable());
133 }
134
135 #[test]
136 fn retryable_codes_match_the_reference_table() {
137 assert!(Code::UnknownNextPeer.is_retryable());
138 assert!(Code::TemporaryRelayFailure.is_retryable());
139 assert!(Code::RelayDisabled.is_retryable());
140 assert!(Code::NodeNotFoundAtTargetRelay.is_retryable());
141 assert!(Code::LoopDetected.is_retryable());
142 assert!(Code::ExpiryTooSoon.is_retryable());
143 assert!(Code::UpstreamCongestion.is_retryable());
144 assert!(Code::InvalidPathHeader.is_retryable());
145 assert!(Code::RealmNotAuthoritativeHere.is_retryable());
146 assert!(Code::UnknownError.is_retryable());
147 }
148
149 #[test]
150 fn names_match_the_reference_spelling() {
151 assert_eq!(Code::UnknownNextPeer.name(), "unknown_next_peer");
152 assert_eq!(Code::Unauthorized.name(), "unauthorized");
153 }
154}