#[doc(hidden)]
pub mod private {
use crate::TryDecodeLinkstore;
use core::{cell::UnsafeCell, mem::size_of};
pub use crate::embed::encode::MAGIC;
#[repr(transparent)]
pub struct VolatileWrapper<T: Sized>(UnsafeCell<T>);
impl<T: Sized> VolatileWrapper<T> {
#[doc(hidden)]
pub const fn new(val: T) -> Self {
Self(UnsafeCell::new(val))
}
#[doc(hidden)]
pub fn get(&'static self) -> &'static T {
unsafe {
core::mem::forget(core::ptr::read_volatile(self.0.get()));
&*self.0.get()
}
}
}
unsafe impl<T: TryDecodeLinkstore + Sized> Sync for VolatileWrapper<T> {}
pub const fn calc_padding<Container, T>(name: &'static str) -> usize
where
Container: Sized,
T: Sized,
{
size_of::<Container>() - (name.len() + 1 + 1) - (size_of::<usize>() * 2) - size_of::<T>()
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "store")))]
#[macro_export]
macro_rules! linkstore {
{$($vis:vis static $name:ident: $ty:ty = $init:expr;)+} => {$(
#[allow(non_snake_case)]
$vis mod $name {
use ::core::mem::{size_of, align_of};
use $crate::__private::*;
const NAME: &'static str = stringify!($name);
#[repr(C)]
pub struct LinkStoreContainer<T: $crate::EncodeLinkstore> {
name: [u8; NAME.len() + 1 + 1],
size: [u8; size_of::<usize>()],
padding: [u8; size_of::<usize>()],
pub value: VolatileWrapper<T>
}
#[cfg_attr(target_os = "macos", link_section = "__TEXT,.lnkstre")]
#[cfg_attr(not(target_os = "macos"), link_section = ".lnkstre")]
#[used]
static $name: LinkStoreContainer<$ty> = LinkStoreContainer {
name: {
let mut static_bytes = [0u8; NAME.len() + 1 + 1];
static_bytes[0] = MAGIC;
let bytes = NAME.as_bytes();
let mut i = 0;
while i < NAME.len() {
static_bytes[i + 1] = bytes[i];
i += 1;
}
static_bytes
},
size: size_of::<$ty>().to_le_bytes(),
padding: calc_padding::<LinkStoreContainer<$ty>, $ty>(NAME).to_le_bytes(),
value: VolatileWrapper::new($init)
};
pub unsafe fn get() -> &'static $ty {
debug_assert_eq!(align_of::<LinkStoreContainer<$ty>>(), align_of::<$ty>(), "Alignment error - this is a bug with linkstore!");
$name.value.get()
}
}
)+};
}