1#[doc(hidden)]
2pub mod private {
3 use crate::TryDecodeLinkstore;
4 use core::{cell::UnsafeCell, mem::size_of};
5
6 pub use crate::embed::encode::MAGIC;
7
8 #[repr(transparent)]
9 pub struct VolatileWrapper<T: Sized>(UnsafeCell<T>);
10 impl<T: Sized> VolatileWrapper<T> {
11 #[doc(hidden)]
12 pub const fn new(val: T) -> Self {
13 Self(UnsafeCell::new(val))
14 }
15
16 #[doc(hidden)]
17 pub fn get(&'static self) -> &'static T {
18 unsafe {
19 core::mem::forget(core::ptr::read_volatile(self.0.get()));
20 &*self.0.get()
21 }
22 }
23 }
24 unsafe impl<T: TryDecodeLinkstore + Sized> Sync for VolatileWrapper<T> {}
25
26 pub const fn calc_padding<Container, T>(name: &'static str) -> usize
27 where
28 Container: Sized,
29 T: Sized,
30 {
31 size_of::<Container>() - (name.len() + 1 + 1) - (size_of::<usize>() * 2) - size_of::<T>()
32 }
33}
34
35#[cfg_attr(docsrs, doc(cfg(feature = "store")))]
59#[macro_export]
60macro_rules! linkstore {
61 {$($vis:vis static $name:ident: $ty:ty = $init:expr;)+} => {$(
62 #[allow(non_snake_case)]
63 $vis mod $name {
64 use ::core::mem::{size_of, align_of};
65 use $crate::__private::*;
66
67 const NAME: &'static str = stringify!($name);
68
69 #[repr(C)]
70 pub struct LinkStoreContainer<T: $crate::EncodeLinkstore> {
71 name: [u8; NAME.len() + 1 + 1],
72 size: [u8; size_of::<usize>()],
73 padding: [u8; size_of::<usize>()],
74 pub value: VolatileWrapper<T>
75 }
76
77 #[cfg_attr(target_os = "macos", link_section = "__TEXT,.lnkstre")]
78 #[cfg_attr(not(target_os = "macos"), link_section = ".lnkstre")]
79 #[used]
80 static $name: LinkStoreContainer<$ty> = LinkStoreContainer {
81 name: {
82 let mut static_bytes = [0u8; NAME.len() + 1 + 1];
83 static_bytes[0] = MAGIC;
84
85 let bytes = NAME.as_bytes();
86 let mut i = 0;
87 while i < NAME.len() {
88 static_bytes[i + 1] = bytes[i];
89 i += 1;
90 }
91
92 static_bytes
93 },
94
95 size: size_of::<$ty>().to_le_bytes(),
96 padding: calc_padding::<LinkStoreContainer<$ty>, $ty>(NAME).to_le_bytes(),
97
98 value: VolatileWrapper::new($init)
99 };
100
101 pub unsafe fn get() -> &'static $ty {
107 debug_assert_eq!(align_of::<LinkStoreContainer<$ty>>(), align_of::<$ty>(), "Alignment error - this is a bug with linkstore!");
108 $name.value.get()
109 }
110 }
111 )+};
112}