49 lines
1.0 KiB
Rust
49 lines
1.0 KiB
Rust
use core::sync::atomic::{AtomicI32, Ordering};
|
|
|
|
use crate::sync::Mutex;
|
|
|
|
pub struct Once {
|
|
done: AtomicI32,
|
|
mutex: Mutex<()>,
|
|
}
|
|
|
|
impl Once {
|
|
pub const fn init(once: &'static Once) -> Once {
|
|
Once {
|
|
done: AtomicI32::new(0),
|
|
mutex: Mutex::init(&once.mutex, ()),
|
|
}
|
|
}
|
|
|
|
pub fn call_once<F: FnOnce()>(&self, f: F) {
|
|
if self.done.load(Ordering::Acquire) == 0 {
|
|
let _guard = self.mutex.lock();
|
|
if self.done.load(Ordering::Relaxed) == 0 {
|
|
f();
|
|
self.done.store(1, Ordering::Release);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn is_completed(&self) -> bool {
|
|
self.done.load(Ordering::Acquire) != 0
|
|
}
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! once {
|
|
($name: ident) => {
|
|
static $name: $crate::sync::Once = $crate::sync::Once::init(&$name);
|
|
};
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
#[test]
|
|
fn fast_path() {
|
|
once!(ONCE);
|
|
ONCE.call_once(|| {});
|
|
assert!(ONCE.is_completed());
|
|
}
|
|
}
|