#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Sequence(u32);
impl Sequence {
#[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 advance(self, n: u32) -> Self {
Self(self.0.wrapping_add(n))
}
#[must_use]
pub const fn is_exactly_acked_by(self, acked: u32) -> bool {
acked.wrapping_sub(self.0) == 0
}
#[must_use]
pub const fn is_at_least_acked_by(self, acked: u32) -> bool {
acked.wrapping_sub(self.0) < 0x8000_0000
}
}
impl From<u32> for Sequence {
fn from(value: u32) -> Self {
Self::new(value)
}
}
impl From<Sequence> for u32 {
fn from(seq: Sequence) -> Self {
seq.value()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn exact_match() {
let s = Sequence::new(100);
assert!(s.is_exactly_acked_by(100));
assert!(!s.is_exactly_acked_by(99));
assert!(!s.is_exactly_acked_by(101));
}
#[test]
fn exact_match_wraps_around() {
let s = Sequence::new(u32::MAX);
assert!(s.is_exactly_acked_by(u32::MAX));
assert!(!s.is_exactly_acked_by(0));
}
#[test]
fn advance_wraps() {
let s = Sequence::new(u32::MAX);
assert_eq!(s.advance(1).value(), 0);
assert_eq!(s.advance(2).value(), 1);
}
#[test]
fn at_least_basic() {
let s = Sequence::new(100);
assert!(s.is_at_least_acked_by(100));
assert!(s.is_at_least_acked_by(101));
assert!(s.is_at_least_acked_by(200));
assert!(!s.is_at_least_acked_by(99));
assert!(!s.is_at_least_acked_by(0));
}
#[test]
fn at_least_across_wrap() {
let s = Sequence::new(u32::MAX);
assert!(s.is_at_least_acked_by(0));
assert!(s.is_at_least_acked_by(5));
assert!(s.is_at_least_acked_by(0x7FFF_FFFE));
assert!(!s.is_at_least_acked_by(0x7FFF_FFFF));
}
#[test]
fn round_trip_u32() {
let s = Sequence::from(42_u32);
let v: u32 = s.into();
assert_eq!(v, 42);
}
}