use crate::SeqNo;
use std::{
fmt::Debug,
sync::{
Arc,
atomic::{
AtomicU64,
Ordering::{AcqRel, Acquire, Release},
},
},
};
pub const MAX_SEQNO: SeqNo = 0x7FFF_FFFF_FFFF_FFFF;
pub trait SequenceNumberGenerator:
Send + Sync + Debug + std::panic::UnwindSafe + std::panic::RefUnwindSafe + 'static
{
#[must_use]
fn next(&self) -> SeqNo;
#[must_use]
fn get(&self) -> SeqNo;
fn set(&self, value: SeqNo);
fn fetch_max(&self, value: SeqNo);
}
pub type SharedSequenceNumberGenerator = Arc<dyn SequenceNumberGenerator>;
#[derive(Clone, Default, Debug)]
pub struct SequenceNumberCounter(Arc<AtomicU64>);
impl SequenceNumberCounter {
#[must_use]
pub fn new(prev: SeqNo) -> Self {
assert!(
prev <= MAX_SEQNO,
"Sequence number must not use the reserved MSB"
);
Self(Arc::new(AtomicU64::new(prev)))
}
#[must_use]
pub fn next(&self) -> SeqNo {
<Self as SequenceNumberGenerator>::next(self)
}
#[must_use]
pub fn get(&self) -> SeqNo {
<Self as SequenceNumberGenerator>::get(self)
}
pub fn set(&self, value: SeqNo) {
<Self as SequenceNumberGenerator>::set(self, value);
}
pub fn fetch_max(&self, value: SeqNo) {
<Self as SequenceNumberGenerator>::fetch_max(self, value);
}
}
impl SequenceNumberGenerator for SequenceNumberCounter {
fn next(&self) -> SeqNo {
match self.0.fetch_update(AcqRel, Acquire, |current| {
if current >= MAX_SEQNO {
None
} else {
Some(current + 1)
}
}) {
Ok(seqno) => seqno,
Err(current) => panic!("Ran out of sequence numbers (current: {current})"),
}
}
fn get(&self) -> SeqNo {
self.0.load(Acquire)
}
fn set(&self, value: SeqNo) {
assert!(
value <= MAX_SEQNO,
"Sequence number must not use the reserved MSB"
);
self.0.store(value, Release);
}
fn fetch_max(&self, value: SeqNo) {
let clamped = value.min(MAX_SEQNO);
self.0.fetch_max(clamped, AcqRel);
}
}
impl From<SequenceNumberCounter> for SharedSequenceNumberGenerator {
fn from(counter: SequenceNumberCounter) -> Self {
Arc::new(counter)
}
}
#[cfg(test)]
mod tests {
use super::MAX_SEQNO;
use test_log::test;
#[test]
fn next_below_max_returns_valid_seqno() {
let counter = super::SequenceNumberCounter::default();
counter.set(MAX_SEQNO - 1);
let _ = counter.next();
}
#[test]
#[should_panic(expected = "Ran out of sequence numbers")]
fn next_at_max_panics() {
let counter = super::SequenceNumberCounter::default();
counter.set(MAX_SEQNO);
let _ = counter.next();
}
#[test]
#[should_panic(expected = "Sequence number must not use the reserved MSB")]
fn set_reserved_range_panics() {
let counter = super::SequenceNumberCounter::default();
counter.set(MAX_SEQNO + 1);
}
#[test]
fn fetch_max_clamps_reserved_to_max() {
let counter = super::SequenceNumberCounter::default();
counter.set(100);
counter.fetch_max(MAX_SEQNO + 1);
assert_eq!(counter.get(), MAX_SEQNO);
}
}