#[doc = include_str!("../README.md")]
use std::fmt::Debug;
use std::fmt::Display;
use std::ops::{Deref, DerefMut};
use std::sync::OnceLock;
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Symbol {
pub file: &'static str,
pub line: u32,
pub column: u32,
pub module: &'static str,
pub ident: &'static str,
}
impl Display for Symbol {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} (at {}:{}:{})", self.ident, self.file, self.line, self.column)
}
}
#[macro_export]
macro_rules! Symbol {
($ident:ident) => {
&$crate::Symbol {
file: file!(),
line: line!(),
column: column!(),
module: module_path!(),
ident: stringify!($ident),
}
};
}
#[macro_export]
macro_rules! InitStatic {
($ident:ident) => {
$crate::InitStatic::new($crate::Symbol!($ident))
};
}
pub struct InitStatic<T> {
symbol: &'static Symbol,
inner: OnceLock<T>,
}
impl<T> InitStatic<T> {
#[inline]
pub const fn new(symbol: &'static Symbol) -> Self {
Self {
symbol,
inner: OnceLock::new(),
}
}
#[inline]
pub fn init(this: &Self, value: T) {
this.inner
.set(value)
.unwrap_or_else(|_| panic!("Double initialization of init_static: {}", this.symbol));
}
#[inline]
pub const fn symbol(this: &Self) -> &'static Symbol {
this.symbol
}
}
impl<T> Deref for InitStatic<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.inner
.get()
.unwrap_or_else(|| panic!("Access to uninitialized init_static: {}", self.symbol))
}
}
impl<T> DerefMut for InitStatic<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner
.get_mut()
.unwrap_or_else(|| panic!("Access to uninitialized init_static: {}", self.symbol))
}
}
impl<T: Debug> Debug for InitStatic<T> {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("InitStatic").field(&**self).finish()
}
}
impl<T: Display> Display for InitStatic<T> {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&**self, f)
}
}
pub trait MaybeInitStatic {
fn __get_symbol(&self) -> Option<&'static Symbol>;
}
impl<T> MaybeInitStatic for InitStatic<T> {
#[inline]
fn __get_symbol(&self) -> Option<&'static Symbol> {
Some(self.symbol)
}
}
impl<T> MaybeInitStatic for &T {
#[inline]
fn __get_symbol(&self) -> Option<&'static Symbol> {
None
}
}