I am basically a beginner, so I Wrote some code that implements a zero cost singleton, through it will crash your program if you have a MMU.
use core::cell::UnsafeCell;
use core::mem::{size_of, transmute, MaybeUninit};
/// This type is mean to Static allocation of variables that should life all the program's life
/// without modification more than once in the initialization.
/// **NOTE:** Very unsafe thing to do.
#[repr(transparent)]
pub struct StaticOnce<'a, T: Sized + Sync>(UnsafeCell<MaybeUninit<&'a T>>);
// This is safe because the user must only use the transmute function once in the entire program runlife.
unsafe impl<'a, T: Sized + Sync> Sync for StaticOnce<'a, T> {}
impl<'a, T: Sized + Sync> StaticOnce<'a, T> {
pub const fn new() -> Self {
const SIZE: usize = size_of::<usize>();
let space = [0u8; SIZE];
// This is safe bacause the transmute converts a array of the same length as the pointer
// (given that pointers have length usize), to a pointer trougth is wrapped in a tranparent
// MaybeUninit that is wrapped in a UnsafeCell to allow mutability for once in the
// entire length of the program runlife.
Self(unsafe { transmute::<[u8; SIZE], UnsafeCell<MaybeUninit<&T>>>(space) })
}
/// Geter of the contents of the singelton.
/// **NOTE**: Never call before initialization or it may crash the program and will have undefined
/// behaviour.
#[inline(always)]
pub fn get(&self) -> &T {
// This is safe because the contents of the singleton were unitialized (if the user follow the
// intructions), so the pointer container by the UnsafeCell will be vaid, and will be
// right configured in a valid address.
let maybe = &(unsafe { *UnsafeCell::get(&self.0) }) as &MaybeUninit<&T>;
// This is true because the user following the intruction of initialized with transmute before
// celling the getter makes the content of the MaybeUninit valid for when this is called.
unsafe { maybe.assume_init() }
}
/// This is supposed toonly be called once in the program initialization.
/// **NOTE**: Very unsafe thing to do.
// This is safe because StaitcOnce::transmute is safe, and the user follow the instructions
// of call this before anything and only once.
pub unsafe fn transmute(&self, item: T) {
StaticOnce::transmute_inner(self, item)
}
fn transmute_inner(self_: &Self, item: T) {
// This is safe beacause (1) this is just make once in the entire program runlife, and (2) the
// typecast reduce to the correct one.
let ptr: &mut MaybeUninit<&T> = &mut unsafe { *UnsafeCell::get(&self_.0) };
// This is safe because we get by compilation the space fo the pointer already allocated, just
// is needed to initialize it.
let ptr: &mut &T = &mut unsafe { *ptr.as_mut_ptr() };
*ptr = &item;
}
}