with_thread_local/lib.rs
1//! A micro crate that simplifies a bit the use of the std macro `thread_local!`.
2//!
3//! ```
4//! extern crate regex;
5//!
6//! use with_thread_local::with_thread_local;
7//! use regex::Regex;
8//!
9//! let user_input = "cat";
10//!
11//! let (is_a_pet, needs_a_walk) = with_thread_local! {
12//! static REGEX_PET: Regex = Regex::new(r"cat|dog").unwrap();
13//! static REGEX_WALK: Regex = Regex::new(r"dog").unwrap();
14//!
15//! {
16//! let is_a_pet = REGEX_PET.is_match(user_input);
17//! let needs_a_walk = REGEX_WALK.is_match(user_input);
18//!
19//! (is_a_pet, needs_a_walk)
20//! }
21//! };
22//!
23//! assert!(is_a_pet && !needs_a_walk);
24//! ```
25//!
26//! You can also use its variant `move` to move variables inside the block. Though I admit I could
27//! not write a good example:
28//!
29//! ```
30//! extern crate regex;
31//!
32//! use with_thread_local::with_thread_local;
33//! use regex::Regex;
34//!
35//! let user_input = vec!["cat", "love", "dog"];
36//!
37//! let output = with_thread_local! {
38//! static REGEX_PET: Regex = Regex::new(r"cat|dog").unwrap();
39//!
40//! move {
41//! user_input
42//! .into_iter()
43//! .filter(|s| REGEX_PET.is_match(s))
44//! .collect::<Vec<_>>()
45//! }
46//! };
47//!
48//! assert_eq!(output, ["cat", "dog"]);
49//! ```
50
51#[macro_export]
52macro_rules! with_thread_local {
53 (
54 $(
55 static $name:ident : $ty:ty = $init:expr;
56 )+
57
58 $block:block
59 ) => {{
60 thread_local! {
61 #[allow(unused_parens)]
62 static _THIS_LOCAL: ($($ty),+) = ($($init),+);
63 }
64
65 _THIS_LOCAL.with(|#[allow(non_snake_case, unused_parens)] ($($name),+)| $block)
66 }};
67 (
68 $(
69 static $name:ident : $ty:ty = $init:expr;
70 )+
71
72 move $block:block
73 ) => {{
74 thread_local! {
75 #[allow(unused_parens)]
76 static _THIS_LOCAL: ($($ty),+) = ($($init),+);
77 }
78
79 _THIS_LOCAL.with(move |#[allow(non_snake_case, unused_parens)] ($($name),+)| $block)
80 }};
81}
82
83#[cfg(test)]
84mod test {
85 #[test]
86 fn use_one() {
87 let res = with_thread_local! {
88 static ONE: usize = 42;
89
90 {
91 *ONE
92 }
93 };
94 assert_eq!(res, 42);
95 }
96
97 #[test]
98 fn use_two() {
99 let res = with_thread_local! {
100 static ONE: usize = 42;
101 static TWO: usize = 2;
102
103 {
104 *ONE + *TWO
105 }
106 };
107 assert_eq!(res, 44);
108 }
109}