use core::fmt;
macro_rules! id_newtype {
($(#[$meta:meta])* $name:ident) => {
$(#[$meta])*
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct $name(u32);
impl $name {
#[must_use]
pub const fn new(value: u32) -> Self {
Self(value)
}
#[must_use]
pub const fn value(self) -> u32 {
self.0
}
#[must_use]
pub const fn checked_next(self) -> Option<Self> {
match self.0.checked_add(1) {
Some(v) => Some(Self(v)),
None => None,
}
}
#[must_use]
pub const fn wrapping_next(self) -> Self {
Self(self.0.wrapping_add(1))
}
#[must_use]
pub const fn saturating_next(self) -> Self {
Self(self.0.saturating_add(1))
}
#[must_use]
pub const fn checked_add(self, n: u32) -> Option<Self> {
match self.0.checked_add(n) {
Some(v) => Some(Self(v)),
None => None,
}
}
#[must_use]
pub const fn checked_sub(self, n: u32) -> Option<Self> {
match self.0.checked_sub(n) {
Some(v) => Some(Self(v)),
None => None,
}
}
#[must_use]
pub const fn checked_distance_from(self, earlier: Self) -> Option<u32> {
self.0.checked_sub(earlier.0)
}
}
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
};
}
id_newtype! {
SegmentSeq
}
id_newtype! {
PartIndex
}
id_newtype! {
Generation
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use alloc::format;
#[test]
fn checked_next_stops_at_max_wrapping_wraps() {
let max = SegmentSeq::new(u32::MAX);
assert_eq!(max.checked_next(), None);
assert_eq!(max.wrapping_next(), SegmentSeq::new(0));
assert_eq!(max.saturating_next(), max);
assert_eq!(SegmentSeq::new(6).checked_next(), Some(SegmentSeq::new(7)));
assert_eq!(PartIndex::new(u32::MAX).checked_next(), None);
}
#[test]
fn checked_add_sub_distance() {
let s = SegmentSeq::new(5);
assert_eq!(s.checked_add(u32::MAX), None);
assert_eq!(s.checked_sub(6), None);
assert_eq!(s.checked_sub(5), Some(SegmentSeq::new(0)));
assert_eq!(s.checked_distance_from(SegmentSeq::new(2)), Some(3));
assert_eq!(s.checked_distance_from(SegmentSeq::new(9)), None);
}
#[test]
fn display_and_debug_are_bare() {
assert_eq!(
format!("{} {:?}", PartIndex::new(7), SegmentSeq::new(9)),
"7 9"
);
}
}