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