use core::{cmp::Ordering, fmt};
use domain_macros::*;
use super::wire::U32;
#[derive(
Copy,
Clone,
Debug,
PartialEq,
Eq,
Hash,
AsBytes,
BuildBytes,
ParseBytes,
ParseBytesZC,
SplitBytes,
SplitBytesZC,
UnsizedCopy,
)]
#[repr(transparent)]
pub struct Serial(U32);
impl Serial {
#[cfg(feature = "std")]
pub fn unix_time() -> Self {
use std::time::SystemTime;
let time = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("The current time is after the Unix Epoch");
Self::from(time.as_secs() as u32)
}
}
impl Serial {
pub fn inc(self, num: i32) -> Self {
assert!(num >= 0, "Cannot subtract from a `Serial`");
self.0.get().wrapping_add_signed(num).into()
}
}
impl PartialOrd for Serial {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let (lhs, rhs) = (self.0.get(), other.0.get());
if lhs == rhs {
Some(Ordering::Equal)
} else if lhs.abs_diff(rhs) == 1 << 31 {
None
} else if (lhs < rhs) ^ (lhs.abs_diff(rhs) > (1 << 31)) {
Some(Ordering::Less)
} else {
Some(Ordering::Greater)
}
}
}
impl From<u32> for Serial {
fn from(value: u32) -> Self {
Self(U32::new(value))
}
}
impl From<Serial> for u32 {
fn from(value: Serial) -> Self {
value.0.get()
}
}
impl fmt::Display for Serial {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.get().fmt(f)
}
}
#[cfg(test)]
mod test {
use super::Serial;
#[test]
fn comparisons() {
assert!(Serial::from(u32::MAX) > Serial::from(u32::MAX / 2 + 1));
assert!(Serial::from(0) > Serial::from(u32::MAX));
assert!(Serial::from(1) > Serial::from(0));
}
#[test]
fn operations() {
assert_eq!(u32::from(Serial::from(1).inc(1)), 2);
assert_eq!(u32::from(Serial::from(u32::MAX).inc(1)), 0);
}
}