use core::{
ops::{Deref, DerefMut},
sync::atomic::Ordering,
};
use portable_atomic::AtomicBool;
use crate::{const_init::ConstInit, uninit::GroundedCell};
pub struct AllocSingle<T> {
taken: AtomicBool,
storage: GroundedCell<T>,
}
impl<T> AllocSingle<T> {
pub const fn new() -> Self {
Self {
taken: AtomicBool::new(false),
storage: GroundedCell::uninit(),
}
}
#[inline]
pub fn alloc(&self, t: T) -> Option<SingleBox<'_, T>> {
if self.taken.swap(true, Ordering::AcqRel) {
return None;
}
let new = SingleBox { single: self };
unsafe {
new.as_ptr().write(t);
}
Some(new)
}
}
impl<T: ConstInit> AllocSingle<T> {
pub fn alloc_const_val(&self) -> Option<SingleBox<'_, T>> {
if self.taken.swap(true, Ordering::AcqRel) {
return None;
}
let new = SingleBox { single: self };
unsafe {
new.as_ptr().write(T::VAL);
}
Some(new)
}
}
pub struct SingleBox<'a, T> {
single: &'a AllocSingle<T>,
}
impl<'a, T> SingleBox<'a, T> {
fn as_ptr(&self) -> *mut T {
self.single.storage.get()
}
}
impl<'a, T> Drop for SingleBox<'a, T> {
fn drop(&mut self) {
unsafe { self.as_ptr().drop_in_place() }
self.single.taken.store(false, Ordering::Release);
}
}
impl<'a, T> Deref for SingleBox<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.as_ptr() }
}
}
impl<'a, T> DerefMut for SingleBox<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.as_ptr() }
}
}
#[cfg(test)]
pub mod test {
use super::AllocSingle;
use crate::const_init::ConstInit;
use core::ops::Deref;
#[derive(Debug)]
struct Demo([u8; 512]);
impl ConstInit for Demo {
const VAL: Self = Demo([44u8; 512]);
}
#[test]
fn smoke() {
static SINGLE: AllocSingle<[u8; 1024]> = AllocSingle::new();
static SINGLE_DEMO: AllocSingle<Demo> = AllocSingle::new();
{
let buf = [0xAF; 1024];
let mut bx = SINGLE.alloc(buf).unwrap();
println!("{:?}", bx.as_slice());
bx.iter_mut().for_each(|b| *b = 123);
println!("{:?}", bx.as_slice());
let buf2 = [0x01; 1024];
assert!(SINGLE.alloc(buf2).is_none());
}
let buf3 = [0x42; 1024];
let mut bx2 = SINGLE.alloc(buf3).unwrap();
println!("{:?}", bx2.as_slice());
bx2.iter_mut().for_each(|b| *b = 231);
println!("{:?}", bx2.as_slice());
let bx3 = SINGLE_DEMO.alloc_const_val().unwrap();
println!("{:?}", bx3.deref());
}
}