#![no_std]
#![no_main]
#![deny(missing_docs)]
use core::sync::atomic::{AtomicBool, Ordering};
const MAGIC_NUMBER: u32 = 0xFAB42069;
static mut PERSISTENT_BUFF_TAKEN: AtomicBool = AtomicBool::new(false);
pub struct PersistentBuff {
magic: *mut u32,
buff: &'static mut [u8],
}
impl PersistentBuff {
pub fn take_managed() -> Option<Self> {
Self::take_raw().map(|b| Self {
magic: b.as_mut_ptr().cast::<u32>(),
buff: &mut b[core::mem::size_of::<u32>()..],
})
}
pub unsafe fn steal_managed() -> Self {
let b = Self::steal();
Self {
magic: b.as_mut_ptr().cast::<u32>(),
buff: &mut b[core::mem::size_of::<u32>()..],
}
}
pub fn take_raw() -> Option<&'static mut [u8]> {
unsafe {
if PERSISTENT_BUFF_TAKEN.swap(true, Ordering::Relaxed) {
None
} else {
Some(Self::steal())
}
}
}
pub unsafe fn steal() -> &'static mut [u8] {
PERSISTENT_BUFF_TAKEN.store(true, Ordering::SeqCst);
extern "C" {
static mut _persistent_buff_start: u8;
static mut _persistent_buff_end: u8;
}
let start = &mut _persistent_buff_start as *mut u8;
let end = &mut _persistent_buff_end as *mut u8;
let len = end as usize - start as usize;
core::slice::from_raw_parts_mut(start, len)
}
fn mark(&mut self) {
unsafe {
self.magic.write_unaligned(MAGIC_NUMBER);
}
}
fn unmark(&mut self) {
unsafe {
self.magic.write_unaligned(0);
}
}
pub fn valid(&self) -> bool {
unsafe { self.magic.read_unaligned() == MAGIC_NUMBER }
}
pub fn take(self) -> Option<&'static mut [u8]> {
if self.valid() {
return Some(self.buff);
} else {
return None;
}
}
pub fn take_reset<F>(mut self, f: F) -> &'static mut [u8]
where
F: FnOnce(&mut [u8]),
{
f(self.buff);
self.mark();
self.buff
}
pub fn take_validate<F>(mut self, f: F) -> &'static mut [u8]
where
F: FnOnce(&mut [u8]),
{
if !self.valid() {
f(self.buff)
}
self.mark();
self.buff
}
pub fn get(&mut self) -> Option<&mut [u8]> {
if self.valid() {
return Some(self.buff);
} else {
return None;
}
}
pub fn reset<F>(&mut self, f: F) -> &mut [u8]
where
F: FnOnce(&mut [u8]),
{
f(self.buff);
self.mark();
self.buff
}
pub fn validate<F>(&mut self, f: F) -> &mut [u8]
where
F: FnOnce(&mut [u8]),
{
if !self.valid() {
f(self.buff)
}
self.mark();
self.buff
}
pub fn invalidate(&mut self) {
self.unmark();
}
}