zng_app_context/
lib.rs

1#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo.png")]
3//! App execution context.
4//!
5//! # Crate
6//!
7#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
8#![warn(unused_extern_crates)]
9#![warn(missing_docs)]
10
11use std::{any::Any, cell::RefCell, fmt, mem, ops, sync::Arc, thread::LocalKey, time::Duration};
12
13use parking_lot::*;
14use zng_txt::Txt;
15use zng_unique_id::unique_id_32;
16
17#[doc(hidden)]
18pub use zng_unique_id::{hot_static, hot_static_ref};
19
20unique_id_32! {
21    /// Identifies an app instance.
22    pub struct AppId;
23}
24zng_unique_id::impl_unique_id_name!(AppId);
25zng_unique_id::impl_unique_id_fmt!(AppId);
26zng_unique_id::impl_unique_id_bytemuck!(AppId);
27
28impl serde::Serialize for AppId {
29    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
30    where
31        S: serde::Serializer,
32    {
33        let name = self.name();
34        if name.is_empty() {
35            use serde::ser::Error;
36            return Err(S::Error::custom("cannot serialize unnamed `AppId`"));
37        }
38        name.serialize(serializer)
39    }
40}
41impl<'de> serde::Deserialize<'de> for AppId {
42    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
43    where
44        D: serde::Deserializer<'de>,
45    {
46        let name = Txt::deserialize(deserializer)?;
47        Ok(AppId::named(name))
48    }
49}
50
51#[derive(Clone, Copy)]
52enum LocalValueKind {
53    Local,
54    Var,
55    App,
56}
57impl LocalValueKind {
58    /// Include in local captures.
59    fn include_local(self) -> bool {
60        !matches!(self, Self::Var)
61    }
62
63    /// Include in var captures.
64    fn include_var(self) -> bool {
65        !matches!(self, Self::Local)
66    }
67}
68
69/// `(value, is_context_var)`
70type LocalValue = (Arc<dyn Any + Send + Sync>, LocalValueKind);
71// equivalent to rustc_hash::FxHashMap, but can be constructed in `const`.
72type LocalData = std::collections::HashMap<AppLocalId, LocalValue, BuildFxHasher>;
73#[derive(Clone, Default)]
74struct BuildFxHasher;
75impl std::hash::BuildHasher for BuildFxHasher {
76    type Hasher = rustc_hash::FxHasher;
77
78    fn build_hasher(&self) -> Self::Hasher {
79        rustc_hash::FxHasher::default()
80    }
81}
82const fn new_local_data() -> LocalData {
83    LocalData::with_hasher(BuildFxHasher)
84}
85
86type LocalSet = std::collections::HashSet<AppLocalId, BuildFxHasher>;
87const fn new_local_set() -> LocalSet {
88    LocalSet::with_hasher(BuildFxHasher)
89}
90
91/// Represents an app lifetime, ends the app on drop.
92///
93/// You can use [`LocalContext::start_app`] to manually create an app scope without actually running an app.
94#[must_use = "ends the app scope on drop"]
95pub struct AppScope {
96    id: AppId,
97    _same_thread: std::rc::Rc<()>,
98}
99impl Drop for AppScope {
100    fn drop(&mut self) {
101        LocalContext::end_app(self.id);
102    }
103}
104
105impl AppId {
106    fn local_id() -> AppLocalId {
107        hot_static! {
108            static ID: u8 = 0;
109        }
110        AppLocalId(hot_static_ref!(ID) as *const u8 as *const () as _)
111    }
112}
113fn cleanup_list_id() -> AppLocalId {
114    hot_static! {
115        static ID: u8 = 0;
116    }
117    AppLocalId(hot_static_ref!(ID) as *const u8 as *const () as _)
118}
119
120/// Tracks the current execution context.
121///
122/// The context tracks the current app, all or some [`context_local!`] and [`TracingDispatcherContext`].
123#[derive(Clone)]
124pub struct LocalContext {
125    data: LocalData,
126    tracing: Option<tracing::dispatcher::Dispatch>,
127}
128impl fmt::Debug for LocalContext {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        let app = self
131            .data
132            .get(&AppId::local_id())
133            .map(|(v, _)| v.downcast_ref::<AppId>().unwrap())
134            .copied();
135
136        f.debug_struct("LocalContext")
137            .field("<app>", &app)
138            .field("<entries>", &(self.data.len() - 1))
139            .finish()
140    }
141}
142impl Default for LocalContext {
143    fn default() -> Self {
144        Self::new()
145    }
146}
147impl LocalContext {
148    /// New empty context.
149    pub const fn new() -> Self {
150        Self {
151            data: new_local_data(),
152            tracing: None,
153        }
154    }
155
156    /// Start an app scope in the current thread.
157    pub fn start_app(id: AppId) -> AppScope {
158        let valid = LOCAL.with_borrow_mut_dyn(|c| match c.entry(AppId::local_id()) {
159            std::collections::hash_map::Entry::Occupied(_) => false,
160            std::collections::hash_map::Entry::Vacant(e) => {
161                e.insert((Arc::new(id), LocalValueKind::App));
162                true
163            }
164        });
165        assert!(valid, "cannot start app, another app is already in the thread context");
166
167        AppScope {
168            id,
169            _same_thread: std::rc::Rc::new(()),
170        }
171    }
172    fn end_app(id: AppId) {
173        let valid = LOCAL.with_borrow_mut_dyn(|c| {
174            if c.get(&AppId::local_id())
175                .map(|(v, _)| v.downcast_ref::<AppId>() == Some(&id))
176                .unwrap_or(false)
177            {
178                Some(mem::take(&mut *c))
179            } else {
180                None
181            }
182        });
183
184        if let Some(data) = valid {
185            // SAFETY: app resources may leak, but we terminate the process
186            let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || {
187                drop(data); // deinit
188            }));
189            if let Err(p) = r {
190                tracing::error!("panic on app drop. {}", panic_str(&p));
191                eprintln!("panic on app drop. {}", panic_str(&p));
192                zng_env::exit(i32::from_le_bytes(*b"appa"));
193            }
194        } else {
195            tracing::error!("can only drop app in one of its threads");
196            eprintln!("can only drop app in one of its threads");
197            zng_env::exit(i32::from_le_bytes(*b"appa"));
198        }
199    }
200
201    /// Get the ID of the app that owns the current context.
202    pub fn current_app() -> Option<AppId> {
203        LOCAL.with_borrow_dyn(|c| c.get(&AppId::local_id()).map(|(v, _)| v.downcast_ref::<AppId>().unwrap()).copied())
204    }
205
206    /// Register to run when the app deinits and all clones of the app context are dropped.
207    pub fn register_cleanup(cleanup: impl FnOnce(AppId) + Send + 'static) {
208        let id = Self::current_app().expect("no app in context");
209        Self::register_cleanup_dyn(Box::new(move || cleanup(id)));
210    }
211    fn register_cleanup_dyn(cleanup: Box<dyn FnOnce() + Send>) {
212        let cleanup = RunOnDrop::new(cleanup);
213
214        type CleanupList = Vec<RunOnDrop<Box<dyn FnOnce() + Send>>>;
215        LOCAL.with_borrow_mut_dyn(|c| {
216            let c = c
217                .entry(cleanup_list_id())
218                .or_insert_with(|| (Arc::new(Mutex::new(CleanupList::new())), LocalValueKind::App));
219            c.0.downcast_ref::<Mutex<CleanupList>>().unwrap().lock().push(cleanup);
220        });
221    }
222
223    /// Capture a snapshot of the current context that can be restored in another thread to recreate
224    /// the current context.
225    ///
226    /// Context locals modified after this capture are not included in the capture.
227    ///
228    /// This is equivalent to [``CaptureFilter::All`].
229    pub fn capture() -> Self {
230        Self {
231            data: LOCAL.with_borrow_dyn(|c| c.clone()),
232            tracing: Some(tracing::dispatcher::get_default(|d| d.clone())),
233        }
234    }
235
236    /// Capture a snapshot of the current context that only includes `filter`.
237    pub fn capture_filtered(filter: CaptureFilter) -> Self {
238        match filter {
239            CaptureFilter::None => Self::new(),
240            CaptureFilter::All => Self::capture(),
241            CaptureFilter::ContextVars { exclude } => {
242                let mut data = new_local_data();
243                LOCAL.with_borrow_dyn(|c| {
244                    for (k, (v, kind)) in c.iter() {
245                        if kind.include_var() && !exclude.0.contains(k) {
246                            data.insert(*k, (v.clone(), *kind));
247                        }
248                    }
249                });
250                Self { data, tracing: None }
251            }
252            CaptureFilter::ContextLocals { exclude } => {
253                let mut data = new_local_data();
254                LOCAL.with_borrow_dyn(|c| {
255                    for (k, (v, kind)) in c.iter() {
256                        if kind.include_local() && !exclude.0.contains(k) {
257                            data.insert(*k, (v.clone(), *kind));
258                        }
259                    }
260                });
261                Self {
262                    data,
263                    tracing: Some(tracing::dispatcher::get_default(|d| d.clone())),
264                }
265            }
266            CaptureFilter::Include(set) => {
267                let mut data = new_local_data();
268                LOCAL.with_borrow_dyn(|c| {
269                    for (k, v) in c.iter() {
270                        if set.0.contains(k) {
271                            data.insert(*k, v.clone());
272                        }
273                    }
274                });
275                Self {
276                    data,
277                    tracing: if set.contains(&TracingDispatcherContext) {
278                        Some(tracing::dispatcher::get_default(|d| d.clone()))
279                    } else {
280                        None
281                    },
282                }
283            }
284            CaptureFilter::Exclude(set) => {
285                let mut data = new_local_data();
286                LOCAL.with_borrow_dyn(|c| {
287                    for (k, v) in c.iter() {
288                        if !set.0.contains(k) {
289                            data.insert(*k, v.clone());
290                        }
291                    }
292                });
293                Self {
294                    data,
295                    tracing: if !set.contains(&TracingDispatcherContext) {
296                        Some(tracing::dispatcher::get_default(|d| d.clone()))
297                    } else {
298                        None
299                    },
300                }
301            }
302        }
303    }
304
305    /// Collects a set of all the values in the context.
306    pub fn value_set(&self) -> ContextValueSet {
307        let mut set = ContextValueSet::new();
308        LOCAL.with_borrow_dyn(|c| {
309            for k in c.keys() {
310                set.0.insert(*k);
311            }
312        });
313        set
314    }
315
316    /// Calls `f` in the captured context.
317    ///
318    /// Note that this fully replaces the parent context for the duration of the `f` call, see [`with_context_blend`]
319    /// for a blending alternative.
320    ///
321    /// [`with_context_blend`]: Self::with_context_blend
322    pub fn with_context<R>(&mut self, f: impl FnOnce() -> R) -> R {
323        let data = mem::take(&mut self.data);
324        let prev = LOCAL.with_borrow_mut_dyn(|c| mem::replace(c, data));
325        let _tracing_restore = self.tracing.as_ref().map(tracing::dispatcher::set_default);
326        let _restore = RunOnDrop::new(|| {
327            self.data = LOCAL.with_borrow_mut_dyn(|c| mem::replace(c, prev));
328        });
329        f()
330    }
331
332    /// Calls `f` while all contextual values of `self` are set on the parent context.
333    ///
334    /// Unlike [`with_context`] this does not remove values that are only set in the parent context, the
335    /// downside is that this call is more expensive.
336    ///
337    /// If `over` is `true` all the values of `self` are set over the parent values, if `false` only
338    /// the values not already set in the parent are set.
339    ///
340    /// [`with_context`]: Self::with_context
341    pub fn with_context_blend<R>(&mut self, over: bool, f: impl FnOnce() -> R) -> R {
342        if self.data.is_empty() {
343            f()
344        } else {
345            let prev = LOCAL.with_borrow_mut_dyn(|c| {
346                let (mut base, over) = if over { (c.clone(), &self.data) } else { (self.data.clone(), &*c) };
347                for (k, v) in over {
348                    base.insert(*k, v.clone());
349                }
350
351                mem::replace(c, base)
352            });
353            let _restore = RunOnDrop::new(|| {
354                LOCAL.with_borrow_mut_dyn(|c| {
355                    *c = prev;
356                });
357            });
358            f()
359        }
360    }
361
362    /// Blend `ctx` over `self`.
363    pub fn extend(&mut self, ctx: Self) {
364        self.data.extend(ctx.data);
365    }
366
367    fn contains(key: AppLocalId) -> bool {
368        LOCAL.with_borrow_dyn(|c| c.contains_key(&key))
369    }
370
371    fn get(key: AppLocalId) -> Option<LocalValue> {
372        LOCAL.with_borrow_dyn(|c| c.get(&key).cloned())
373    }
374
375    fn set(key: AppLocalId, value: LocalValue) -> Option<LocalValue> {
376        LOCAL.with_borrow_mut_dyn(|c| c.insert(key, value))
377    }
378    fn remove(key: AppLocalId) -> Option<LocalValue> {
379        LOCAL.with_borrow_mut_dyn(|c| c.remove(&key))
380    }
381
382    fn with_value_ctx<T: Send + Sync + 'static>(
383        key: &'static ContextLocal<T>,
384        kind: LocalValueKind,
385        value: &mut Option<Arc<T>>,
386        f: impl FnOnce(),
387    ) {
388        let key = key.id();
389        let prev = Self::set(key, (value.take().expect("no `value` to set"), kind));
390        let _restore = RunOnDrop::new(move || {
391            let back = if let Some(prev) = prev {
392                Self::set(key, prev)
393            } else {
394                Self::remove(key)
395            }
396            .unwrap();
397            *value = Some(Arc::downcast(back.0).unwrap());
398        });
399
400        f();
401    }
402
403    fn with_default_ctx<T: Send + Sync + 'static>(key: &'static ContextLocal<T>, f: impl FnOnce()) {
404        let key = key.id();
405        let prev = Self::remove(key);
406        let _restore = RunOnDrop::new(move || {
407            if let Some(prev) = prev {
408                Self::set(key, prev);
409            }
410        });
411
412        f()
413    }
414}
415thread_local! {
416    static LOCAL: RefCell<LocalData> = const { RefCell::new(new_local_data()) };
417}
418
419trait LocalKeyDyn {
420    fn with_borrow_dyn<R>(&'static self, f: impl FnOnce(&LocalData) -> R) -> R;
421    fn with_borrow_mut_dyn<R>(&'static self, f: impl FnOnce(&mut LocalData) -> R) -> R;
422}
423impl LocalKeyDyn for LocalKey<RefCell<LocalData>> {
424    fn with_borrow_dyn<R>(&'static self, f: impl FnOnce(&LocalData) -> R) -> R {
425        let mut r = None;
426        let f = |l: &LocalData| r = Some(f(l));
427
428        #[cfg(feature = "dyn_closure")]
429        let f: Box<dyn FnOnce(&LocalData)> = Box::new(f);
430
431        self.with_borrow(f);
432
433        r.unwrap()
434    }
435
436    fn with_borrow_mut_dyn<R>(&'static self, f: impl FnOnce(&mut LocalData) -> R) -> R {
437        let mut r = None;
438        let f = |l: &mut LocalData| r = Some(f(l));
439
440        #[cfg(feature = "dyn_closure")]
441        let f: Box<dyn FnOnce(&mut LocalData)> = Box::new(f);
442
443        self.with_borrow_mut(f);
444
445        r.unwrap()
446    }
447}
448
449/*
450    app_local!
451*/
452
453#[doc(hidden)]
454pub struct AppLocalConst<T: Send + Sync + 'static> {
455    value: RwLock<T>,
456}
457impl<T: Send + Sync + 'static> AppLocalConst<T> {
458    pub const fn new(init: T) -> Self {
459        Self { value: RwLock::new(init) }
460    }
461}
462#[doc(hidden)]
463pub struct AppLocalOption<T: Send + Sync + 'static> {
464    value: RwLock<Option<T>>,
465    init: fn() -> T,
466}
467impl<T: Send + Sync + 'static> AppLocalOption<T> {
468    pub const fn new(init: fn() -> T) -> Self {
469        Self {
470            value: RwLock::new(None),
471            init,
472        }
473    }
474
475    fn read_impl(&'static self, read: RwLockReadGuard<'static, Option<T>>) -> MappedRwLockReadGuard<'static, T> {
476        if read.is_some() {
477            return RwLockReadGuard::map(read, |v| v.as_ref().unwrap());
478        }
479        drop(read);
480
481        let mut write = self.value.write();
482        if write.is_some() {
483            drop(write);
484            return self.read();
485        }
486
487        let value = (self.init)();
488        *write = Some(value);
489
490        let read = RwLockWriteGuard::downgrade(write);
491
492        RwLockReadGuard::map(read, |v| v.as_ref().unwrap())
493    }
494
495    fn write_impl(&'static self, mut write: RwLockWriteGuard<'static, Option<T>>) -> MappedRwLockWriteGuard<'static, T> {
496        if write.is_some() {
497            return RwLockWriteGuard::map(write, |v| v.as_mut().unwrap());
498        }
499
500        let value = (self.init)();
501        *write = Some(value);
502
503        RwLockWriteGuard::map(write, |v| v.as_mut().unwrap())
504    }
505}
506
507#[doc(hidden)]
508pub struct AppLocalVec<T: Send + Sync + 'static> {
509    value: RwLock<Vec<(AppId, T)>>,
510    init: fn() -> T,
511}
512impl<T: Send + Sync + 'static> AppLocalVec<T> {
513    pub const fn new(init: fn() -> T) -> Self {
514        Self {
515            value: RwLock::new(vec![]),
516            init,
517        }
518    }
519
520    fn cleanup(&'static self, id: AppId) {
521        self.try_cleanup(id, 0);
522    }
523    fn try_cleanup(&'static self, id: AppId, tries: u8) {
524        if let Some(mut w) = self.value.try_write_for(if tries == 0 {
525            Duration::from_millis(50)
526        } else {
527            Duration::from_millis(500)
528        }) {
529            if let Some(i) = w.iter().position(|(s, _)| *s == id) {
530                w.swap_remove(i);
531            }
532        } else if tries > 5 {
533            tracing::error!("failed to cleanup `app_local` for {id:?}, was locked after app drop");
534        } else {
535            std::thread::spawn(move || {
536                self.try_cleanup(id, tries + 1);
537            });
538        }
539    }
540
541    fn read_impl(&'static self, read: RwLockReadGuard<'static, Vec<(AppId, T)>>) -> MappedRwLockReadGuard<'static, T> {
542        let id = LocalContext::current_app().expect("no app running, `app_local` can only be accessed inside apps");
543
544        if let Some(i) = read.iter().position(|(s, _)| *s == id) {
545            return RwLockReadGuard::map(read, |v| &v[i].1);
546        }
547        drop(read);
548
549        let mut write = self.value.write();
550        if write.iter().any(|(s, _)| *s == id) {
551            drop(write);
552            return self.read();
553        }
554
555        let value = (self.init)();
556        let i = write.len();
557        write.push((id, value));
558
559        LocalContext::register_cleanup(Box::new(move |id| self.cleanup(id)));
560
561        let read = RwLockWriteGuard::downgrade(write);
562
563        RwLockReadGuard::map(read, |v| &v[i].1)
564    }
565
566    fn write_impl(&'static self, mut write: RwLockWriteGuard<'static, Vec<(AppId, T)>>) -> MappedRwLockWriteGuard<'static, T> {
567        let id = LocalContext::current_app().expect("no app running, `app_local` can only be accessed inside apps");
568
569        if let Some(i) = write.iter().position(|(s, _)| *s == id) {
570            return RwLockWriteGuard::map(write, |v| &mut v[i].1);
571        }
572
573        let value = (self.init)();
574        let i = write.len();
575        write.push((id, value));
576
577        LocalContext::register_cleanup(move |id| self.cleanup(id));
578
579        RwLockWriteGuard::map(write, |v| &mut v[i].1)
580    }
581}
582#[doc(hidden)]
583pub trait AppLocalImpl<T: Send + Sync + 'static>: Send + Sync + 'static {
584    fn read(&'static self) -> MappedRwLockReadGuard<'static, T>;
585    fn try_read(&'static self) -> Option<MappedRwLockReadGuard<'static, T>>;
586    fn write(&'static self) -> MappedRwLockWriteGuard<'static, T>;
587    fn try_write(&'static self) -> Option<MappedRwLockWriteGuard<'static, T>>;
588}
589
590impl<T: Send + Sync + 'static> AppLocalImpl<T> for AppLocalVec<T> {
591    fn read(&'static self) -> MappedRwLockReadGuard<'static, T> {
592        self.read_impl(self.value.read_recursive())
593    }
594
595    fn try_read(&'static self) -> Option<MappedRwLockReadGuard<'static, T>> {
596        Some(self.read_impl(self.value.try_read_recursive()?))
597    }
598
599    fn write(&'static self) -> MappedRwLockWriteGuard<'static, T> {
600        self.write_impl(self.value.write())
601    }
602
603    fn try_write(&'static self) -> Option<MappedRwLockWriteGuard<'static, T>> {
604        Some(self.write_impl(self.value.try_write()?))
605    }
606}
607impl<T: Send + Sync + 'static> AppLocalImpl<T> for AppLocalOption<T> {
608    fn read(&'static self) -> MappedRwLockReadGuard<'static, T> {
609        self.read_impl(self.value.read_recursive())
610    }
611
612    fn try_read(&'static self) -> Option<MappedRwLockReadGuard<'static, T>> {
613        Some(self.read_impl(self.value.try_read_recursive()?))
614    }
615
616    fn write(&'static self) -> MappedRwLockWriteGuard<'static, T> {
617        self.write_impl(self.value.write())
618    }
619
620    fn try_write(&'static self) -> Option<MappedRwLockWriteGuard<'static, T>> {
621        Some(self.write_impl(self.value.try_write()?))
622    }
623}
624impl<T: Send + Sync + 'static> AppLocalImpl<T> for AppLocalConst<T> {
625    fn read(&'static self) -> MappedRwLockReadGuard<'static, T> {
626        RwLockReadGuard::map(self.value.read(), |l| l)
627    }
628
629    fn try_read(&'static self) -> Option<MappedRwLockReadGuard<'static, T>> {
630        Some(RwLockReadGuard::map(self.value.try_read()?, |l| l))
631    }
632
633    fn write(&'static self) -> MappedRwLockWriteGuard<'static, T> {
634        RwLockWriteGuard::map(self.value.write(), |l| l)
635    }
636
637    fn try_write(&'static self) -> Option<MappedRwLockWriteGuard<'static, T>> {
638        Some(RwLockWriteGuard::map(self.value.try_write()?, |l| l))
639    }
640}
641
642/// An app local storage.
643///
644/// This is similar to [`std::thread::LocalKey`], but works across all threads of the app.
645///
646/// Use the [`app_local!`] macro to declare a static variable in the same style as [`thread_local!`].
647///
648/// Note that in `"multi_app"` builds the app local can only be used if an app is running in the thread,
649/// if no app is running read and write **will panic**.
650pub struct AppLocal<T: Send + Sync + 'static> {
651    inner: fn() -> &'static dyn AppLocalImpl<T>,
652}
653impl<T: Send + Sync + 'static> AppLocal<T> {
654    #[doc(hidden)]
655    pub const fn new(inner: fn() -> &'static dyn AppLocalImpl<T>) -> Self {
656        AppLocal { inner }
657    }
658
659    /// Read lock the value associated with the current app.
660    ///
661    /// Initializes the default value for the app if this is the first value access.
662    ///
663    /// # Panics
664    ///
665    /// Panics if no app is running in `"multi_app"` builds.
666    #[inline]
667    pub fn read(&'static self) -> MappedRwLockReadGuard<'static, T> {
668        (self.inner)().read()
669    }
670
671    /// Try read lock the value associated with the current app.
672    ///
673    /// Initializes the default value for the app if this is the first value access.
674    ///
675    /// Returns `None` if can’t acquire a read lock.
676    ///
677    /// # Panics
678    ///
679    /// Panics if no app is running in `"multi_app"` builds.
680    #[inline]
681    pub fn try_read(&'static self) -> Option<MappedRwLockReadGuard<'static, T>> {
682        (self.inner)().try_read()
683    }
684
685    /// Write lock the value associated with the current app.
686    ///
687    /// Initializes the default value for the app if this is the first value access.
688    ///
689    /// # Panics
690    ///
691    /// Panics if no app is running in `"multi_app"` builds.
692    #[inline]
693    pub fn write(&'static self) -> MappedRwLockWriteGuard<'static, T> {
694        (self.inner)().write()
695    }
696
697    /// Try to write lock the value associated with the current app.
698    ///
699    /// Initializes the default value for the app if this is the first value access.
700    ///
701    /// Returns `None` if can’t acquire a write lock.
702    ///
703    /// # Panics
704    ///
705    /// Panics if no app is running in `"multi_app"` builds.
706    pub fn try_write(&'static self) -> Option<MappedRwLockWriteGuard<'static, T>> {
707        (self.inner)().try_write()
708    }
709
710    /// Get a clone of the value.
711    #[inline]
712    pub fn get(&'static self) -> T
713    where
714        T: Clone,
715    {
716        self.read().clone()
717    }
718
719    /// Set the value.
720    #[inline]
721    pub fn set(&'static self, value: T) {
722        *self.write() = value;
723    }
724
725    /// Try to get a clone of the value.
726    ///
727    /// Returns `None` if can't acquire a read lock.
728    #[inline]
729    pub fn try_get(&'static self) -> Option<T>
730    where
731        T: Clone,
732    {
733        self.try_read().map(|l| l.clone())
734    }
735
736    /// Try to set the value.
737    ///
738    /// Returns `Err(value)` if can't acquire a write lock.
739    #[inline]
740    pub fn try_set(&'static self, value: T) -> Result<(), T> {
741        match self.try_write() {
742            Some(mut l) => {
743                *l = value;
744                Ok(())
745            }
746            None => Err(value),
747        }
748    }
749
750    /// Create a read lock and `map` it to a sub-value.
751    #[inline]
752    pub fn read_map<O>(&'static self, map: impl FnOnce(&T) -> &O) -> MappedRwLockReadGuard<'static, O> {
753        MappedRwLockReadGuard::map(self.read(), map)
754    }
755
756    /// Try to create a read lock and `map` it to a sub-value.
757    #[inline]
758    pub fn try_read_map<O>(&'static self, map: impl FnOnce(&T) -> &O) -> Option<MappedRwLockReadGuard<'static, O>> {
759        let lock = self.try_read()?;
760        Some(MappedRwLockReadGuard::map(lock, map))
761    }
762
763    /// Create a write lock and `map` it to a sub-value.
764    #[inline]
765    pub fn write_map<O>(&'static self, map: impl FnOnce(&mut T) -> &mut O) -> MappedRwLockWriteGuard<'static, O> {
766        MappedRwLockWriteGuard::map(self.write(), map)
767    }
768
769    /// Try to create a write lock and `map` it to a sub-value.
770    #[inline]
771    pub fn try_write_map<O>(&'static self, map: impl FnOnce(&mut T) -> &mut O) -> Option<MappedRwLockWriteGuard<'static, O>> {
772        let lock = self.try_write()?;
773        Some(MappedRwLockWriteGuard::map(lock, map))
774    }
775
776    /// Gets an ID for this local instance that is valid for the lifetime of the process.
777    ///
778    /// Note that comparing two `&'static LOCAL` pointers is incorrect, because in `"hot_reload"` builds the statics
779    /// can be different and still represent the same app local. This ID identifies the actual inner pointer.
780    pub fn id(&'static self) -> AppLocalId {
781        AppLocalId((self.inner)() as *const dyn AppLocalImpl<T> as *const () as _)
782    }
783}
784impl<T: Send + Sync + 'static> PartialEq for AppLocal<T> {
785    fn eq(&self, other: &Self) -> bool {
786        let a = AppLocalId((self.inner)() as *const dyn AppLocalImpl<T> as *const () as _);
787        let b = AppLocalId((other.inner)() as *const dyn AppLocalImpl<T> as *const () as _);
788        a == b
789    }
790}
791impl<T: Send + Sync + 'static> Eq for AppLocal<T> {}
792impl<T: Send + Sync + 'static> std::hash::Hash for AppLocal<T> {
793    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
794        let a = AppLocalId((self.inner)() as *const dyn AppLocalImpl<T> as *const () as _);
795        std::hash::Hash::hash(&a, state)
796    }
797}
798
799/// Identifies an [`AppLocal<T>`] instance.
800///
801/// Note that comparing two `&'static LOCAL` pointers is incorrect, because in `"hot_reload"` builds the statics
802/// can be different and still represent the same app local. This ID identifies the actual inner pointer, it is
803/// valid for the lifetime of the process.
804#[derive(PartialEq, Eq, Hash, Clone, Copy)]
805pub struct AppLocalId(usize);
806impl AppLocalId {
807    /// Get the underlying value.
808    pub fn get(self) -> usize {
809        // VarPtr depends on this being an actual pointer (must be unique against an `Arc<T>` raw pointer).
810        self.0 as _
811    }
812}
813impl fmt::Debug for AppLocalId {
814    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
815        write!(f, "AppLocalId({:#x})", self.0)
816    }
817}
818
819///<span data-del-macro-root></span> Declares new app local variable.
820///
821/// An app local is a static variable that is declared using the same syntax as [`thread_local!`], but can be
822/// accessed by any thread in the app. In apps that only run once per process it compiles down to the equivalent
823/// of a `static LOCAL: RwLock<T> = const;` or `static LOCAL: RwLock<Option<T>>` that initializes on first usage. In test
824/// builds with multiple parallel apps it compiles to a switching storage that provides a different value depending on
825/// what app is running in the current thread.
826///
827/// See [`AppLocal<T>`] for more details.
828///
829/// # Multi App
830///
831/// If the crate is compiled with the `"multi_app"` feature a different internal implementation is used that supports multiple
832/// apps, either running in parallel in different threads or one after the other. This backing implementation has some small overhead,
833/// but usually you only want multiple app instances per-process when running tests.
834///
835/// The lifetime of `"multi_app"` locals is also more limited, trying to use an app-local before starting to build an app will panic,
836/// the app-local value will be dropped when the app is dropped. Without the `"multi_app"` feature the app-locals can be used at
837/// any point before or after the app lifetime, values are not explicitly dropped, just unloaded with the process.
838///
839/// # Const
840///
841/// The initialization expression can be wrapped in a `const { .. }` block, if the `"multi_app"` feature is **not** enabled
842/// a faster implementation is used that is equivalent to a direct `static LOCAL: RwLock<T>` in terms of performance.
843///
844/// Note that this syntax is available even if the `"multi_app"` feature is enabled, the expression must be const either way,
845/// but with the feature the same dynamic implementation is used.
846///
847/// Note that `const` initialization does not automatically convert the value into the static type.
848///
849/// # Examples
850///
851/// The example below declares two app locals, note that `BAR` init value automatically converts into the app local type.
852///
853/// ```
854/// # use zng_app_context::*;
855/// app_local! {
856///     /// A public documented value.
857///     pub static FOO: u8 = const { 10u8 };
858///
859///     // A private value.
860///     static BAR: String = "Into!";
861/// }
862///
863/// let app = LocalContext::start_app(AppId::new_unique());
864///
865/// assert_eq!(10, FOO.get());
866/// ```
867///
868/// Also note that an app context is started before the first use, in `multi_app` builds trying to use an app local in
869/// a thread not owned by an app panics.
870#[macro_export]
871macro_rules! app_local {
872    ($(
873        $(#[$meta:meta])*
874        $vis:vis static $IDENT:ident : $T:ty = $(const { $init_const:expr })? $($init:expr_2021)?;
875    )+) => {$(
876        $crate::app_local_impl! {
877            $(#[$meta])*
878            $vis static $IDENT: $T = $(const { $init_const })? $($init)?;
879        }
880    )+};
881}
882
883#[doc(hidden)]
884#[macro_export]
885macro_rules! app_local_impl_single {
886    (
887        $(#[$meta:meta])*
888        $vis:vis static $IDENT:ident : $T:ty = const { $init:expr };
889    ) => {
890        $(#[$meta])*
891        $vis static $IDENT: $crate::AppLocal<$T> = {
892            fn s() -> &'static dyn $crate::AppLocalImpl<$T> {
893                $crate::hot_static! {
894                    static IMPL: $crate::AppLocalConst<$T> = $crate::AppLocalConst::new($init);
895                }
896                $crate::hot_static_ref!(IMPL)
897            }
898            $crate::AppLocal::new(s)
899        };
900    };
901    (
902        $(#[$meta:meta])*
903        $vis:vis static $IDENT:ident : $T:ty = $init:expr_2021;
904    ) => {
905        $(#[$meta])*
906        $vis static $IDENT: $crate::AppLocal<$T> = {
907            fn s() -> &'static dyn $crate::AppLocalImpl<$T> {
908                fn init() -> $T {
909                    std::convert::Into::into($init)
910                }
911                $crate::hot_static! {
912                    static IMPL: $crate::AppLocalOption<$T> = $crate::AppLocalOption::new(init);
913                }
914                $crate::hot_static_ref!(IMPL)
915            }
916            $crate::AppLocal::new(s)
917        };
918    };
919    (
920        $(#[$meta:meta])*
921        $vis:vis static $IDENT:ident : $T:ty = ($tt:tt)*
922    ) => {
923        std::compile_error!("expected `const { $expr };` or `$expr;`")
924    };
925}
926
927#[doc(hidden)]
928#[macro_export]
929macro_rules! app_local_impl_multi {
930    (
931        $(#[$meta:meta])*
932        $vis:vis static $IDENT:ident : $T:ty = const { $init:expr };
933    ) => {
934        $(#[$meta])*
935        $vis static $IDENT: $crate::AppLocal<$T> = {
936            fn s() -> &'static dyn $crate::AppLocalImpl<$T> {
937                const fn init() -> $T {
938                    $init
939                }
940                $crate::hot_static! {
941                    static IMPL: $crate::AppLocalVec<$T> = $crate::AppLocalVec::new(init);
942                }
943                $crate::hot_static_ref!(IMPL)
944            }
945            $crate::AppLocal::new(s)
946        };
947    };
948    (
949        $(#[$meta:meta])*
950        $vis:vis static $IDENT:ident : $T:ty = $init:expr_2021;
951    ) => {
952        $(#[$meta])*
953        $vis static $IDENT: $crate::AppLocal<$T> = {
954            fn s() -> &'static dyn $crate::AppLocalImpl<$T> {
955                fn init() -> $T {
956                    std::convert::Into::into($init)
957                }
958                $crate::hot_static! {
959                    static IMPL: $crate::AppLocalVec<$T> = $crate::AppLocalVec::new(init);
960                }
961                $crate::hot_static_ref!(IMPL)
962            }
963            $crate::AppLocal::new(s)
964        };
965    };
966    (
967        $(#[$meta:meta])*
968        $vis:vis static $IDENT:ident : $T:ty = ($tt:tt)*
969    ) => {
970        std::compile_error!("expected `const { $expr };` or `$expr;`")
971    };
972}
973
974#[cfg(feature = "multi_app")]
975#[doc(hidden)]
976pub use app_local_impl_multi as app_local_impl;
977#[cfg(not(feature = "multi_app"))]
978#[doc(hidden)]
979pub use app_local_impl_single as app_local_impl;
980
981/*
982    context_local!
983*/
984
985#[doc(hidden)]
986pub struct ContextLocalData<T: Send + Sync + 'static> {
987    default_init: fn() -> T,
988    default_value: Option<Arc<T>>,
989}
990impl<T: Send + Sync + 'static> ContextLocalData<T> {
991    #[doc(hidden)]
992    pub const fn new(default_init: fn() -> T) -> Self {
993        Self {
994            default_init,
995            default_value: None,
996        }
997    }
998}
999
1000/// Represents an [`AppLocal<T>`] value that can be temporarily overridden in a context.
1001///
1002/// The *context* works across threads, as long as the threads are instrumented using [`LocalContext`].
1003///
1004/// Use the [`context_local!`] macro to declare a static variable in the same style as [`thread_local!`].
1005pub struct ContextLocal<T: Send + Sync + 'static> {
1006    data: AppLocal<ContextLocalData<T>>,
1007}
1008impl<T: Send + Sync + 'static> ContextLocal<T> {
1009    #[doc(hidden)]
1010    pub const fn new(storage: fn() -> &'static dyn AppLocalImpl<ContextLocalData<T>>) -> Self {
1011        Self {
1012            data: AppLocal::new(storage),
1013        }
1014    }
1015
1016    /// Gets an ID for this context local instance that is valid for the lifetime of the process.
1017    ///
1018    /// Note that comparing two `&'static CTX_LOCAL` pointers is incorrect, because in `"hot_reload"` builds the statics
1019    /// can be different and still represent the same app local. This ID identifies the actual inner pointer.
1020    pub fn id(&'static self) -> AppLocalId {
1021        self.data.id()
1022    }
1023
1024    /// Calls `f` with the `value` loaded in context.
1025    ///
1026    /// The `value` is moved into context, `f` is called, then the value is moved back to `value`.
1027    ///
1028    /// # Panics
1029    ///
1030    /// Panics if `value` is `None`.
1031    pub fn with_context<R>(&'static self, value: &mut Option<Arc<T>>, f: impl FnOnce() -> R) -> R {
1032        let mut r = None;
1033        let f = || r = Some(f());
1034        #[cfg(feature = "dyn_closure")]
1035        let f: Box<dyn FnOnce()> = Box::new(f);
1036
1037        LocalContext::with_value_ctx(self, LocalValueKind::Local, value, f);
1038
1039        r.unwrap()
1040    }
1041
1042    /// Same as [`with_context`], but `value` represents a variable.
1043    ///
1044    /// Values loaded with this method are captured by [`CaptureFilter::ContextVars`].
1045    ///
1046    /// [`with_context`]: Self::with_context
1047    pub fn with_context_var<R>(&'static self, value: &mut Option<Arc<T>>, f: impl FnOnce() -> R) -> R {
1048        let mut r = None;
1049        let f = || r = Some(f());
1050
1051        #[cfg(feature = "dyn_closure")]
1052        let f: Box<dyn FnOnce()> = Box::new(f);
1053
1054        LocalContext::with_value_ctx(self, LocalValueKind::Var, value, f);
1055
1056        r.unwrap()
1057    }
1058
1059    /// Calls `f` with no value loaded in context.
1060    pub fn with_default<R>(&'static self, f: impl FnOnce() -> R) -> R {
1061        let mut r = None;
1062        let f = || r = Some(f());
1063
1064        #[cfg(feature = "dyn_closure")]
1065        let f: Box<dyn FnOnce()> = Box::new(f);
1066        LocalContext::with_default_ctx(self, f);
1067
1068        r.unwrap()
1069    }
1070
1071    /// Gets if no value is set in the context.
1072    pub fn is_default(&'static self) -> bool {
1073        !LocalContext::contains(self.id())
1074    }
1075
1076    /// Clone a reference to the current value in the context or the default value.
1077    pub fn get(&'static self) -> Arc<T> {
1078        let cl = self.data.read();
1079        match LocalContext::get(self.id()) {
1080            Some(c) => Arc::downcast(c.0).unwrap(),
1081            None => match &cl.default_value {
1082                Some(d) => d.clone(),
1083                None => {
1084                    drop(cl);
1085                    let mut cl = self.data.write();
1086                    match &cl.default_value {
1087                        None => {
1088                            let d = Arc::new((cl.default_init)());
1089                            cl.default_value = Some(d.clone());
1090                            d
1091                        }
1092                        Some(d) => d.clone(),
1093                    }
1094                }
1095            },
1096        }
1097    }
1098
1099    /// Clone the current value in the context or the default value.
1100    pub fn get_clone(&'static self) -> T
1101    where
1102        T: Clone,
1103    {
1104        let cl = self.data.read();
1105        match LocalContext::get(self.id()) {
1106            Some(c) => c.0.downcast_ref::<T>().unwrap().clone(),
1107            None => match &cl.default_value {
1108                Some(d) => d.as_ref().clone(),
1109                None => {
1110                    drop(cl);
1111                    let mut cl = self.data.write();
1112                    match &cl.default_value {
1113                        None => {
1114                            let val = (cl.default_init)();
1115                            let r = val.clone();
1116                            cl.default_value = Some(Arc::new(val));
1117                            r
1118                        }
1119                        Some(d) => d.as_ref().clone(),
1120                    }
1121                }
1122            },
1123        }
1124    }
1125}
1126
1127impl<T: Send + Sync + 'static> ContextLocal<RwLock<T>> {
1128    /// Gets a read-only shared reference to the current context value.
1129    pub fn read_only(&'static self) -> ReadOnlyRwLock<T> {
1130        ReadOnlyRwLock::new(self.get())
1131    }
1132
1133    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be acquired.
1134    ///
1135    /// See `parking_lot::RwLock::read` for more details.
1136    pub fn read(&'static self) -> RwLockReadGuardOwned<T> {
1137        RwLockReadGuardOwned::lock(self.get())
1138    }
1139
1140    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be acquired.
1141    ///
1142    /// Unlike `read`, this method is guaranteed to succeed without blocking if
1143    /// another read lock is held at the time of the call.
1144    ///
1145    /// See `parking_lot::RwLock::read` for more details.
1146    pub fn read_recursive(&'static self) -> RwLockReadGuardOwned<T> {
1147        RwLockReadGuardOwned::lock_recursive(self.get())
1148    }
1149
1150    /// Locks this `RwLock` with exclusive write access, blocking the current
1151    /// thread until it can be acquired.
1152    ///
1153    /// See `parking_lot::RwLock::write` for more details.
1154    pub fn write(&'static self) -> RwLockWriteGuardOwned<T> {
1155        RwLockWriteGuardOwned::lock(self.get())
1156    }
1157
1158    /// Try lock this `RwLock` with shared read access, blocking the current thread until it can be acquired.
1159    ///
1160    /// See `parking_lot::RwLock::try_read` for more details.
1161    pub fn try_read(&'static self) -> Option<RwLockReadGuardOwned<T>> {
1162        RwLockReadGuardOwned::try_lock(self.get())
1163    }
1164
1165    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be acquired.
1166    ///
1167    /// See `parking_lot::RwLock::try_read_recursive` for more details.
1168    pub fn try_read_recursive(&'static self) -> Option<RwLockReadGuardOwned<T>> {
1169        RwLockReadGuardOwned::try_lock_recursive(self.get())
1170    }
1171
1172    /// Locks this `RwLock` with exclusive write access, blocking the current
1173    /// thread until it can be acquired.
1174    ///
1175    /// See `parking_lot::RwLock::try_write` for more details.
1176    pub fn try_write(&'static self) -> Option<RwLockWriteGuardOwned<T>> {
1177        RwLockWriteGuardOwned::try_lock(self.get())
1178    }
1179}
1180
1181/// Represents a read guard for an `Arc<RwLock<T>>` that owns a reference to it.
1182pub struct RwLockReadGuardOwned<T: 'static> {
1183    lock: parking_lot::RwLockReadGuard<'static, T>,
1184    _owned: Arc<RwLock<T>>,
1185}
1186impl<T> RwLockReadGuardOwned<T> {
1187    /// Lock owned.    
1188    ///
1189    /// See `parking_lot::RwLock::read` for more details.
1190    pub fn lock(own: Arc<RwLock<T>>) -> Self {
1191        Self {
1192            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
1193            lock: unsafe { mem::transmute::<parking_lot::RwLockReadGuard<'_, T>, parking_lot::RwLockReadGuard<'static, T>>(own.read()) },
1194            _owned: own,
1195        }
1196    }
1197
1198    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be acquired.
1199    ///
1200    /// See `parking_lot::RwLock::read_recursive` for more details.
1201    pub fn lock_recursive(own: Arc<RwLock<T>>) -> Self {
1202        Self {
1203            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
1204            lock: unsafe {
1205                mem::transmute::<parking_lot::RwLockReadGuard<'_, T>, parking_lot::RwLockReadGuard<'static, T>>(own.read_recursive())
1206            },
1207            _owned: own,
1208        }
1209    }
1210
1211    /// Try lock owned.
1212    ///
1213    /// See `parking_lot::RwLock::try_read` for more details.
1214    pub fn try_lock(own: Arc<RwLock<T>>) -> Option<Self> {
1215        let lock = own.try_read()?;
1216        Some(Self {
1217            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
1218            lock: unsafe { mem::transmute::<parking_lot::RwLockReadGuard<'_, T>, parking_lot::RwLockReadGuard<'static, T>>(lock) },
1219            _owned: own,
1220        })
1221    }
1222
1223    /// Try lock owned.
1224    ///
1225    /// See `parking_lot::RwLock::try_read` for more details.
1226    pub fn try_lock_recursive(own: Arc<RwLock<T>>) -> Option<Self> {
1227        let lock = own.try_read_recursive()?;
1228        Some(Self {
1229            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
1230            lock: unsafe { mem::transmute::<parking_lot::RwLockReadGuard<'_, T>, parking_lot::RwLockReadGuard<'static, T>>(lock) },
1231            _owned: own,
1232        })
1233    }
1234
1235    /// Make a new `MappedRwLockReadGuardOwned` for a component of the locked data.
1236    ///
1237    /// This is an associated function that needs to be
1238    /// used as `RwLockReadGuardOwned::map(...)`. A method would interfere with methods of
1239    /// the same name on the contents of the locked data.
1240    pub fn map<O>(guard: Self, map: impl FnOnce(&T) -> &O) -> MappedRwLockReadGuardOwned<T, O> {
1241        MappedRwLockReadGuardOwned {
1242            lock: parking_lot::RwLockReadGuard::map(guard.lock, map),
1243            _owned: guard._owned,
1244        }
1245    }
1246}
1247impl<T> ops::Deref for RwLockReadGuardOwned<T> {
1248    type Target = T;
1249
1250    fn deref(&self) -> &Self::Target {
1251        self.lock.deref()
1252    }
1253}
1254
1255/// Represents a read guard for an `Arc<RwLock<T>>` that owns a reference to it, mapped from another read guard.
1256pub struct MappedRwLockReadGuardOwned<T: 'static, O: 'static> {
1257    lock: parking_lot::MappedRwLockReadGuard<'static, O>,
1258    _owned: Arc<RwLock<T>>,
1259}
1260impl<T, O> MappedRwLockReadGuardOwned<T, O> {
1261    /// Make a new `MappedRwLockReadGuardOwned` for a component of the locked data.
1262    ///
1263    /// This is an associated function that needs to be
1264    /// used as `MappedRwLockReadGuardOwned::map(...)`. A method would interfere with methods of
1265    /// the same name on the contents of the locked data.
1266    pub fn map<O2>(guard: Self, map: impl FnOnce(&O) -> &O2) -> MappedRwLockReadGuardOwned<T, O2> {
1267        MappedRwLockReadGuardOwned {
1268            lock: parking_lot::MappedRwLockReadGuard::map(guard.lock, map),
1269            _owned: guard._owned,
1270        }
1271    }
1272}
1273impl<T, O> ops::Deref for MappedRwLockReadGuardOwned<T, O> {
1274    type Target = O;
1275
1276    fn deref(&self) -> &Self::Target {
1277        self.lock.deref()
1278    }
1279}
1280
1281/// Represents a read guard for an `Arc<RwLock<T>>` that owns a reference to it.
1282pub struct RwLockWriteGuardOwned<T: 'static> {
1283    lock: parking_lot::RwLockWriteGuard<'static, T>,
1284    _owned: Arc<RwLock<T>>,
1285}
1286impl<T> RwLockWriteGuardOwned<T> {
1287    /// Lock owned.
1288    ///
1289    /// See `parking_lot::RwLock::write` for more details.
1290    pub fn lock(own: Arc<RwLock<T>>) -> Self {
1291        Self {
1292            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
1293            lock: unsafe { mem::transmute::<parking_lot::RwLockWriteGuard<'_, T>, parking_lot::RwLockWriteGuard<'static, T>>(own.write()) },
1294            _owned: own,
1295        }
1296    }
1297
1298    /// Lock owned.
1299    ///
1300    /// See `parking_lot::RwLock::try_write` for more details.
1301    pub fn try_lock(own: Arc<RwLock<T>>) -> Option<Self> {
1302        let lock = own.try_write()?;
1303        Some(Self {
1304            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
1305            lock: unsafe { mem::transmute::<parking_lot::RwLockWriteGuard<'_, T>, parking_lot::RwLockWriteGuard<'static, T>>(lock) },
1306            _owned: own,
1307        })
1308    }
1309
1310    /// Make a new `MappedRwLockReadGuardOwned` for a component of the locked data.
1311    ///
1312    /// This is an associated function that needs to be
1313    /// used as `MappedRwLockReadGuardOwned::map(...)`. A method would interfere with methods of
1314    /// the same name on the contents of the locked data.
1315    pub fn map<O>(guard: Self, map: impl FnOnce(&mut T) -> &mut O) -> MappedRwLockWriteGuardOwned<T, O> {
1316        MappedRwLockWriteGuardOwned {
1317            lock: parking_lot::RwLockWriteGuard::map(guard.lock, map),
1318            _owned: guard._owned,
1319        }
1320    }
1321}
1322impl<T> ops::Deref for RwLockWriteGuardOwned<T> {
1323    type Target = T;
1324
1325    fn deref(&self) -> &Self::Target {
1326        self.lock.deref()
1327    }
1328}
1329impl<T> ops::DerefMut for RwLockWriteGuardOwned<T> {
1330    fn deref_mut(&mut self) -> &mut Self::Target {
1331        self.lock.deref_mut()
1332    }
1333}
1334
1335/// Represents a write guard for an `Arc<RwLock<T>>` that owns a reference to it, mapped from another read guard.
1336pub struct MappedRwLockWriteGuardOwned<T: 'static, O: 'static> {
1337    lock: parking_lot::MappedRwLockWriteGuard<'static, O>,
1338    _owned: Arc<RwLock<T>>,
1339}
1340impl<T, O> MappedRwLockWriteGuardOwned<T, O> {
1341    /// Make a new `MappedRwLockWriteGuardOwned` for a component of the locked data.
1342    ///
1343    /// This is an associated function that needs to be
1344    /// used as `MappedRwLockWriteGuardOwned::map(...)`. A method would interfere with methods of
1345    /// the same name on the contents of the locked data.
1346    pub fn map<O2>(guard: Self, map: impl FnOnce(&mut O) -> &mut O2) -> MappedRwLockWriteGuardOwned<T, O2> {
1347        MappedRwLockWriteGuardOwned {
1348            lock: parking_lot::MappedRwLockWriteGuard::map(guard.lock, map),
1349            _owned: guard._owned,
1350        }
1351    }
1352}
1353impl<T, O> ops::Deref for MappedRwLockWriteGuardOwned<T, O> {
1354    type Target = O;
1355
1356    fn deref(&self) -> &Self::Target {
1357        self.lock.deref()
1358    }
1359}
1360impl<T, O> ops::DerefMut for MappedRwLockWriteGuardOwned<T, O> {
1361    fn deref_mut(&mut self) -> &mut Self::Target {
1362        self.lock.deref_mut()
1363    }
1364}
1365
1366/// Read-only wrapper on an `Arc<RwLock<T>>` contextual value.
1367pub struct ReadOnlyRwLock<T>(Arc<RwLock<T>>);
1368impl<T> Clone for ReadOnlyRwLock<T> {
1369    fn clone(&self) -> Self {
1370        Self(self.0.clone())
1371    }
1372}
1373impl<T> ReadOnlyRwLock<T> {
1374    /// New.
1375    pub fn new(l: Arc<RwLock<T>>) -> Self {
1376        Self(l)
1377    }
1378
1379    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be acquired.
1380    ///
1381    /// See `parking_lot::RwLock::read` for more details.
1382    pub fn read(&self) -> parking_lot::RwLockReadGuard<T> {
1383        self.0.read()
1384    }
1385
1386    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be acquired.
1387    ///
1388    /// Unlike `read`, this method is guaranteed to succeed without blocking if
1389    /// another read lock is held at the time of the call.
1390    ///
1391    /// See `parking_lot::RwLock::read_recursive` for more details.
1392    pub fn read_recursive(&self) -> parking_lot::RwLockReadGuard<T> {
1393        self.0.read_recursive()
1394    }
1395
1396    /// Attempts to acquire this `RwLock` with shared read access.
1397    ///
1398    /// See `parking_lot::RwLock::try_read` for more details.
1399    pub fn try_read(&self) -> Option<parking_lot::RwLockReadGuard<T>> {
1400        self.0.try_read()
1401    }
1402
1403    /// Attempts to acquire this `RwLock` with shared read access.
1404    ///
1405    /// See `parking_lot::RwLock::try_read_recursive` for more details.
1406    pub fn try_read_recursive(&self) -> Option<parking_lot::RwLockReadGuard<T>> {
1407        self.0.try_read_recursive()
1408    }
1409
1410    /// Gets if the read-only shared reference is to the same lock as `other`.
1411    pub fn ptr_eq(&self, other: &Self) -> bool {
1412        Arc::ptr_eq(&self.0, &other.0)
1413    }
1414}
1415
1416///<span data-del-macro-root></span> Declares new app and context local variable.
1417///
1418/// # Examples
1419///
1420/// ```
1421/// # use zng_app_context::*;
1422/// context_local! {
1423///     /// A public documented value.
1424///     pub static FOO: u8 = 10u8;
1425///
1426///     // A private value.
1427///     static BAR: String = "Into!";
1428/// }
1429/// ```
1430///
1431/// # Default Value
1432///
1433/// All contextual values must have a fallback value that is used when no context is loaded.
1434///
1435/// The default value is instantiated once per app, the expression can be any static value that converts [`Into<T>`].
1436///
1437/// # Usage
1438///
1439/// After you declare the context local you can use it by loading a contextual value for the duration of a closure call.
1440///
1441/// ```
1442/// # use zng_app_context::*;
1443/// # use std::sync::Arc;
1444/// context_local! { static FOO: String = "default"; }
1445///
1446/// fn print_value() {
1447///     println!("value is {}!", FOO.get());
1448/// }
1449///
1450/// let _scope = LocalContext::start_app(AppId::new_unique());
1451///
1452/// let mut value = Some(Arc::new(String::from("other")));
1453/// FOO.with_context(&mut value, || {
1454///     print!("in context, ");
1455///     print_value();
1456/// });
1457///
1458/// print!("out of context, ");
1459/// print_value();
1460/// ```
1461///
1462/// The example above prints:
1463///
1464/// ```text
1465/// in context, value is other!
1466/// out of context, value is default!
1467/// ```
1468///
1469/// See [`ContextLocal<T>`] for more details.
1470#[macro_export]
1471macro_rules! context_local {
1472    ($(
1473        $(#[$meta:meta])*
1474        $vis:vis static $IDENT:ident : $T:ty = $init:expr;
1475    )+) => {$(
1476        $crate::context_local_impl! {
1477            $(#[$meta])*
1478            $vis static $IDENT: $T = $init;
1479        }
1480    )+};
1481}
1482
1483#[doc(hidden)]
1484#[macro_export]
1485macro_rules! context_local_impl_single {
1486    ($(
1487        $(#[$meta:meta])*
1488        $vis:vis static $IDENT:ident : $T:ty = $init:expr;
1489    )+) => {$(
1490        $(#[$meta])*
1491        $vis static $IDENT: $crate::ContextLocal<$T> = {
1492            fn s() -> &'static dyn $crate::AppLocalImpl<$crate::ContextLocalData<$T>> {
1493                fn init() -> $T {
1494                    std::convert::Into::into($init)
1495                }
1496                $crate::hot_static! {
1497                    static IMPL: $crate::AppLocalConst<$crate::ContextLocalData<$T>> =
1498                    $crate::AppLocalConst::new(
1499                        $crate::ContextLocalData::new(init)
1500                    );
1501                }
1502                $crate::hot_static_ref!(IMPL)
1503            }
1504            $crate::ContextLocal::new(s)
1505        };
1506    )+};
1507}
1508
1509#[doc(hidden)]
1510#[macro_export]
1511macro_rules! context_local_impl_multi {
1512    ($(
1513        $(#[$meta:meta])*
1514        $vis:vis static $IDENT:ident : $T:ty = $init:expr;
1515    )+) => {$(
1516        $(#[$meta])*
1517        $vis static $IDENT: $crate::ContextLocal<$T> = {
1518            fn s() -> &'static dyn $crate::AppLocalImpl<$crate::ContextLocalData<$T>> {
1519                fn init() -> $T {
1520                    std::convert::Into::into($init)
1521                }
1522                $crate::hot_static! {
1523                    static IMPL: $crate::AppLocalVec<$crate::ContextLocalData<$T>> =
1524                    $crate::AppLocalVec::new(
1525                        || $crate::ContextLocalData::new(init)
1526                    );
1527                }
1528                $crate::hot_static_ref!(IMPL)
1529            }
1530            $crate::ContextLocal::new(s)
1531        };
1532    )+};
1533}
1534
1535#[cfg(feature = "multi_app")]
1536#[doc(hidden)]
1537pub use context_local_impl_multi as context_local_impl;
1538
1539#[cfg(not(feature = "multi_app"))]
1540#[doc(hidden)]
1541pub use context_local_impl_single as context_local_impl;
1542
1543/// Defines a [`LocalContext::capture_filtered`] filter.
1544#[derive(Debug, Clone, PartialEq, Eq)]
1545pub enum CaptureFilter {
1546    /// Don't capture anything, equivalent of [`LocalContext::new`].
1547    None,
1548
1549    /// Capture all [`context_local!`] values and [`TracingDispatcherContext`].
1550    All,
1551    /// Capture all variables not excluded, no [`context_local!`] nor [`TracingDispatcherContext`].
1552    ContextVars {
1553        /// Vars to not include.
1554        exclude: ContextValueSet,
1555    },
1556    /// Capture all [`context_local!`] and [`TracingDispatcherContext`] not excluded, no context variables.
1557    ContextLocals {
1558        /// Locals to not include.
1559        exclude: ContextValueSet,
1560    },
1561
1562    /// Capture only this set.
1563    Include(ContextValueSet),
1564
1565    /// Capture all except this set.
1566    Exclude(ContextValueSet),
1567}
1568impl CaptureFilter {
1569    /// Capture all variables, no [`context_local!`] nor [`TracingDispatcherContext`].
1570    pub const fn context_vars() -> Self {
1571        Self::ContextVars {
1572            exclude: ContextValueSet::new(),
1573        }
1574    }
1575
1576    /// Capture all [`context_local!`] and [`TracingDispatcherContext`], no context variables.
1577    pub const fn context_locals() -> Self {
1578        Self::ContextLocals {
1579            exclude: ContextValueSet::new(),
1580        }
1581    }
1582
1583    /// Only capture the [`app_local!`] and [`TracingDispatcherContext`].
1584    pub fn app_only() -> Self {
1585        let mut set = ContextValueSet::new();
1586        set.insert_app();
1587        Self::Include(set)
1588    }
1589}
1590
1591/// Provides an identifying key for a context local value.
1592///
1593/// Implemented by all [`ContextLocal<T>`] already, only implement this for context local thin wrappers.
1594pub trait ContextLocalKeyProvider {
1595    /// Gets the key.
1596    fn context_local_key(&'static self) -> AppLocalId;
1597}
1598impl<T: Send + Sync + 'static> ContextLocalKeyProvider for ContextLocal<T> {
1599    fn context_local_key(&'static self) -> AppLocalId {
1600        self.id()
1601    }
1602}
1603
1604/// Represents the [`tracing::dispatcher::get_default`] dispatcher in a context value set.
1605///
1606/// [`tracing::dispatcher::get_default`]: https://docs.rs/tracing/latest/tracing/dispatcher/fn.get_global_default.html
1607pub struct TracingDispatcherContext;
1608
1609impl ContextLocalKeyProvider for TracingDispatcherContext {
1610    fn context_local_key(&'static self) -> AppLocalId {
1611        static ID: bool = true;
1612        AppLocalId(&ID as *const bool as *const () as usize)
1613    }
1614}
1615
1616/// Identifies a selection of [`LocalContext`] values.
1617#[derive(Default, Clone, PartialEq, Eq)]
1618pub struct ContextValueSet(LocalSet);
1619impl ContextValueSet {
1620    /// New empty.
1621    pub const fn new() -> Self {
1622        Self(new_local_set())
1623    }
1624
1625    /// Insert a context local.
1626    pub fn insert(&mut self, value: &'static impl ContextLocalKeyProvider) -> bool {
1627        self.0.insert(value.context_local_key())
1628    }
1629
1630    /// Remove a context local.
1631    pub fn remove(&mut self, value: &'static impl ContextLocalKeyProvider) -> bool {
1632        self.0.remove(&value.context_local_key())
1633    }
1634
1635    /// Checks if the context local is in the set.
1636    pub fn contains(&self, value: &'static impl ContextLocalKeyProvider) -> bool {
1637        self.0.contains(&value.context_local_key())
1638    }
1639
1640    /// Number of unique values in the set.
1641    pub fn len(&self) -> usize {
1642        self.0.len()
1643    }
1644
1645    /// If the set has any values.
1646    pub fn is_empty(&self) -> bool {
1647        self.0.is_empty()
1648    }
1649
1650    /// Extend this set with all `other` contexts.
1651    pub fn insert_all(&mut self, other: &Self) {
1652        self.0.extend(other.0.iter().copied());
1653    }
1654
1655    /// Removes all `other` contexts from this set.
1656    pub fn remove_all(&mut self, other: &Self) {
1657        for o in other.0.iter() {
1658            self.0.remove(o);
1659        }
1660    }
1661
1662    /// Insert the [`app_local!`] ID and [`TracingDispatcherContext`].
1663    pub fn insert_app(&mut self) -> bool {
1664        let inserted_app = self.0.insert(AppId::local_id());
1665        static TRACING: TracingDispatcherContext = TracingDispatcherContext;
1666        self.insert(&TRACING) || inserted_app
1667    }
1668}
1669impl fmt::Debug for ContextValueSet {
1670    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1671        f.debug_struct("ContextValueSet").field("len()", &self.len()).finish()
1672    }
1673}
1674
1675/// Helper, runs a cleanup action once on drop.
1676pub struct RunOnDrop<F: FnOnce()>(Option<F>);
1677impl<F: FnOnce()> RunOnDrop<F> {
1678    /// New with closure that will run once on drop.
1679    pub fn new(clean: F) -> Self {
1680        RunOnDrop(Some(clean))
1681    }
1682}
1683impl<F: FnOnce()> Drop for RunOnDrop<F> {
1684    fn drop(&mut self) {
1685        if let Some(clean) = self.0.take() {
1686            clean();
1687        }
1688    }
1689}
1690
1691fn panic_str<'s>(payload: &'s Box<dyn std::any::Any + Send + 'static>) -> &'s str {
1692    if let Some(s) = payload.downcast_ref::<&str>() {
1693        s
1694    } else if let Some(s) = payload.downcast_ref::<String>() {
1695        s
1696    } else {
1697        "<unknown-panic-message-type>"
1698    }
1699}