#![warn(missing_docs)]
use std::sync::{
Once,
atomic::{AtomicUsize, Ordering},
};
#[unsafe(export_name = "__utally_global_counter")]
pub static GLOBAL_COUNTER: Tally = Tally::new(1);
#[unsafe(export_name = "utally_next")]
pub extern "C" fn next() -> usize {
GLOBAL_COUNTER.next()
}
#[unsafe(export_name = "utally_peek")]
pub extern "C" fn peek() -> usize {
GLOBAL_COUNTER.peek()
}
#[repr(C)]
pub struct Tally {
tally: AtomicUsize,
}
impl Tally {
pub const fn new(initial: usize) -> Tally {
Tally {
tally: AtomicUsize::new(initial),
}
}
pub fn next(&self) -> usize {
self.tally.fetch_add(1, Ordering::Relaxed)
}
pub fn peek(&self) -> usize {
self.tally.load(Ordering::Relaxed)
}
}
#[repr(C)]
pub struct LazyTally {
value: AtomicUsize,
once: Once,
}
impl LazyTally {
pub const fn new() -> Self {
LazyTally {
value: AtomicUsize::new(0),
once: Once::new(),
}
}
pub fn get(&self) -> usize {
let mut val = self.value.load(Ordering::Relaxed);
self.once.call_once(|| {
val = crate::next();
self.value.store(val, Ordering::Relaxed);
});
val
}
}
impl Default for LazyTally {
fn default() -> Self {
Self::new()
}
}