use serde::{Deserialize, Serialize};
use std::ops::{Add, AddAssign};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct MaxBlockRange(u64);
impl MaxBlockRange {
pub const DEFAULT: Self = Self(2000);
pub const MODERATE: Self = Self(5000);
pub const GENEROUS: Self = Self(10000);
pub const CONSERVATIVE: Self = Self(1000);
pub const fn new(blocks: u64) -> Self {
Self(blocks)
}
pub const fn as_u64(&self) -> u64 {
self.0
}
}
impl From<u64> for MaxBlockRange {
fn from(value: u64) -> Self {
Self(value)
}
}
impl std::fmt::Display for MaxBlockRange {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} blocks", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)]
#[serde(transparent)]
pub struct TransactionCount(usize);
impl TransactionCount {
pub const ZERO: Self = Self(0);
pub const fn new(count: usize) -> Self {
Self(count)
}
pub const fn as_usize(&self) -> usize {
self.0
}
pub fn increment(&mut self) {
self.0 = self.0.saturating_add(1);
}
pub fn is_zero(&self) -> bool {
self.0 == 0
}
}
impl From<usize> for TransactionCount {
fn from(value: usize) -> Self {
Self(value)
}
}
impl Add for TransactionCount {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0.saturating_add(rhs.0))
}
}
impl AddAssign for TransactionCount {
fn add_assign(&mut self, rhs: Self) {
self.0 = self.0.saturating_add(rhs.0);
}
}
impl std::fmt::Display for TransactionCount {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} transactions", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)]
#[serde(transparent)]
pub struct BlockCount(u64);
impl BlockCount {
pub const ZERO: Self = Self(0);
pub const fn new(count: u64) -> Self {
Self(count)
}
pub const fn as_u64(&self) -> u64 {
self.0
}
pub fn is_zero(&self) -> bool {
self.0 == 0
}
}
impl From<u64> for BlockCount {
fn from(value: u64) -> Self {
Self(value)
}
}
impl Add for BlockCount {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0.saturating_add(rhs.0))
}
}
impl AddAssign for BlockCount {
fn add_assign(&mut self, rhs: Self) {
self.0 = self.0.saturating_add(rhs.0);
}
}
impl std::fmt::Display for BlockCount {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.0 == 1 {
write!(f, "1 block")
} else {
write!(f, "{} blocks", self.0)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_max_block_range_creation() {
let range = MaxBlockRange::new(2000);
assert_eq!(range.as_u64(), 2000);
}
#[test]
fn test_max_block_range_constants() {
assert_eq!(MaxBlockRange::CONSERVATIVE.as_u64(), 1000);
assert_eq!(MaxBlockRange::DEFAULT.as_u64(), 2000);
assert_eq!(MaxBlockRange::MODERATE.as_u64(), 5000);
assert_eq!(MaxBlockRange::GENEROUS.as_u64(), 10000);
}
#[test]
fn test_display() {
let range = MaxBlockRange::new(2000);
assert_eq!(format!("{}", range), "2000 blocks");
}
#[test]
fn test_serialization() {
let range = MaxBlockRange::new(2000);
let json = serde_json::to_string(&range).unwrap();
let deserialized: MaxBlockRange = serde_json::from_str(&json).unwrap();
assert_eq!(range, deserialized);
}
#[test]
fn test_conversions() {
let u64_val = 2000u64;
let range: MaxBlockRange = u64_val.into();
let back: u64 = range.as_u64();
assert_eq!(u64_val, back);
}
#[test]
fn test_ordering() {
let small = MaxBlockRange::CONSERVATIVE;
let medium = MaxBlockRange::DEFAULT;
let large = MaxBlockRange::GENEROUS;
assert!(small < medium);
assert!(medium < large);
assert!(small < large);
}
#[test]
fn test_transaction_count_creation() {
let count = TransactionCount::new(5);
assert_eq!(count.as_usize(), 5);
}
#[test]
fn test_transaction_count_zero() {
assert!(TransactionCount::ZERO.is_zero());
assert_eq!(TransactionCount::ZERO.as_usize(), 0);
}
#[test]
fn test_transaction_count_addition() {
let a = TransactionCount::new(5);
let b = TransactionCount::new(3);
let sum = a + b;
assert_eq!(sum.as_usize(), 8);
}
#[test]
fn test_transaction_count_increment() {
let mut count = TransactionCount::new(5);
count.increment();
assert_eq!(count.as_usize(), 6);
}
#[test]
fn test_transaction_count_saturating_addition() {
let max_count = TransactionCount::new(usize::MAX);
let small_count = TransactionCount::new(1);
let result = max_count + small_count;
assert_eq!(result.as_usize(), usize::MAX);
}
#[test]
fn test_transaction_count_saturating_increment() {
let mut count = TransactionCount::new(usize::MAX);
count.increment();
assert_eq!(count.as_usize(), usize::MAX);
}
#[test]
fn test_transaction_count_display() {
let count = TransactionCount::new(42);
assert_eq!(format!("{}", count), "42 transactions");
}
#[test]
fn test_transaction_count_serialization() {
let count = TransactionCount::new(10);
let json = serde_json::to_string(&count).unwrap();
let deserialized: TransactionCount = serde_json::from_str(&json).unwrap();
assert_eq!(count, deserialized);
}
#[test]
fn test_transaction_count_conversions() {
let usize_val = 42usize;
let count: TransactionCount = usize_val.into();
let back: usize = count.as_usize();
assert_eq!(usize_val, back);
}
#[test]
fn test_transaction_count_ordering() {
let small = TransactionCount::new(5);
let medium = TransactionCount::new(10);
let large = TransactionCount::new(20);
assert!(small < medium);
assert!(medium < large);
assert!(small < large);
}
}