zng_unique_id/
hot_reload.rs
1#[macro_export]
21macro_rules! hot_static {
22 (
23 static $IDENT:ident: $Ty:ty = $init:expr;
24 ) => {
25 $crate::hot_reload::hot_static_impl! {
26 static $IDENT: $Ty = $init;
27 }
28 };
29}
30
31#[macro_export]
35macro_rules! hot_static_ref {
36 ($PATH:path) => {
37 $crate::hot_reload::hot_static_ref_impl!($PATH)
38 };
39}
40
41#[doc(hidden)]
42#[macro_export]
43macro_rules! hot_static_not_patchable {
44 (
45 static $IDENT:ident: $Ty:ty = $init:expr;
46 ) => {
47 static $IDENT: $Ty = $init;
48 };
49}
50#[doc(hidden)]
51#[macro_export]
52macro_rules! hot_static_patchable {
53 (
54 $vis:vis static $IDENT:ident: $Ty:ty = $init:expr;
55 ) => {
56 $crate::paste! {
57 struct [<_K $IDENT:camel>];
58 impl $crate::hot_reload::PatchKey for [<_K $IDENT:camel>] {
59 fn id(&'static self) -> &'static str {
60 std::any::type_name::<[<_K $IDENT:camel>]>()
61 }
62 }
63
64 static [<$IDENT _COLD>] : $Ty = $init;
65 #[allow(non_camel_case_types)]
66 static mut $IDENT: &$Ty = &[<$IDENT _COLD>];
67 #[allow(non_snake_case)]
68 unsafe fn [<$IDENT _INIT>](static_ptr: *const ()) -> *const () {
69 unsafe { $crate::hot_reload::init_static(&mut $IDENT, static_ptr) }
70 }
71
72 #[used]
77 #[cfg_attr(
78 any(
79 target_os = "none",
80 target_os = "linux",
81 target_os = "android",
82 target_os = "fuchsia",
83 target_os = "psp"
84 ),
85 unsafe(link_section = "linkme_HOT_STATICS")
86 )]
87 #[cfg_attr(
88 any(target_os = "macos", target_os = "ios", target_os = "tvos"),
89 unsafe(link_section = "__DATA,__linkmeAGDMMOwP,regular,no_dead_strip")
90 )]
91 #[cfg_attr(any(target_os = "uefi", target_os = "windows"), unsafe(link_section = ".linkme_HOT_STATICS$b"))]
92 #[cfg_attr(target_os = "illumos", unsafe(link_section = "set_linkme_HOT_STATICS"))]
93 #[cfg_attr(any(target_os = "freebsd", target_os = "openbsd"), unsafe(link_section = "linkme_HOT_STATICS"))]
94 #[doc(hidden)]
95 static [<$IDENT _REGISTER>]: (&'static dyn $crate::hot_reload::PatchKey, unsafe fn(*const ()) -> *const ()) = (
96 &[<_K $IDENT:camel>],
97 [<$IDENT _INIT>]
98 );
99
100 }
101 };
102}
103
104#[doc(hidden)]
105pub unsafe fn init_static<T>(s: &mut &'static T, static_ptr: *const ()) -> *const () {
106 if static_ptr.is_null() {
107 *s as *const T as *const ()
108 } else {
109 *s = unsafe { &*(static_ptr as *const T) };
110 std::ptr::null()
111 }
112}
113
114use std::{any::Any, fmt, ops};
115
116#[doc(hidden)]
117#[cfg(not(feature = "hot_reload"))]
118pub use crate::hot_static_not_patchable as hot_static_impl;
119
120#[doc(hidden)]
121#[cfg(feature = "hot_reload")]
122pub use crate::hot_static_patchable as hot_static_impl;
123
124#[doc(hidden)]
125#[macro_export]
126macro_rules! hot_static_ref_not_patchable {
127 ($PATH:path) => {
128 &$PATH
129 };
130}
131
132#[doc(hidden)]
133#[macro_export]
134macro_rules! hot_static_ref_patchable {
135 ($PATH:path) => {
136 unsafe { $PATH }
138 };
139}
140
141#[doc(hidden)]
142#[cfg(not(feature = "hot_reload"))]
143pub use crate::hot_static_ref_not_patchable as hot_static_ref_impl;
144
145#[doc(hidden)]
146#[cfg(feature = "hot_reload")]
147pub use crate::hot_static_ref_patchable as hot_static_ref_impl;
148
149#[doc(hidden)]
150#[cfg(feature = "hot_reload")]
151#[linkme::distributed_slice]
152pub static HOT_STATICS: [(&'static dyn PatchKey, unsafe fn(*const ()) -> *const ())];
153
154#[doc(hidden)]
155pub trait PatchKey: Send + Sync + Any {
156 fn id(&'static self) -> &'static str;
157}
158impl PartialEq for &'static dyn PatchKey {
159 fn eq(&self, other: &Self) -> bool {
160 self.id() == other.id()
161 }
162}
163impl Eq for &'static dyn PatchKey {}
164impl std::hash::Hash for &'static dyn PatchKey {
165 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
166 std::hash::Hash::hash(self.id(), state)
167 }
168}
169impl fmt::Debug for &'static dyn PatchKey {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 fmt::Debug::fmt(&self.id(), f)
172 }
173}
174
175#[doc(hidden)]
176pub use once_cell::sync::OnceCell as OnceCellLazy;
177
178#[doc(hidden)]
179pub struct Lazy<T: 'static> {
180 #[cfg(feature = "hot_reload")]
181 inner: fn(&mut Option<T>) -> &'static T,
182 #[cfg(not(feature = "hot_reload"))]
183 inner: (OnceCellLazy<T>, fn() -> T),
184}
185
186impl<T: 'static> Lazy<T> {
187 #[doc(hidden)]
188 #[cfg(feature = "hot_reload")]
189 pub const fn new(inner: fn(&mut Option<T>) -> &'static T) -> Self {
190 Self { inner }
191 }
192
193 #[doc(hidden)]
194 #[cfg(not(feature = "hot_reload"))]
195 pub const fn new(init: fn() -> T) -> Self {
196 Self {
197 inner: (OnceCellLazy::new(), init),
198 }
199 }
200}
201impl<T: 'static> ops::Deref for Lazy<T> {
202 type Target = T;
203
204 #[cfg(feature = "hot_reload")]
205 fn deref(&self) -> &Self::Target {
206 (self.inner)(&mut None)
207 }
208
209 #[cfg(not(feature = "hot_reload"))]
210 fn deref(&self) -> &Self::Target {
211 self.inner.0.get_or_init(|| (self.inner.1)())
212 }
213}
214
215pub fn lazy_static_init<T>(lazy_static: &'static Lazy<T>, value: T) -> Result<&'static T, T> {
219 let mut value = Some(value);
220
221 #[cfg(feature = "hot_reload")]
222 let r = (lazy_static.inner)(&mut value);
223 #[cfg(not(feature = "hot_reload"))]
224 let r = {
225 let (lazy, _) = &lazy_static.inner;
226 lazy.get_or_init(|| value.take().unwrap())
227 };
228
229 match value {
230 Some(v) => Err(v),
231 None => Ok(r),
232 }
233}
234
235#[doc(hidden)]
236#[cfg(feature = "hot_reload")]
237pub fn lazy_static_ref<T>(lazy_static: &'static OnceCellLazy<T>, init: fn() -> T, override_init: &mut Option<T>) -> &'static T {
238 lazy_static.get_or_init(|| match override_init.take() {
239 Some(o) => o,
240 None => init(),
241 })
242}
243
244#[macro_export]
250macro_rules! lazy_static {
251 ($(
252 $(#[$attr:meta])*
253 $vis:vis static ref $N:ident : $T:ty = $e:expr;
254 )+) => {
255 $(
256 $crate::hot_reload::lazy_static_impl! {
257 $(#[$attr])*
258 $vis static ref $N : $T = $e;
259 }
260 )+
261 };
262}
263
264#[doc(hidden)]
265#[macro_export]
266macro_rules! lazy_static_patchable {
267 (
268 $(#[$attr:meta])*
269 $vis:vis static ref $N:ident : $T:ty = $e:expr;
270 ) => {
271 $crate::paste! {
272 fn [<_ $N:lower _hot>](__override: &mut Option<$T>) -> &'static $T {
273 fn __init() -> $T {
274 $e
275 }
276 $crate::hot_static! {
277 static IMPL: $crate::hot_reload::OnceCellLazy<$T> = $crate::hot_reload::OnceCellLazy::new();
278 }
279 $crate::hot_reload::lazy_static_ref($crate::hot_static_ref!(IMPL), __init, __override)
280 }
281
282 $(#[$attr])*
283 $vis static $N: $crate::hot_reload::Lazy<$T> = $crate::hot_reload::Lazy::new([<_ $N:lower _hot>]);
284 }
285 };
286}
287
288#[doc(hidden)]
289#[macro_export]
290macro_rules! lazy_static_not_patchable {
291 (
292 $(#[$attr:meta])*
293 $vis:vis static ref $N:ident : $T:ty = $e:expr;
294 ) => {
295 $crate::paste! {
296 fn [<_ $N:lower _init>]() -> $T {
297 $e
298 }
299
300 $(#[$attr])*
301 $vis static $N: $crate::hot_reload::Lazy<$T> = $crate::hot_reload::Lazy::new([<_ $N:lower _init>]);
302 }
303 };
304}
305
306#[doc(hidden)]
307#[cfg(not(feature = "hot_reload"))]
308pub use crate::lazy_static_not_patchable as lazy_static_impl;
309
310#[doc(hidden)]
311#[cfg(feature = "hot_reload")]
312pub use crate::lazy_static_patchable as lazy_static_impl;