solar_interface/
globals.rs1use crate::SourceMap;
2use solar_data_structures::{defer, sync::Lock};
3use std::sync::Arc;
4
5scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
6
7pub struct SessionGlobals {
13 pub(crate) symbol_interner: crate::symbol::Interner,
14 pub(crate) source_map: Lock<Option<Arc<SourceMap>>>,
22}
23
24impl Default for SessionGlobals {
25 fn default() -> Self {
26 Self::new()
27 }
28}
29
30impl SessionGlobals {
31 pub fn new() -> Self {
33 Self { symbol_interner: crate::symbol::Interner::fresh(), source_map: Lock::new(None) }
34 }
35
36 #[inline]
38 pub fn set<R>(&self, f: impl FnOnce() -> R) -> R {
39 if SESSION_GLOBALS.is_set() {
40 panic_overwrite();
41 }
42 SESSION_GLOBALS.set(self, f)
43 }
44
45 pub fn with_source_map<R>(source_map: Arc<SourceMap>, f: impl FnOnce() -> R) -> R {
47 let prev = Self::with(|g| g.source_map.lock().replace(source_map));
48 let _clear = defer(|| {
49 Self::with(|g| *g.source_map.lock() = prev);
50 });
51 f()
52 }
53
54 #[inline]
60 pub fn with<R>(f: impl FnOnce(&Self) -> R) -> R {
61 #[cfg(debug_assertions)]
62 if !SESSION_GLOBALS.is_set() {
63 let msg = if rayon::current_thread_index().is_some() {
64 "cannot access a scoped thread local variable without calling `set` first;\n\
65 did you forget to call `Session::enter_parallel`?"
66 } else {
67 "cannot access a scoped thread local variable without calling `set` first;\n\
68 did you forget to call `Session::enter`, or `Session::enter_parallel` \
69 if using Rayon?"
70 };
71 panic!("{msg}");
72 }
73 SESSION_GLOBALS.with(f)
74 }
75
76 #[inline]
79 pub fn with_or_default<R>(f: impl FnOnce(&Self) -> R) -> R {
80 if Self::is_set() {
81 Self::with(f)
82 } else {
83 Self::new().set(|| Self::with(f))
84 }
85 }
86
87 #[inline]
89 pub fn is_set() -> bool {
90 SESSION_GLOBALS.is_set()
91 }
92}
93
94#[cold]
95#[inline(never)]
96const fn panic_overwrite() -> ! {
97 panic!(
98 "SESSION_GLOBALS should never be overwritten! \
99 Use another thread if you need another SessionGlobals"
100 );
101}