use bc_envelope::prelude::*;
use std::cmp::{Ord, Ordering};
use std::fmt;
use std::ops::{Add, Sub};
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct BlockHeight(u32);
pub const H0: BlockHeight = BlockHeight(0);
impl BlockHeight {
pub const fn from_u32(v: u32) -> BlockHeight {
BlockHeight(v)
}
pub fn saturating_sub(self, v: u32) -> BlockHeight {
BlockHeight(self.0.saturating_sub(v))
}
}
impl fmt::Display for BlockHeight {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(formatter)
}
}
impl Ord for BlockHeight {
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
}
impl PartialOrd for BlockHeight {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl From<u32> for BlockHeight {
fn from(value: u32) -> Self {
BlockHeight(value)
}
}
impl From<BlockHeight> for u32 {
fn from(value: BlockHeight) -> u32 {
value.0
}
}
impl TryFrom<u64> for BlockHeight {
type Error = std::num::TryFromIntError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
u32::try_from(value).map(BlockHeight)
}
}
impl From<BlockHeight> for u64 {
fn from(value: BlockHeight) -> u64 {
value.0 as u64
}
}
impl TryFrom<i32> for BlockHeight {
type Error = std::num::TryFromIntError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
u32::try_from(value).map(BlockHeight)
}
}
impl TryFrom<i64> for BlockHeight {
type Error = std::num::TryFromIntError;
fn try_from(value: i64) -> Result<Self, Self::Error> {
u32::try_from(value).map(BlockHeight)
}
}
impl From<BlockHeight> for i64 {
fn from(value: BlockHeight) -> i64 {
value.0 as i64
}
}
impl Add<u32> for BlockHeight {
type Output = Self;
fn add(self, other: u32) -> Self {
BlockHeight(self.0.saturating_add(other))
}
}
impl Sub<u32> for BlockHeight {
type Output = Self;
fn sub(self, other: u32) -> Self {
BlockHeight(self.0.saturating_sub(other))
}
}
impl Sub<BlockHeight> for BlockHeight {
type Output = u32;
fn sub(self, other: BlockHeight) -> u32 {
self.0.saturating_sub(other.0)
}
}
impl From<BlockHeight> for CBOR {
fn from(value: BlockHeight) -> Self {
CBOR::from(value.0)
}
}
impl From<&BlockHeight> for CBOR {
fn from(value: &BlockHeight) -> Self {
CBOR::from(value.0)
}
}
impl TryFrom<CBOR> for BlockHeight {
type Error = dcbor::Error;
fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
Ok(BlockHeight::from(u32::try_from(cbor)?))
}
}
impl From<BlockHeight> for Envelope {
fn from(value: BlockHeight) -> Self {
Envelope::new(CBOR::from(value))
}
}
impl TryFrom<Envelope> for BlockHeight {
type Error = anyhow::Error;
fn try_from(envelope: Envelope) -> Result<Self, Self::Error> {
envelope.extract_subject()
}
}
#[cfg(test)]
mod tests {
use crate::{test_cbor_roundtrip, test_envelope_roundtrip};
use super::BlockHeight;
impl crate::RandomInstance for BlockHeight {
fn random() -> Self {
let mut rng = bc_rand::thread_rng();
let value = rand::Rng::gen_range(&mut rng, 0..u32::MAX);
Self(value)
}
}
test_cbor_roundtrip!(BlockHeight);
test_envelope_roundtrip!(BlockHeight);
}