iq_cometbft/block/
round.rs

1use core::{
2    convert::{TryFrom, TryInto},
3    fmt::{self, Debug, Display},
4    str::FromStr,
5};
6
7use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
8
9use crate::{error::Error, prelude::*};
10
11/// Block round for a particular chain
12#[derive(Copy, Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
13pub struct Round(u32);
14
15impl TryFrom<i32> for Round {
16    type Error = Error;
17
18    fn try_from(value: i32) -> Result<Self, Self::Error> {
19        Ok(Round(value.try_into().map_err(Error::negative_round)?))
20    }
21}
22
23impl From<Round> for i32 {
24    fn from(value: Round) -> Self {
25        value.value() as i32 // does not overflow. The value is <= i32::MAX
26    }
27}
28
29impl TryFrom<u32> for Round {
30    type Error = Error;
31
32    fn try_from(value: u32) -> Result<Self, Self::Error> {
33        let _val: i32 = value.try_into().map_err(Error::integer_overflow)?;
34
35        Ok(Round(value))
36    }
37}
38
39impl From<Round> for u32 {
40    fn from(value: Round) -> Self {
41        value.value()
42    }
43}
44
45impl From<u16> for Round {
46    fn from(value: u16) -> Self {
47        Round(value as u32)
48    }
49}
50
51impl From<u8> for Round {
52    fn from(value: u8) -> Self {
53        Round(value as u32)
54    }
55}
56
57impl Round {
58    /// Get inner integer value. Alternative to `.0` or `.into()`
59    pub fn value(&self) -> u32 {
60        self.0
61    }
62
63    /// Increment the block round by 1
64    pub fn increment(self) -> Self {
65        Round::try_from(self.0.checked_add(1).expect("round overflow")).unwrap()
66    }
67}
68
69impl Debug for Round {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        write!(f, "block::Round({})", self.0)
72    }
73}
74
75impl Display for Round {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        write!(f, "{}", self.0)
78    }
79}
80
81impl FromStr for Round {
82    type Err = Error;
83
84    fn from_str(s: &str) -> Result<Self, Error> {
85        Round::try_from(
86            s.parse::<u32>()
87                .map_err(|e| Error::parse_int(s.to_string(), e))?,
88        )
89    }
90}
91
92impl<'de> Deserialize<'de> for Round {
93    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
94        Self::from_str(&String::deserialize(deserializer)?)
95            .map_err(|e| D::Error::custom(format!("{e}")))
96    }
97}
98
99impl Serialize for Round {
100    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
101        u32::from(*self).to_string().serialize(serializer)
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn increment_by_one() {
111        assert_eq!(Round::default().increment().value(), 1);
112    }
113
114    #[test]
115    fn avoid_try_unwrap_dance() {
116        assert_eq!(
117            Round::try_from(2_u32).unwrap().value(),
118            Round::from(2_u16).value()
119        );
120    }
121}