use std::sync::atomic::{AtomicU32, Ordering};
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct Handle {
next: u32,
first: u32,
}
impl Handle {
pub fn new(first: u32) -> Handle {
Handle { next: first, first }
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> u32 {
let next = self.next;
if self.next == u32::MAX {
self.next = self.first;
} else {
self.next += 1;
}
next
}
pub fn peek_next(&self) -> u32 {
self.next
}
pub fn set_next(&mut self, next: u32) {
self.next = next;
}
pub fn reset(&mut self) {
self.set_next(self.first);
}
}
#[derive(Debug)]
pub struct AtomicHandle {
next: AtomicU32,
first: u32,
}
impl AtomicHandle {
pub fn new(first: u32) -> Self {
Self {
next: AtomicU32::new(first),
first,
}
}
pub fn next(&self) -> u32 {
let mut val = self.next.fetch_add(1, Ordering::Relaxed);
while val < self.first {
match self.next.compare_exchange(
val + 1,
self.first + 1,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => val = self.first,
Err(v) => {
if v >= self.first {
val = self.next.fetch_add(1, Ordering::Relaxed);
} else {
val = v;
}
}
}
}
val
}
pub fn set_next(&self, next: u32) {
debug_assert!(next >= self.first);
self.next.store(next, Ordering::Relaxed);
}
pub fn reset(&self) {
self.set_next(self.first);
}
}
#[test]
fn handle_increment() {
let mut h = Handle::new(0);
assert_eq!(h.next(), 0);
assert_eq!(h.next(), 1);
assert_eq!(h.next(), 2);
let mut h = Handle::new(100);
assert_eq!(h.next(), 100);
assert_eq!(h.next(), 101);
}
#[test]
fn handle_wrap() {
let mut h = Handle::new(u32::MAX - 2);
assert_eq!(h.next(), u32::MAX - 2);
assert_eq!(h.next(), u32::MAX - 1);
assert_eq!(h.next(), u32::MAX);
assert_eq!(h.next(), u32::MAX - 2);
}
#[test]
fn atomic_handle_increment() {
let h = AtomicHandle::new(0);
assert_eq!(h.next(), 0);
assert_eq!(h.next(), 1);
assert_eq!(h.next(), 2);
let h = AtomicHandle::new(100);
assert_eq!(h.next(), 100);
assert_eq!(h.next(), 101);
}
#[test]
fn atomic_handle_wrap() {
let h = AtomicHandle::new(u32::MAX - 2);
assert_eq!(h.next(), u32::MAX - 2);
assert_eq!(h.next(), u32::MAX - 1);
assert_eq!(h.next(), u32::MAX);
assert_eq!(h.next(), u32::MAX - 2);
}