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