use std::fmt;
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
pub struct InFlightClaim(Arc<AtomicU64>);
impl InFlightClaim {
pub fn attach(counter: &Arc<AtomicU64>) -> Self {
counter.fetch_add(1, Ordering::AcqRel);
Self(Arc::clone(counter))
}
pub fn split(&self) -> Self {
self.0.fetch_add(1, Ordering::AcqRel);
Self(Arc::clone(&self.0))
}
}
impl Drop for InFlightClaim {
fn drop(&mut self) {
self.0.fetch_sub(1, Ordering::AcqRel);
}
}
impl fmt::Debug for InFlightClaim {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("InFlightClaim")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn claim_attach_increments_and_drop_decrements() {
let counter = Arc::new(AtomicU64::new(0));
let claim = InFlightClaim::attach(&counter);
assert_eq!(counter.load(Ordering::Acquire), 1);
drop(claim);
assert_eq!(counter.load(Ordering::Acquire), 0);
}
#[test]
fn claim_split_adds_one_sibling() {
let counter = Arc::new(AtomicU64::new(0));
let original = InFlightClaim::attach(&counter);
assert_eq!(counter.load(Ordering::Acquire), 1);
let sibling = original.split();
assert_eq!(counter.load(Ordering::Acquire), 2);
drop(sibling);
assert_eq!(counter.load(Ordering::Acquire), 1);
drop(original);
assert_eq!(counter.load(Ordering::Acquire), 0);
}
#[test]
fn claim_debug_does_not_leak_pointer() {
let counter = Arc::new(AtomicU64::new(0));
let claim = InFlightClaim::attach(&counter);
assert_eq!(format!("{claim:?}"), "InFlightClaim");
}
}