use core::{
cell::UnsafeCell,
sync::atomic::{AtomicBool, Ordering},
};
pub struct Guard<'a, T> {
lock: &'a SpinLock<T>,
}
unsafe impl<T> Sync for Guard<'_, T> where T: Sync {}
pub struct SpinLock<T> {
locked: AtomicBool,
val: UnsafeCell<T>,
}
unsafe impl<T> Sync for SpinLock<T> where T: Send {}
impl<T> SpinLock<T> {
pub const fn new(val: T) -> Self {
Self {
locked: AtomicBool::new(false),
val: UnsafeCell::new(val),
}
}
#[inline]
pub fn lock(&self) -> Guard<T> {
while self
.locked
.swap(true, core::sync::atomic::Ordering::Acquire)
{
core::hint::spin_loop();
}
Guard { lock: self }
}
}
impl<T> core::ops::Deref for Guard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.val.get() }
}
}
impl<T> core::ops::DerefMut for Guard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.val.get() }
}
}
impl<T> Drop for Guard<'_, T> {
fn drop(&mut self) {
let prev_val = self
.lock
.locked
.swap(false, core::sync::atomic::Ordering::AcqRel);
assert_eq!(prev_val, true);
}
}
pub struct OnceCell<T> {
initialized: AtomicBool,
value: Option<T>,
}
impl<T> OnceCell<T> {
pub const fn new() -> Self {
OnceCell {
initialized: AtomicBool::new(false),
value: None,
}
}
pub fn get_or_init(&mut self, f: impl FnOnce() -> T) -> &mut T {
if !self.initialized.load(Ordering::Relaxed) {
self.value = Some(f());
self.initialized.store(true, Ordering::Relaxed);
}
self.value.as_mut().unwrap()
}
}