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