use core::fmt;
use std::{
cmp,
};
use crate::protocol::FrameSn;
const MASK: FrameSn = (u32::MAX >> 4) as FrameSn;
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct SeqNum(u32);
impl SeqNum {
pub(crate) const fn new(value: u32) -> Self {
let value = value & MASK;
SeqNum(value)
}
pub(crate) const fn get(&self) -> u32 {
self.0
}
pub(crate) fn set(&mut self, sn: Self) {
*self = sn;
}
pub(crate) fn next(&self) -> Self {
Self(self.0.wrapping_add(1) & MASK)
}
pub(crate) fn increment(&mut self) -> Self {
let next = self.next();
self.set(next);
next
}
#[cfg(test)]
pub(crate) fn rand() -> Self {
use rand::Rng;
let mut rng = rand::rng();
Self::new(rng.random())
}
}
impl PartialOrd for SeqNum {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for SeqNum {
fn cmp(&self, other: &Self) -> cmp::Ordering {
if self == other {
return cmp::Ordering::Equal;
}
let gap = other.0.wrapping_sub(self.0) & MASK;
if (gap != 0) && ((gap & !(MASK >> 1)) == 0) {
cmp::Ordering::Less
} else {
cmp::Ordering::Greater
}
}
}
impl fmt::Display for SeqNum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}", self.0))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_seq_num_vle() {
assert_eq!(crate::codec::core::vle::vle_len(super::MASK as u64), 4);
}
#[test]
fn test_new_and_get() {
let sn = SeqNum::new(5);
assert_eq!(sn.get(), 5);
let sn = SeqNum::new(42);
assert_eq!(sn.get(), 42 & MASK);
let large_value = u32::MAX;
let sn = SeqNum::new(large_value);
assert_eq!(sn.get(), large_value & MASK); }
#[test]
fn test_set() {
let mut sn = SeqNum::new(2);
let new_sn = SeqNum::new(4);
sn.set(new_sn);
assert_eq!(sn.get(), 4);
}
#[test]
fn test_next() {
let sn = SeqNum::new(3);
let next = sn.next();
assert_eq!(next.get(), 4);
let max_sn = SeqNum::new(MASK);
let next = max_sn.next();
assert_eq!(next.get(), 0);
}
#[test]
fn test_increment() {
let mut sn = SeqNum::new(2);
let result = sn.increment();
assert_eq!(sn.get(), 3);
assert_eq!(result.get(), 3);
let mut sn = SeqNum::new(MASK);
let result = sn.increment();
assert_eq!(sn.get(), 0);
assert_eq!(result.get(), 0);
}
#[test]
fn test_ordering() {
let sn1 = SeqNum::new(1);
let sn2 = SeqNum::new(2);
let sn3 = SeqNum::new(3);
assert!(sn1 < sn2);
assert!(sn2 < sn3);
assert!(sn1 < sn3);
assert!(sn2 > sn1);
assert!(sn3 > sn1);
}
#[test]
fn test_ordering_wraparound() {
let sn_low = SeqNum::new(MASK);
let sn_high = SeqNum::new(6);
assert!(sn_high > sn_low);
assert!(sn_low < sn_high);
}
#[test]
fn test_ordering_half_space() {
let half_space = (MASK >> 1) + 1;
let sn0 = SeqNum::new(0);
let sn1 = SeqNum::new(1);
let sn_before_half = SeqNum::new(half_space - 1);
let sn_at_half = SeqNum::new(half_space);
let sn_after_half = SeqNum::new(half_space + 1);
let sn_near_end = SeqNum::new(MASK - 1);
let sn_max = SeqNum::new(MASK);
assert!(sn0 < sn1);
assert!(sn0 < sn_before_half);
assert!(sn0 > sn_at_half);
assert!(sn_after_half < sn0); assert!(sn_near_end < sn0); assert!(sn_max < sn0); }
#[test]
fn test_partial_ord() {
let sn1 = SeqNum::new(2);
let sn2 = SeqNum::new(4);
assert_eq!(sn1.partial_cmp(&sn2), Some(cmp::Ordering::Less));
assert_eq!(sn2.partial_cmp(&sn1), Some(cmp::Ordering::Greater));
assert_eq!(sn1.partial_cmp(&sn1), Some(cmp::Ordering::Equal));
}
#[test]
fn test_debug() {
let sn = SeqNum::new(5);
let debug_str = format!("{:?}", sn);
assert!(debug_str.contains("5"));
}
}