solar_interface/
globals.rs1use crate::SourceMap;
2use std::sync::Arc;
3
4scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
5
6pub(crate) struct SessionGlobals {
15 pub(crate) symbol_interner: crate::symbol::Interner,
16 pub(crate) source_map: Arc<SourceMap>,
17}
18
19impl Default for SessionGlobals {
20 fn default() -> Self {
21 Self::new(Default::default())
22 }
23}
24
25impl SessionGlobals {
26 pub(crate) fn new(source_map: Arc<SourceMap>) -> Self {
28 Self { symbol_interner: crate::symbol::Interner::fresh(), source_map }
29 }
30
31 pub(crate) fn set<R>(&self, f: impl FnOnce() -> R) -> R {
33 self.check_overwrite();
34 SESSION_GLOBALS.set(self, f)
35 }
36
37 fn check_overwrite(&self) {
38 Self::try_with(|prev| {
39 if let Some(prev) = prev
40 && !prev.maybe_eq(self)
41 {
42 overwrite_log();
43 }
44 });
45 }
46
47 #[inline]
53 #[track_caller]
54 pub(crate) fn with<R>(f: impl FnOnce(&Self) -> R) -> R {
55 debug_assert!(
56 SESSION_GLOBALS.is_set(),
57 "cannot access a scoped thread local variable without calling `set` first; \
58 did you forget to call `Session::enter`?"
59 );
60 SESSION_GLOBALS.with(f)
61 }
62
63 #[inline]
66 #[track_caller]
67 pub(crate) fn with_or_default<R>(f: impl FnOnce(&Self) -> R) -> R {
68 if Self::is_set() { Self::with(f) } else { Self::default().set(|| Self::with(f)) }
69 }
70
71 #[inline]
73 pub(crate) fn is_set() -> bool {
74 SESSION_GLOBALS.is_set()
75 }
76
77 pub(crate) fn try_with<R>(f: impl FnOnce(Option<&Self>) -> R) -> R {
78 if SESSION_GLOBALS.is_set() { SESSION_GLOBALS.with(|g| f(Some(g))) } else { f(None) }
79 }
80
81 pub(crate) fn maybe_eq(&self, other: &Self) -> bool {
82 std::ptr::eq(self, other)
83 }
84}
85
86#[inline(never)]
87#[cold]
88fn overwrite_log() {
89 debug!(
90 "overwriting SESSION_GLOBALS; \
91 this might be due to manual incorrect usage of `SessionGlobals`, \
92 or entering multiple different nested `Session`s, which may cause unexpected behavior"
93 );
94}