1use core::{fmt, ops};
15
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19#[cfg(doc)]
20use crate::locktime;
21use crate::locktime::{absolute, relative};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31pub struct BlockHeight(pub u32);
33
34impl BlockHeight {
35 pub const ZERO: Self = BlockHeight(0);
37
38 pub const MIN: Self = Self::ZERO;
40
41 pub const MAX: Self = BlockHeight(u32::MAX);
43
44 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
47
48 pub const fn to_u32(&self) -> u32 { self.0 }
51}
52
53impl fmt::Display for BlockHeight {
54 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
55}
56
57crate::impl_parse_str_from_int_infallible!(BlockHeight, u32, from);
58
59impl From<u32> for BlockHeight {
60 fn from(inner: u32) -> Self { Self::from_u32(inner) }
61}
62
63impl From<BlockHeight> for u32 {
64 fn from(height: BlockHeight) -> Self { height.to_u32() }
65}
66
67impl From<absolute::Height> for BlockHeight {
68 fn from(h: absolute::Height) -> Self { Self::from_u32(h.to_consensus_u32()) }
74}
75
76impl TryFrom<BlockHeight> for absolute::Height {
77 type Error = absolute::ConversionError;
78
79 fn try_from(h: BlockHeight) -> Result<Self, Self::Error> {
85 absolute::Height::from_consensus(h.to_u32())
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
97#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
98pub struct BlockInterval(pub u32);
100
101impl BlockInterval {
102 pub const ZERO: Self = BlockInterval(0);
104
105 pub const MIN: Self = Self::ZERO;
107
108 pub const MAX: Self = BlockInterval(u32::MAX);
110
111 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
114
115 pub const fn to_u32(&self) -> u32 { self.0 }
118}
119
120impl fmt::Display for BlockInterval {
121 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
122}
123
124crate::impl_parse_str_from_int_infallible!(BlockInterval, u32, from);
125
126impl From<u32> for BlockInterval {
127 fn from(inner: u32) -> Self { Self::from_u32(inner) }
128}
129
130impl From<BlockInterval> for u32 {
131 fn from(height: BlockInterval) -> Self { height.to_u32() }
132}
133
134impl From<relative::Height> for BlockInterval {
135 fn from(h: relative::Height) -> Self { Self::from_u32(h.value().into()) }
140}
141
142impl TryFrom<BlockInterval> for relative::Height {
143 type Error = TooBigForRelativeBlockHeightError;
144
145 fn try_from(h: BlockInterval) -> Result<Self, Self::Error> {
150 let h = h.to_u32();
151 if h > u16::MAX as u32 {
152 return Err(TooBigForRelativeBlockHeightError(h));
153 }
154 Ok(relative::Height::from(h as u16)) }
156}
157
158#[derive(Debug, Clone, PartialEq, Eq)]
160pub struct TooBigForRelativeBlockHeightError(u32);
161
162impl fmt::Display for TooBigForRelativeBlockHeightError {
163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164 write!(
165 f,
166 "block interval is too big to be used as a relative lock time: {} (max: {})",
167 self.0,
168 relative::Height::MAX
169 )
170 }
171}
172
173#[cfg(feature = "std")]
174impl std::error::Error for TooBigForRelativeBlockHeightError {}
175
176impl ops::Sub<BlockHeight> for BlockHeight {
178 type Output = BlockInterval;
179
180 fn sub(self, rhs: BlockHeight) -> Self::Output {
181 let interval = self.to_u32() - rhs.to_u32();
182 BlockInterval::from_u32(interval)
183 }
184}
185
186impl ops::Add<BlockInterval> for BlockHeight {
188 type Output = BlockHeight;
189
190 fn add(self, rhs: BlockInterval) -> Self::Output {
191 let height = self.to_u32() + rhs.to_u32();
192 BlockHeight::from_u32(height)
193 }
194}
195
196impl ops::Sub<BlockInterval> for BlockHeight {
198 type Output = BlockHeight;
199
200 fn sub(self, rhs: BlockInterval) -> Self::Output {
201 let height = self.to_u32() - rhs.to_u32();
202 BlockHeight::from_u32(height)
203 }
204}
205
206impl ops::Add<BlockInterval> for BlockInterval {
208 type Output = BlockInterval;
209
210 fn add(self, rhs: BlockInterval) -> Self::Output {
211 let height = self.to_u32() + rhs.to_u32();
212 BlockInterval::from_u32(height)
213 }
214}
215
216impl ops::AddAssign<BlockInterval> for BlockInterval {
217 fn add_assign(&mut self, rhs: BlockInterval) { self.0 = self.to_u32() + rhs.to_u32(); }
218}
219
220impl ops::Sub<BlockInterval> for BlockInterval {
222 type Output = BlockInterval;
223
224 fn sub(self, rhs: BlockInterval) -> Self::Output {
225 let height = self.to_u32() - rhs.to_u32();
226 BlockInterval::from_u32(height)
227 }
228}
229
230impl ops::SubAssign<BlockInterval> for BlockInterval {
231 fn sub_assign(&mut self, rhs: BlockInterval) { self.0 = self.to_u32() - rhs.to_u32(); }
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
237
238 #[test]
240 fn all_available_ops() {
241 assert!(BlockHeight(100) - BlockHeight(99) == BlockInterval(1));
243
244 assert!(BlockHeight(100) + BlockInterval(1) == BlockHeight(101));
246
247 assert!(BlockHeight(100) - BlockInterval(1) == BlockHeight(99));
249
250 assert!(BlockInterval(1) + BlockInterval(2) == BlockInterval(3));
252
253 assert!(BlockInterval(3) - BlockInterval(2) == BlockInterval(1));
255
256 let mut int = BlockInterval(1);
258 int += BlockInterval(2);
259 assert_eq!(int, BlockInterval(3));
260
261 let mut int = BlockInterval(3);
263 int -= BlockInterval(2);
264 assert_eq!(int, BlockInterval(1));
265 }
266}