use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FuelAmount(u64);
impl FuelAmount {
pub const DEFAULT: u64 = 1_000_000;
pub const MIN_RECOMMENDED: u64 = 10_000;
pub const MAX: u64 = 100_000_000;
#[inline]
#[must_use]
pub const fn new(amount: u64) -> Self {
Self(amount)
}
#[inline]
#[must_use]
pub const fn new_checked(amount: u64) -> Option<Self> {
if amount > 0 && amount <= Self::MAX {
Some(Self(amount))
} else {
None
}
}
#[inline]
#[must_use]
pub const fn default() -> Self {
Self(Self::DEFAULT)
}
#[inline]
#[must_use]
pub const fn as_u64(self) -> u64 {
self.0
}
#[inline]
#[must_use]
pub const fn checked_sub(self, amount: u64) -> Option<Self> {
match self.0.checked_sub(amount) {
Some(remaining) => Some(Self(remaining)),
None => None,
}
}
#[inline]
#[must_use]
pub const fn is_exhausted(self) -> bool {
self.0 == 0
}
}
impl Default for FuelAmount {
fn default() -> Self {
Self::default()
}
}
impl From<u64> for FuelAmount {
fn from(amount: u64) -> Self {
Self::new(amount)
}
}
impl fmt::Display for FuelAmount {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} fuel", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CheckCount(usize);
impl CheckCount {
pub const MAX: usize = 256;
#[inline]
#[must_use]
pub const fn new(count: usize) -> Self {
Self(count)
}
#[inline]
#[must_use]
pub const fn new_checked(count: usize) -> Option<Self> {
if count <= Self::MAX {
Some(Self(count))
} else {
None
}
}
#[inline]
#[must_use]
pub const fn zero() -> Self {
Self(0)
}
#[inline]
#[must_use]
pub const fn as_usize(self) -> usize {
self.0
}
#[inline]
#[must_use]
pub const fn increment(self) -> Option<Self> {
if self.0 < Self::MAX {
Some(Self(self.0 + 1))
} else {
None
}
}
#[inline]
#[must_use]
pub const fn at_max(self) -> bool {
self.0 >= Self::MAX
}
#[inline]
#[must_use]
pub const fn is_zero(self) -> bool {
self.0 == 0
}
}
impl Default for CheckCount {
fn default() -> Self {
Self::zero()
}
}
impl From<usize> for CheckCount {
fn from(count: usize) -> Self {
Self::new(count)
}
}
impl fmt::Display for CheckCount {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} checks", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LogSize(usize);
impl LogSize {
pub const MAX: usize = 64 * 1024;
#[inline]
#[must_use]
pub const fn new(size: usize) -> Self {
Self(size)
}
#[inline]
#[must_use]
pub const fn new_checked(size: usize) -> Option<Self> {
if size <= Self::MAX {
Some(Self(size))
} else {
None
}
}
#[inline]
#[must_use]
pub const fn as_usize(self) -> usize {
self.0
}
#[inline]
#[must_use]
pub const fn would_exceed(self, additional: usize) -> bool {
match self.0.checked_add(additional) {
Some(total) => total > Self::MAX,
None => true,
}
}
}
impl fmt::Display for LogSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} bytes", self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fuel_amount_basic() {
let fuel = FuelAmount::new(1000);
assert_eq!(fuel.as_u64(), 1000);
}
#[test]
fn test_fuel_amount_checked() {
assert!(FuelAmount::new_checked(1000).is_some());
assert!(FuelAmount::new_checked(0).is_none());
assert!(FuelAmount::new_checked(FuelAmount::MAX + 1).is_none());
}
#[test]
fn test_fuel_amount_subtract() {
let fuel = FuelAmount::new(1000);
assert_eq!(fuel.checked_sub(100).unwrap().as_u64(), 900);
assert!(fuel.checked_sub(1001).is_none());
}
#[test]
fn test_fuel_amount_exhausted() {
assert!(FuelAmount::new(0).is_exhausted());
assert!(!FuelAmount::new(1).is_exhausted());
}
#[test]
fn test_check_count_basic() {
let count = CheckCount::new(5);
assert_eq!(count.as_usize(), 5);
}
#[test]
fn test_check_count_increment() {
let count = CheckCount::new(5);
let incremented = count.increment().unwrap();
assert_eq!(incremented.as_usize(), 6);
let max_count = CheckCount::new(CheckCount::MAX);
assert!(max_count.increment().is_none());
}
#[test]
fn test_check_count_at_max() {
assert!(!CheckCount::new(5).at_max());
assert!(CheckCount::new(CheckCount::MAX).at_max());
}
#[test]
fn test_log_size_would_exceed() {
let size = LogSize::new(100);
assert!(!size.would_exceed(50));
let size = LogSize::new(LogSize::MAX - 10);
assert!(size.would_exceed(20));
}
}