1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#[doc(hidden)]
pub extern crate scoped_tls;
#[macro_export]
macro_rules! scoped_tls {
($(#[$attrs:meta])* $vis:vis static $name:ident: $ty:ty) => {
$crate::scoped_tls::scoped_thread_local!(
static INNER: $ty
);
$(#[$attrs])*
$vis static $name: $crate::ScopedKey<$ty> = $crate::ScopedKey {
inner: &INNER,
#[cfg(debug_assertions)]
module_path: module_path!(),
#[cfg(debug_assertions)]
name: stringify!($name),
};
};
}
pub struct ScopedKey<T>
where
T: 'static,
{
#[doc(hidden)]
pub inner: &'static scoped_tls::ScopedKey<T>,
#[cfg(debug_assertions)]
#[doc(hidden)]
pub module_path: &'static str,
#[cfg(debug_assertions)]
#[doc(hidden)]
pub name: &'static str,
}
impl<T> ScopedKey<T>
where
T: 'static,
{
#[cfg_attr(not(debug_assertions), inline(always))]
pub fn set<F, R>(&'static self, t: &T, f: F) -> R
where
F: FnOnce() -> R,
{
self.inner.set(t, f)
}
#[cfg_attr(not(debug_assertions), inline(always))]
pub fn with<F, R>(&'static self, f: F) -> R
where
F: FnOnce(&T) -> R,
{
#[cfg(debug_assertions)]
if !self.inner.is_set() {
panic!(
"You should perform this operation in the closure passed to `set` of {}::{}",
self.module_path, self.name
)
}
self.inner.with(f)
}
#[cfg_attr(not(debug_assertions), inline(always))]
pub fn is_set(&'static self) -> bool {
self.inner.is_set()
}
}
#[cfg(test)]
mod tests {
scoped_tls!(
pub static TESTTLS: String
);
#[cfg(debug_assertions)]
#[test]
#[should_panic = "You should perform this operation in the closure passed to `set` of \
better_scoped_tls::tests::TESTTLS"]
fn panic_on_with() {
TESTTLS.with(|s| {
println!("S: {}", s);
})
}
#[test]
fn valid() {
TESTTLS.set(&String::new(), || {
TESTTLS.with(|s| {
assert_eq!(*s, String::new());
})
})
}
}