use core::ptr::null_mut;
use core::sync::atomic::{AtomicPtr, Ordering};
pub static ERROR_REGISTRY: ErrorRegistry = ErrorRegistry::new();
pub struct ErrorRegistry {
error: AtomicPtr<()>,
}
impl ErrorRegistry {
pub const fn new() -> Self {
Self {
error: AtomicPtr::new(null_mut()),
}
}
pub fn store<E>(&self, error: E) {
#[cfg(feature = "std")]
{
use std::boxed::Box;
let boxed = Box::into_raw(Box::new(error));
let old = self.error.swap(boxed as *mut (), Ordering::SeqCst);
if !old.is_null() {
unsafe {
drop(Box::from_raw(old));
}
}
}
#[cfg(not(feature = "std"))]
{
let _ = error; self.error.store(1 as *mut (), Ordering::SeqCst);
}
}
pub fn clear(&self) {
#[cfg(feature = "std")]
{
let ptr = self.error.swap(null_mut(), Ordering::SeqCst);
if !ptr.is_null() {
unsafe {
drop(Box::from_raw(ptr));
}
}
}
#[cfg(not(feature = "std"))]
{
self.error.store(null_mut(), Ordering::SeqCst);
}
}
pub fn has_error(&self) -> bool {
!self.error.load(Ordering::SeqCst).is_null()
}
#[cfg(feature = "std")]
pub fn get_error<E: Clone>(&self) -> Option<E> {
let ptr = self.error.load(Ordering::SeqCst);
if ptr.is_null() {
None
} else {
unsafe {
let error_ref = &*(ptr as *const E);
Some(error_ref.clone())
}
}
}
}
impl Default for ErrorRegistry {
fn default() -> Self {
Self::new()
}
}
impl Drop for ErrorRegistry {
fn drop(&mut self) {
self.clear();
}
}