use std::{ fmt::Debug, ops::{Add, AddAssign, Rem}, }; use allocative::Allocative; use bitcoincore_rpc::{Client, RpcApi}; use byteview::ByteView; use derive_deref::Deref; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, PrintableIndex, Stamp, StoredCompressed}; use zerocopy::{FromBytes, IntoBytes}; use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout}; use crate::{BLOCKS_PER_DIFF_EPOCHS, BLOCKS_PER_HALVING, copy_first_4bytes}; use super::StoredU64; #[derive( Debug, Clone, Copy, PartialEq, Deref, Eq, PartialOrd, Ord, Default, Serialize, Deserialize, FromBytes, Immutable, IntoBytes, KnownLayout, StoredCompressed, Allocative, )] pub struct Height(u32); impl Height { pub const ZERO: Self = Self(0); pub const MAX: Self = Self(u32::MAX); pub const fn new(height: u32) -> Self { Self(height) } pub fn write(&self, path: &std::path::Path) -> Result<(), std::io::Error> { std::fs::write(path, self.as_bytes()) } pub fn increment(&mut self) { self.0 += 1; } pub fn incremented(self) -> Self { Self(self.0 + 1) } pub fn decrement(&mut self) { *self = self.decremented().unwrap(); } pub fn decremented(self) -> Option { self.checked_sub(1_u32) } pub fn is_zero(self) -> bool { self == Self::ZERO } pub fn is_not_zero(self) -> bool { self != Self::ZERO } pub fn left_before_next_diff_adj(self) -> u32 { BLOCKS_PER_DIFF_EPOCHS - (*self % BLOCKS_PER_DIFF_EPOCHS) } pub fn left_before_next_halving(self) -> u32 { BLOCKS_PER_HALVING - (*self % BLOCKS_PER_HALVING) } } impl PartialEq for Height { fn eq(&self, other: &u64) -> bool { self.0 == *other as u32 } } impl Add for Height { type Output = Self; fn add(self, rhs: Height) -> Self::Output { Self::from(self.0 + rhs.0) } } impl Add for Height { type Output = Self; fn add(self, rhs: u32) -> Self::Output { Self::from(self.0 + rhs) } } impl Add for Height { type Output = Self; fn add(self, rhs: u64) -> Self::Output { Self::from(self.0 + rhs as u32) } } impl Add for Height { type Output = Self; fn add(self, rhs: usize) -> Self::Output { Self::from(self.0 + rhs as u32) } } impl CheckedSub for Height { fn checked_sub(self, rhs: Self) -> Option { self.0.checked_sub(rhs.0).map(Self) } } impl CheckedSub for Height { fn checked_sub(self, rhs: u32) -> Option { self.0.checked_sub(rhs).map(Height::from) } } impl CheckedSub for Height { fn checked_sub(self, rhs: usize) -> Option { self.0.checked_sub(rhs as u32).map(Height::from) } } impl AddAssign for Height { fn add_assign(&mut self, rhs: usize) { *self = self.add(rhs); } } impl CheckedSub for Height { fn checked_sub(self, rhs: u64) -> Option { self.0.checked_sub(rhs as u32).map(Height::from) } } impl AddAssign for Height { fn add_assign(&mut self, rhs: u64) { *self = self.add(rhs); } } impl Rem for Height { type Output = Self; fn rem(self, rhs: Height) -> Self::Output { Self(self.0.rem(rhs.0)) } } impl Rem for Height { type Output = Self; fn rem(self, rhs: usize) -> Self::Output { Self(self.0.rem(Height::from(rhs).0)) } } impl From for Height { fn from(value: u32) -> Self { Self(value) } } impl From for Height { fn from(value: u64) -> Self { Self(value as u32) } } impl From for Height { fn from(value: StoredU64) -> Self { Self(*value as u32) } } impl From for Height { fn from(value: usize) -> Self { Self(value as u32) } } impl From for usize { fn from(value: Height) -> Self { value.0 as usize } } impl From for u32 { fn from(value: Height) -> Self { value.0 } } impl From for u64 { fn from(value: Height) -> Self { value.0 as u64 } } impl TryFrom<&Client> for Height { type Error = bitcoincore_rpc::Error; fn try_from(value: &Client) -> Result { Ok((value.get_block_count()? as usize).into()) } } impl From for Height { fn from(value: bitcoin::locktime::absolute::Height) -> Self { Self(value.to_consensus_u32()) } } impl TryFrom<&std::path::Path> for Height { type Error = brk_error::Error; fn try_from(value: &std::path::Path) -> Result { Ok(Self::read_from_bytes(std::fs::read(value)?.as_slice())?.to_owned()) } } impl From for Height { fn from(value: ByteView) -> Self { Self(u32::from_be_bytes(copy_first_4bytes(&value).unwrap())) } } impl From for ByteView { fn from(value: Height) -> Self { Self::from(&value) } } impl From<&Height> for ByteView { fn from(value: &Height) -> Self { Self::new(&value.0.to_be_bytes()) } } impl From for Height { fn from(value: Stamp) -> Self { let u = u64::from(value); assert!(u <= u32::MAX as u64); Self(u as u32) } } impl From for Stamp { fn from(value: Height) -> Self { Self::from(value.0 as u64) } } impl PrintableIndex for Height { fn to_string() -> &'static str { "height" } fn to_possible_strings() -> &'static [&'static str] { &["h", "height"] } } impl std::fmt::Display for Height { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut buf = itoa::Buffer::new(); let str = buf.format(self.0); f.write_str(str) } }