zng_unique_id/
hot_reload.rs1#[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 #[$crate::hot_reload::__linkme::distributed_slice($crate::hot_reload::HOT_STATICS)]
74 #[linkme(crate=$crate::hot_reload::__linkme)]
75 #[doc(hidden)]
76 static [<$IDENT _REGISTER>]: (&'static dyn $crate::hot_reload::PatchKey, unsafe fn(*const ()) -> *const ()) = (
77 &[<_K $IDENT:camel>],
78 [<$IDENT _INIT>]
79 );
80
81 }
82 };
83}
84
85#[doc(hidden)]
86pub unsafe fn init_static<T>(s: &mut &'static T, static_ptr: *const ()) -> *const () {
87 if static_ptr.is_null() {
88 *s as *const T as *const ()
89 } else {
90 *s = unsafe { &*(static_ptr as *const T) };
91 std::ptr::null()
92 }
93}
94
95use std::{any::Any, fmt, ops};
96
97#[doc(hidden)]
98#[cfg(feature = "hot_reload")]
99pub use linkme as __linkme;
100
101#[doc(hidden)]
102#[cfg(not(feature = "hot_reload"))]
103pub use crate::hot_static_not_patchable as hot_static_impl;
104
105#[doc(hidden)]
106#[cfg(feature = "hot_reload")]
107pub use crate::hot_static_patchable as hot_static_impl;
108
109#[doc(hidden)]
110#[macro_export]
111macro_rules! hot_static_ref_not_patchable {
112 ($PATH:path) => {
113 &$PATH
114 };
115}
116
117#[doc(hidden)]
118#[macro_export]
119macro_rules! hot_static_ref_patchable {
120 ($PATH:path) => {
121 unsafe { $PATH }
123 };
124}
125
126#[doc(hidden)]
127#[cfg(not(feature = "hot_reload"))]
128pub use crate::hot_static_ref_not_patchable as hot_static_ref_impl;
129
130#[doc(hidden)]
131#[cfg(feature = "hot_reload")]
132pub use crate::hot_static_ref_patchable as hot_static_ref_impl;
133
134#[doc(hidden)]
135#[cfg(feature = "hot_reload")]
136#[linkme::distributed_slice]
137pub static HOT_STATICS: [(&'static dyn PatchKey, unsafe fn(*const ()) -> *const ())];
138
139#[doc(hidden)]
140pub trait PatchKey: Send + Sync + Any {
141 fn id(&'static self) -> &'static str;
142}
143impl PartialEq for &'static dyn PatchKey {
144 fn eq(&self, other: &Self) -> bool {
145 self.id() == other.id()
146 }
147}
148impl Eq for &'static dyn PatchKey {}
149impl std::hash::Hash for &'static dyn PatchKey {
150 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
151 std::hash::Hash::hash(self.id(), state)
152 }
153}
154impl fmt::Debug for &'static dyn PatchKey {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 fmt::Debug::fmt(&self.id(), f)
157 }
158}
159
160#[doc(hidden)]
161pub use once_cell::sync::OnceCell as OnceCellLazy;
162
163#[doc(hidden)]
164pub struct Lazy<T: 'static> {
165 #[cfg(feature = "hot_reload")]
166 inner: fn(&mut Option<T>) -> &'static T,
167 #[cfg(not(feature = "hot_reload"))]
168 inner: (OnceCellLazy<T>, fn() -> T),
169}
170
171impl<T: 'static> Lazy<T> {
172 #[doc(hidden)]
173 #[cfg(feature = "hot_reload")]
174 pub const fn new(inner: fn(&mut Option<T>) -> &'static T) -> Self {
175 Self { inner }
176 }
177
178 #[doc(hidden)]
179 #[cfg(not(feature = "hot_reload"))]
180 pub const fn new(init: fn() -> T) -> Self {
181 Self {
182 inner: (OnceCellLazy::new(), init),
183 }
184 }
185}
186impl<T: 'static> ops::Deref for Lazy<T> {
187 type Target = T;
188
189 #[cfg(feature = "hot_reload")]
190 fn deref(&self) -> &Self::Target {
191 (self.inner)(&mut None)
192 }
193
194 #[cfg(not(feature = "hot_reload"))]
195 fn deref(&self) -> &Self::Target {
196 self.inner.0.get_or_init(|| (self.inner.1)())
197 }
198}
199
200pub fn lazy_static_init<T>(lazy_static: &'static Lazy<T>, value: T) -> Result<&'static T, T> {
204 let mut value = Some(value);
205
206 #[cfg(feature = "hot_reload")]
207 let r = (lazy_static.inner)(&mut value);
208 #[cfg(not(feature = "hot_reload"))]
209 let r = {
210 let (lazy, _) = &lazy_static.inner;
211 lazy.get_or_init(|| value.take().unwrap())
212 };
213
214 match value {
215 Some(v) => Err(v),
216 None => Ok(r),
217 }
218}
219
220#[doc(hidden)]
221#[cfg(feature = "hot_reload")]
222pub fn lazy_static_ref<T>(lazy_static: &'static OnceCellLazy<T>, init: fn() -> T, override_init: &mut Option<T>) -> &'static T {
223 lazy_static.get_or_init(|| match override_init.take() {
224 Some(o) => o,
225 None => init(),
226 })
227}
228
229#[macro_export]
235macro_rules! lazy_static {
236 ($(
237 $(#[$attr:meta])*
238 $vis:vis static ref $N:ident : $T:ty = $e:expr;
239 )+) => {
240 $(
241 $crate::hot_reload::lazy_static_impl! {
242 $(#[$attr])*
243 $vis static ref $N : $T = $e;
244 }
245 )+
246 };
247}
248
249#[doc(hidden)]
250#[macro_export]
251macro_rules! lazy_static_patchable {
252 (
253 $(#[$attr:meta])*
254 $vis:vis static ref $N:ident : $T:ty = $e:expr;
255 ) => {
256 $crate::paste! {
257 fn [<_ $N:lower _hot>](__override: &mut Option<$T>) -> &'static $T {
258 fn __init() -> $T {
259 $e
260 }
261 $crate::hot_static! {
262 static IMPL: $crate::hot_reload::OnceCellLazy<$T> = $crate::hot_reload::OnceCellLazy::new();
263 }
264 $crate::hot_reload::lazy_static_ref($crate::hot_static_ref!(IMPL), __init, __override)
265 }
266
267 $(#[$attr])*
268 $vis static $N: $crate::hot_reload::Lazy<$T> = $crate::hot_reload::Lazy::new([<_ $N:lower _hot>]);
269 }
270 };
271}
272
273#[doc(hidden)]
274#[macro_export]
275macro_rules! lazy_static_not_patchable {
276 (
277 $(#[$attr:meta])*
278 $vis:vis static ref $N:ident : $T:ty = $e:expr;
279 ) => {
280 $crate::paste! {
281 fn [<_ $N:lower _init>]() -> $T {
282 $e
283 }
284
285 $(#[$attr])*
286 $vis static $N: $crate::hot_reload::Lazy<$T> = $crate::hot_reload::Lazy::new([<_ $N:lower _init>]);
287 }
288 };
289}
290
291#[doc(hidden)]
292#[cfg(not(feature = "hot_reload"))]
293pub use crate::lazy_static_not_patchable as lazy_static_impl;
294
295#[doc(hidden)]
296#[cfg(feature = "hot_reload")]
297pub use crate::lazy_static_patchable as lazy_static_impl;