use std::fmt;
use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Serialize};
#[derive(
BorshSerialize,
BorshDeserialize,
Clone,
Copy,
Debug,
Default,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
Serialize,
Deserialize,
)]
#[serde(transparent)]
#[repr(transparent)]
pub struct TokenomicsEpochId(u64);
impl TokenomicsEpochId {
pub const ZERO: Self = Self(0);
pub const fn new(epoch: u64) -> Self {
Self(epoch)
}
pub const fn as_u64(self) -> u64 {
self.0
}
}
impl fmt::Display for TokenomicsEpochId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_as_u64_roundtrip() {
assert_eq!(TokenomicsEpochId::new(42).as_u64(), 42);
assert_eq!(TokenomicsEpochId::ZERO.as_u64(), 0);
}
#[test]
fn test_display_forwards_format_flags() {
assert_eq!(format!("{}", TokenomicsEpochId::new(42)), "42");
assert_eq!(format!("{:04}", TokenomicsEpochId::new(42)), "0042");
}
#[test]
fn test_bincode_matches_u64() {
use bincode::Options;
let cfg = bincode::DefaultOptions::new()
.with_big_endian()
.with_fixint_encoding();
for raw in [0u64, 1, 42, u64::MAX] {
assert_eq!(
cfg.serialize(&TokenomicsEpochId::new(raw)).unwrap(),
cfg.serialize(&raw).unwrap()
);
}
assert!(
cfg.serialize(&TokenomicsEpochId::new(5)).unwrap()
< cfg.serialize(&TokenomicsEpochId::new(6)).unwrap()
);
assert_eq!(
bincode::serialize(&TokenomicsEpochId::new(9)).unwrap(),
bincode::serialize(&9u64).unwrap()
);
}
#[test]
fn test_bcs_matches_u64() {
let raw: u64 = 0xdead_beef;
assert_eq!(
bcs::to_bytes(&TokenomicsEpochId::new(raw)).unwrap(),
bcs::to_bytes(&raw).unwrap()
);
assert_eq!(
bcs::from_bytes::<TokenomicsEpochId>(&bcs::to_bytes(&raw).unwrap()).unwrap(),
TokenomicsEpochId::new(raw)
);
}
#[test]
fn test_borsh_roundtrips_like_u64() {
let e = TokenomicsEpochId::new(123);
let bytes = borsh::to_vec(&e).unwrap();
assert_eq!(bytes, 123u64.to_le_bytes());
assert_eq!(borsh::from_slice::<TokenomicsEpochId>(&bytes).unwrap(), e);
}
}