cctp_rs/protocol/
finality.rs1use serde::{Deserialize, Serialize};
13use std::fmt;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
34#[serde(rename_all = "snake_case")]
35#[repr(u32)]
36pub enum FinalityThreshold {
37 Fast = 1000,
43
44 Standard = 2000,
50}
51
52impl FinalityThreshold {
53 #[inline]
64 pub const fn as_u32(self) -> u32 {
65 self as u32
66 }
67
68 #[inline]
86 pub const fn from_u32(value: u32) -> Option<Self> {
87 match value {
88 1000 => Some(Self::Fast),
89 2000 => Some(Self::Standard),
90 _ => None,
91 }
92 }
93
94 #[inline]
105 pub const fn name(self) -> &'static str {
106 match self {
107 Self::Fast => "Fast Transfer",
108 Self::Standard => "Standard Transfer",
109 }
110 }
111
112 #[inline]
123 pub const fn is_fast(self) -> bool {
124 matches!(self, Self::Fast)
125 }
126
127 #[inline]
138 pub const fn is_standard(self) -> bool {
139 matches!(self, Self::Standard)
140 }
141}
142
143impl Default for FinalityThreshold {
144 fn default() -> Self {
148 Self::Standard
149 }
150}
151
152impl From<FinalityThreshold> for u32 {
153 #[inline]
154 fn from(threshold: FinalityThreshold) -> Self {
155 threshold.as_u32()
156 }
157}
158
159impl TryFrom<u32> for FinalityThreshold {
160 type Error = InvalidFinalityThreshold;
161
162 #[inline]
163 fn try_from(value: u32) -> Result<Self, Self::Error> {
164 Self::from_u32(value).ok_or(InvalidFinalityThreshold(value))
165 }
166}
167
168impl fmt::Display for FinalityThreshold {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 write!(f, "{} ({})", self.name(), self.as_u32())
171 }
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
176pub struct InvalidFinalityThreshold(pub u32);
177
178impl fmt::Display for InvalidFinalityThreshold {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 write!(
181 f,
182 "invalid finality threshold: {} (expected 1000 or 2000)",
183 self.0
184 )
185 }
186}
187
188impl std::error::Error for InvalidFinalityThreshold {}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 fn test_threshold_values() {
196 assert_eq!(FinalityThreshold::Fast.as_u32(), 1000);
197 assert_eq!(FinalityThreshold::Standard.as_u32(), 2000);
198 }
199
200 #[test]
201 fn test_from_u32_valid() {
202 assert_eq!(
203 FinalityThreshold::from_u32(1000),
204 Some(FinalityThreshold::Fast)
205 );
206 assert_eq!(
207 FinalityThreshold::from_u32(2000),
208 Some(FinalityThreshold::Standard)
209 );
210 }
211
212 #[test]
213 fn test_from_u32_invalid() {
214 assert_eq!(FinalityThreshold::from_u32(0), None);
215 assert_eq!(FinalityThreshold::from_u32(500), None);
216 assert_eq!(FinalityThreshold::from_u32(1500), None);
217 assert_eq!(FinalityThreshold::from_u32(3000), None);
218 }
219
220 #[test]
221 fn test_try_from_valid() {
222 assert_eq!(
223 FinalityThreshold::try_from(1000).unwrap(),
224 FinalityThreshold::Fast
225 );
226 assert_eq!(
227 FinalityThreshold::try_from(2000).unwrap(),
228 FinalityThreshold::Standard
229 );
230 }
231
232 #[test]
233 fn test_try_from_invalid() {
234 assert!(FinalityThreshold::try_from(1500).is_err());
235 let err = FinalityThreshold::try_from(1500).unwrap_err();
236 assert_eq!(err, InvalidFinalityThreshold(1500));
237 }
238
239 #[test]
240 fn test_display() {
241 assert_eq!(
242 format!("{}", FinalityThreshold::Fast),
243 "Fast Transfer (1000)"
244 );
245 assert_eq!(
246 format!("{}", FinalityThreshold::Standard),
247 "Standard Transfer (2000)"
248 );
249 }
250
251 #[test]
252 fn test_name() {
253 assert_eq!(FinalityThreshold::Fast.name(), "Fast Transfer");
254 assert_eq!(FinalityThreshold::Standard.name(), "Standard Transfer");
255 }
256
257 #[test]
258 fn test_is_fast() {
259 assert!(FinalityThreshold::Fast.is_fast());
260 assert!(!FinalityThreshold::Standard.is_fast());
261 }
262
263 #[test]
264 fn test_is_standard() {
265 assert!(FinalityThreshold::Standard.is_standard());
266 assert!(!FinalityThreshold::Fast.is_standard());
267 }
268
269 #[test]
270 fn test_default() {
271 assert_eq!(FinalityThreshold::default(), FinalityThreshold::Standard);
272 }
273
274 #[test]
275 fn test_conversion_roundtrip() {
276 for threshold in [FinalityThreshold::Fast, FinalityThreshold::Standard] {
277 let value: u32 = threshold.into();
278 let parsed = FinalityThreshold::try_from(value).unwrap();
279 assert_eq!(threshold, parsed);
280 }
281 }
282}