use std::cell::UnsafeCell;
#[derive(Debug)]
#[repr(transparent)]
pub struct UnsafeSyncOnceCell<T>(UnsafeCell<Option<T>>);
impl<T> UnsafeSyncOnceCell<T> {
pub const fn new() -> Self {
UnsafeSyncOnceCell(UnsafeCell::new(None))
}
pub unsafe fn set(&self, value: T) -> Result<(), T> {
unsafe {
if self.get().is_some() {
return Err(value);
}
let slot = &mut *self.0.get();
let _ = slot.insert(value);
Ok(())
}
}
pub unsafe fn get(&self) -> Option<&T> {
unsafe { &*self.0.get() }.as_ref()
}
pub unsafe fn get_mut(&self) -> Option<&mut T> {
unsafe { &mut *self.0.get() }.as_mut()
}
pub unsafe fn take(&self) -> Option<T> {
unsafe { &mut *self.0.get() }.take()
}
}
unsafe impl<T: Send> Send for UnsafeSyncOnceCell<T> {}
unsafe impl<T: Sync> Sync for UnsafeSyncOnceCell<T> {}
impl<T> Default for UnsafeSyncOnceCell<T> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct UnsafeSyncCell<T>(UnsafeCell<T>);
impl<T> UnsafeSyncCell<T> {
pub const fn new(val: T) -> Self {
UnsafeSyncCell(UnsafeCell::new(val))
}
pub unsafe fn get(&self) -> &T {
unsafe { &*self.0.get() }
}
#[allow(clippy::mut_from_ref)]
pub unsafe fn get_mut(&self) -> &mut T {
unsafe { &mut *self.0.get() }
}
}
unsafe impl<T: Send> Send for UnsafeSyncCell<T> {}
unsafe impl<T: Sync> Sync for UnsafeSyncCell<T> {}
#[cfg(test)]
mod tests {
use super::*;
fn check_sync_send(_s: impl Sync + Send) {
}
#[test]
fn once_cell_is_sync_send() {
let cell = UnsafeSyncOnceCell::<i32>::new();
check_sync_send(cell);
}
#[test]
fn cell_is_sync_send() {
let cell = UnsafeSyncCell::<i32>::new(4);
check_sync_send(cell);
}
}