bitcoin_units/locktime/
relative.rsuse core::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Height(u16);
impl Height {
pub const ZERO: Self = Height(0);
pub const MIN: Self = Self::ZERO;
pub const MAX: Self = Height(u16::MAX);
#[inline]
pub const fn from_height(blocks: u16) -> Self { Height(blocks) }
#[inline]
pub const fn value(self) -> u16 { self.0 }
#[inline]
pub const fn to_consensus_u32(&self) -> u32 {
self.0 as u32 }
}
impl From<u16> for Height {
#[inline]
fn from(value: u16) -> Self { Height(value) }
}
crate::impl_parse_str_from_int_infallible!(Height, u16, from);
impl fmt::Display for Height {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Time(u16);
impl Time {
pub const ZERO: Self = Time(0);
pub const MIN: Self = Time::ZERO;
pub const MAX: Self = Time(u16::MAX);
#[inline]
pub const fn from_512_second_intervals(intervals: u16) -> Self { Time(intervals) }
#[inline]
#[rustfmt::skip] pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
let interval = seconds / 512;
if interval <= u16::MAX as u32 { Ok(Time::from_512_second_intervals(interval as u16)) } else {
Err(TimeOverflowError { seconds })
}
}
#[inline]
#[rustfmt::skip] pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
if seconds <= u16::MAX as u32 * 512 {
let interval = (seconds + 511) / 512;
Ok(Time::from_512_second_intervals(interval as u16)) } else {
Err(TimeOverflowError { seconds })
}
}
#[inline]
pub const fn value(self) -> u16 { self.0 }
#[inline]
pub const fn to_consensus_u32(&self) -> u32 {
(1u32 << 22) | self.0 as u32 }
}
crate::impl_parse_str_from_int_infallible!(Time, u16, from_512_second_intervals);
impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TimeOverflowError {
pub(crate) seconds: u32,
}
impl TimeOverflowError {
pub fn new(seconds: u32) -> Self {
assert!(u16::try_from((seconds + 511) / 512).is_err());
Self { seconds }
}
}
impl fmt::Display for TimeOverflowError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{} seconds is too large to be encoded to a 16 bit 512 second interval",
self.seconds
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for TimeOverflowError {}
#[cfg(test)]
mod tests {
use super::*;
const MAXIMUM_ENCODABLE_SECONDS: u32 = u16::MAX as u32 * 512;
#[test]
fn from_seconds_ceil_success() {
let actual = Time::from_seconds_ceil(100).unwrap();
let expected = Time(1_u16);
assert_eq!(actual, expected);
}
#[test]
fn from_seconds_ceil_with_maximum_encodable_seconds_success() {
let actual = Time::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS).unwrap();
let expected = Time(u16::MAX);
assert_eq!(actual, expected);
}
#[test]
fn from_seconds_ceil_causes_time_overflow_error() {
let result = Time::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS + 1);
assert!(result.is_err());
}
#[test]
fn from_seconds_floor_success() {
let actual = Time::from_seconds_floor(100).unwrap();
let expected = Time(0_u16);
assert_eq!(actual, expected);
}
#[test]
fn from_seconds_floor_with_exact_interval() {
let actual = Time::from_seconds_floor(512).unwrap();
let expected = Time(1_u16);
assert_eq!(actual, expected);
}
#[test]
fn from_seconds_floor_with_maximum_encodable_seconds_success() {
let actual = Time::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 511).unwrap();
let expected = Time(u16::MAX);
assert_eq!(actual, expected);
}
#[test]
fn from_seconds_floor_causes_time_overflow_error() {
let result = Time::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 512);
assert!(result.is_err());
}
}