iq_cometbft/block/
height.rs1use core::{
2 convert::{TryFrom, TryInto},
3 fmt::{self, Debug, Display},
4 str::FromStr,
5};
6
7use cometbft_proto::Protobuf;
8use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
9
10use crate::{error::Error, prelude::*};
11
12#[derive(Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
17pub struct Height(u64);
18
19impl Protobuf<i64> for Height {}
20
21impl TryFrom<i64> for Height {
22 type Error = Error;
23
24 fn try_from(value: i64) -> Result<Self, Self::Error> {
25 Ok(Height(value.try_into().map_err(Error::negative_height)?))
26 }
27}
28
29impl From<Height> for i64 {
30 fn from(value: Height) -> Self {
31 value.value() as i64 }
33}
34
35impl TryFrom<u64> for Height {
36 type Error = Error;
37
38 fn try_from(value: u64) -> Result<Self, Self::Error> {
39 let _ival: i64 = value.try_into().map_err(Error::integer_overflow)?;
41
42 Ok(Height(value))
43 }
44}
45
46impl From<Height> for u64 {
47 fn from(value: Height) -> Self {
48 value.value()
49 }
50}
51
52impl From<u32> for Height {
53 fn from(value: u32) -> Self {
54 Height(value as u64)
55 }
56}
57
58impl From<u16> for Height {
59 fn from(value: u16) -> Self {
60 Height(value as u64)
61 }
62}
63
64impl From<u8> for Height {
65 fn from(value: u8) -> Self {
66 Height(value as u64)
67 }
68}
69
70impl Height {
71 pub fn value(&self) -> u64 {
73 self.0
74 }
75
76 pub fn increment(self) -> Self {
78 Height::try_from(self.0.checked_add(1).expect("height overflow")).unwrap()
79 }
80}
81
82impl Debug for Height {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 write!(f, "block::Height({})", self.0)
85 }
86}
87
88impl Default for Height {
89 fn default() -> Self {
90 Height(1)
91 }
92}
93
94impl Display for Height {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 write!(f, "{}", self.0)
97 }
98}
99
100impl FromStr for Height {
101 type Err = Error;
102
103 fn from_str(s: &str) -> Result<Self, Error> {
104 Height::try_from(
105 s.parse::<u64>()
106 .map_err(|e| Error::parse_int(s.to_string(), e))?,
107 )
108 }
109}
110
111impl<'de> Deserialize<'de> for Height {
112 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
113 Self::from_str(&String::deserialize(deserializer)?)
114 .map_err(|e| D::Error::custom(format!("{e}")))
115 }
116}
117
118impl Serialize for Height {
119 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
120 i64::from(*self).to_string().serialize(serializer)
121 }
122}
123
124pub trait ParseHeight {
126 fn parse_block_height(&self) -> Result<Height, Error>;
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn increment_by_one() {
136 assert_eq!(Height::default().increment().value(), 2);
137 }
138
139 #[test]
140 fn avoid_try_unwrap_dance() {
141 assert_eq!(
142 Height::try_from(2_u64).unwrap().value(),
143 Height::from(2_u32).value()
144 );
145 }
146}