1#![cfg_attr(not(feature = "std"), no_std)]
42
43extern crate alloc;
44
45#[doc(hidden)]
46pub use core::{cell::RefCell, mem::{transmute, replace}, marker::PhantomData};
47
48#[doc(hidden)]
49pub use alloc::{rc::Rc, vec::Vec};
50
51#[cfg(not(feature = "std"))]
52#[macro_export]
53mod local_key;
54
55#[doc(hidden)]
56#[cfg(not(feature = "std"))]
57pub use local_key::LocalKey;
58
59#[doc(hidden)]
60#[cfg(feature = "std")]
61pub use std::thread::LocalKey;
62
63#[doc(hidden)]
64#[cfg(feature = "std")]
65#[macro_export]
66macro_rules! thread_local_impl {
67 ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr) => (
68 thread_local!($(#[$attr])* static $name: $t = $init);
69 );
70}
71
72#[doc(hidden)]
73#[cfg(not(feature = "std"))]
74#[macro_export]
75macro_rules! thread_local_impl {
76 ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr) => (
77 $(#[$attr])*
78 static $name: $crate::LocalKey<$t> = {
79 fn __init() -> $t { $init }
80
81 $crate::local_key_init!(__init)
82 };
83 );
84}
85
86#[doc(hidden)]
88pub type GlobalInner<T> = RefCell<Vec<Rc<RefCell<*mut T>>>>;
89
90type Global<T> = LocalKey<GlobalInner<T>>;
92
93struct PopGlobal<'a, T: 'a + ?Sized> {
94 global_stack: &'a GlobalInner<T>,
95}
96
97impl<'a, T: 'a + ?Sized> Drop for PopGlobal<'a, T> {
98 fn drop(&mut self) {
99 self.global_stack.borrow_mut().pop();
100 }
101}
102
103#[doc(hidden)]
104pub fn using<T: ?Sized, R, F: FnOnce() -> R>(
105 global: &'static Global<T>,
106 protected: &mut T,
107 f: F,
108) -> R {
109 global.with(|r| {
116 r.borrow_mut().push(
118 Rc::new(RefCell::new(protected as _)),
119 );
120
121 let _guard = PopGlobal { global_stack: r };
123
124 f()
125 })
126}
127
128#[doc(hidden)]
129pub fn using_once<T: ?Sized, R, F: FnOnce() -> R>(
130 global: &'static Global<T>,
131 protected: &mut T,
132 f: F,
133) -> R {
134 global.with(|r| {
141 if r.borrow().last().is_some() {
143 f()
144 } else {
145 r.borrow_mut().push(
147 Rc::new(RefCell::new(protected as _)),
148 );
149
150 let _guard = PopGlobal { global_stack: r };
152
153 f()
154 }
155 })
156}
157
158#[doc(hidden)]
159pub fn with<T: ?Sized, R, F: FnOnce(&mut T) -> R>(
160 global: &'static Global<T>,
161 mutator: F,
162) -> Option<R> {
163 global.with(|r| {
164 let last = r.borrow().last().cloned();
167 match last {
168 Some(ptr) => unsafe {
169 Some(mutator(&mut **ptr.borrow_mut()))
172 }
173 None => None,
174 }
175 })
176}
177
178#[macro_export]
241macro_rules! environmental {
242 ($name:ident : $t:ty) => {
243 #[allow(non_camel_case_types)]
244 struct $name { __private_field: () }
245
246 $crate::thread_local_impl! {
247 static GLOBAL: $crate::GlobalInner<$t> = Default::default()
248 }
249
250 impl $name {
251 #[allow(unused_imports)]
252 #[allow(dead_code)]
253 pub fn using<R, F: FnOnce() -> R>(
254 protected: &mut $t,
255 f: F,
256 ) -> R {
257 $crate::using(&GLOBAL, protected, f)
258 }
259
260 #[allow(dead_code)]
261 pub fn with<R, F: FnOnce(&mut $t) -> R>(
262 f: F,
263 ) -> Option<R> {
264 $crate::with(&GLOBAL, |x| f(x))
265 }
266
267 #[allow(dead_code)]
268 pub fn using_once<R, F: FnOnce() -> R>(
269 protected: &mut $t,
270 f: F,
271 ) -> R {
272 $crate::using_once(&GLOBAL, protected, f)
273 }
274 }
275 };
276 ($name:ident : trait @$t:ident [$($args:ty,)*]) => {
277 #[allow(non_camel_case_types, dead_code)]
278 struct $name { __private_field: () }
279
280 $crate::thread_local_impl! {
281 static GLOBAL: $crate::GlobalInner<(dyn $t<$($args),*> + 'static)>
282 = Default::default()
283 }
284
285 impl $name {
286 #[allow(unused_imports)]
287 #[allow(dead_code)]
288 pub fn using<R, F: FnOnce() -> R>(
289 protected: &mut dyn $t<$($args),*>,
290 f: F
291 ) -> R {
292 let lifetime_extended = unsafe {
293 $crate::transmute::<&mut dyn $t<$($args),*>, &mut (dyn $t<$($args),*> + 'static)>(protected)
294 };
295 $crate::using(&GLOBAL, lifetime_extended, f)
296 }
297
298 #[allow(dead_code)]
299 pub fn with<R, F: for<'a> FnOnce(&'a mut (dyn $t<$($args),*> + 'a)) -> R>(
300 f: F
301 ) -> Option<R> {
302 $crate::with(&GLOBAL, |x| f(x))
303 }
304
305 #[allow(unused_imports)]
306 #[allow(dead_code)]
307 pub fn using_once<R, F: FnOnce() -> R>(
308 protected: &mut dyn $t<$($args),*>,
309 f: F
310 ) -> R {
311 let lifetime_extended = unsafe {
312 $crate::transmute::<&mut dyn $t<$($args),*>, &mut (dyn $t<$($args),*> + 'static)>(protected)
313 };
314 $crate::using_once(&GLOBAL, lifetime_extended, f)
315 }
316 }
317 };
318 ($name:ident<$traittype:ident> : trait $t:ident <$concretetype:ty>) => {
319 #[allow(non_camel_case_types, dead_code)]
320 struct $name <H: $traittype> { _private_field: $crate::PhantomData<H> }
321
322 $crate::thread_local_impl! {
323 static GLOBAL: $crate::GlobalInner<(dyn $t<$concretetype> + 'static)>
324 = Default::default()
325 }
326
327 impl<H: $traittype> $name<H> {
328 #[allow(unused_imports)]
329 #[allow(dead_code)]
330 pub fn using<R, F: FnOnce() -> R>(
331 protected: &mut dyn $t<H>,
332 f: F
333 ) -> R {
334 let lifetime_extended = unsafe {
335 $crate::transmute::<&mut dyn $t<H>, &mut (dyn $t<$concretetype> + 'static)>(protected)
336 };
337 $crate::using(&GLOBAL, lifetime_extended, f)
338 }
339
340 #[allow(dead_code)]
341 pub fn with<R, F: for<'a> FnOnce(&'a mut (dyn $t<$concretetype> + 'a)) -> R>(
342 f: F
343 ) -> Option<R> {
344 $crate::with(&GLOBAL, |x| f(x))
345 }
346
347 #[allow(unused_imports)]
348 #[allow(dead_code)]
349 pub fn using_once<R, F: FnOnce() -> R>(
350 protected: &mut dyn $t<H>,
351 f: F
352 ) -> R {
353 let lifetime_extended = unsafe {
354 $crate::transmute::<&mut dyn $t<H>, &mut (dyn $t<$concretetype> + 'static)>(protected)
355 };
356 $crate::using_once(&GLOBAL, lifetime_extended, f)
357 }
358 }
359 };
360 ($name:ident : trait $t:ident <>) => { $crate::environmental! { $name : trait @$t [] } };
361 ($name:ident : trait $t:ident < $($args:ty),* $(,)* >) => {
362 $crate::environmental! { $name : trait @$t [$($args,)*] }
363 };
364 ($name:ident : trait $t:ident) => { $crate::environmental! { $name : trait @$t [] } };
365}
366
367#[cfg(test)]
368mod tests {
369 #[allow(dead_code)]
371 mod trait_test {
372 trait Test {}
373
374 environmental!(item_positon_trait: trait Test);
375 }
376
377 #[allow(dead_code)]
379 mod type_test {
380 environmental!(item_position_type: u32);
381 }
382
383 #[test]
384 fn simple_works() {
385 environmental!(counter: u32);
386
387 fn stuff() { counter::with(|value| *value += 1); }
388
389 let mut local = 41u32;
391
392 counter::using(&mut local, stuff);
394 assert_eq!(local, 42);
395 stuff(); assert_eq!(local, 42);
397 }
398
399 #[test]
400 fn overwrite_with_lesser_lifetime() {
401 environmental!(items: Vec<u8>);
402
403 let mut local_items = vec![1, 2, 3];
404 items::using(&mut local_items, || {
405 let dies_at_end = vec![4, 5, 6];
406 items::with(|items| *items = dies_at_end);
407 });
408
409 assert_eq!(local_items, vec![4, 5, 6]);
410 }
411
412 #[test]
413 fn declare_with_trait_object() {
414 trait Foo {
415 fn get(&self) -> i32;
416 fn set(&mut self, x: i32);
417 }
418
419 impl Foo for i32 {
420 fn get(&self) -> i32 { *self }
421 fn set(&mut self, x: i32) { *self = x }
422 }
423
424 environmental!(foo: dyn Foo + 'static);
425
426 fn stuff() {
427 foo::with(|value| {
428 let new_val = value.get() + 1;
429 value.set(new_val);
430 });
431 }
432
433 let mut local = 41i32;
434 foo::using(&mut local, stuff);
435
436 assert_eq!(local, 42);
437
438 stuff(); assert_eq!(local, 42);
441 }
442
443 #[test]
444 fn unwind_recursive() {
445 use std::panic;
446
447 environmental!(items: Vec<u8>);
448
449 let panicked = panic::catch_unwind(|| {
450 let mut local_outer = vec![1, 2, 3];
451
452 items::using(&mut local_outer, || {
453 let mut local_inner = vec![4, 5, 6];
454 items::using(&mut local_inner, || {
455 panic!("are you unsafe?");
456 })
457 });
458 }).is_err();
459
460 assert!(panicked);
461
462 let mut was_cleared = true;
463 items::with(|_items| was_cleared = false);
464
465 assert!(was_cleared);
466 }
467
468 #[test]
469 fn use_non_static_trait() {
470 trait Sum { fn sum(&self) -> usize; }
471 impl Sum for &[usize] {
472 fn sum(&self) -> usize {
473 self.iter().fold(0, |a, c| a + c)
474 }
475 }
476
477 environmental!(sum: trait Sum);
478 let numbers = vec![1, 2, 3, 4, 5];
479 let mut numbers = &numbers[..];
480 let got_sum = sum::using(&mut numbers, || {
481 sum::with(|x| x.sum())
482 }).unwrap();
483
484 assert_eq!(got_sum, 15);
485 }
486
487 #[test]
488 fn stacking_globals() {
489 trait Sum { fn sum(&self) -> usize; }
490 impl Sum for &[usize] {
491 fn sum(&self) -> usize {
492 self.iter().fold(0, |a, c| a + c)
493 }
494 }
495
496 environmental!(sum: trait Sum);
497 let numbers = vec![1, 2, 3, 4, 5];
498 let mut numbers = &numbers[..];
499 let got_sum = sum::using(&mut numbers, || {
500 sum::with(|_| {
501 let numbers2 = vec![1, 2, 3, 4, 5, 6];
502 let mut numbers2 = &numbers2[..];
503 sum::using(&mut numbers2, || {
504 sum::with(|x| x.sum())
505 })
506 })
507 }).unwrap().unwrap();
508
509 assert_eq!(got_sum, 21);
510
511 assert!(sum::with(|_| ()).is_none());
512 }
513
514 #[test]
515 fn use_generic_trait() {
516 trait Plus { fn plus42() -> usize; }
517 struct ConcretePlus;
518 impl Plus for ConcretePlus {
519 fn plus42() -> usize { 42 }
520 }
521 trait Multiplier<T: Plus> { fn mul_and_add(&self) -> usize; }
522 impl<'a, P: Plus> Multiplier<P> for &'a [usize] {
523 fn mul_and_add(&self) -> usize {
524 self.iter().fold(1, |a, c| a * c) + P::plus42()
525 }
526 }
527
528 let numbers = vec![1, 2, 3];
529 let mut numbers = &numbers[..];
530 let out = foo::<ConcretePlus>::using(&mut numbers, || {
531 foo::<ConcretePlus>::with(|x| x.mul_and_add() )
532 }).unwrap();
533
534 assert_eq!(out, 6 + 42);
535 environmental!(foo<Plus>: trait Multiplier<ConcretePlus>);
536 }
537
538 #[test]
539 fn using_once_is_working() {
540 environmental!(value: u32);
541
542 let mut called_inner = false;
543
544 value::using_once(&mut 5, || {
545 value::using_once(&mut 10, || {
546 assert_eq!(5, value::with(|v| *v).unwrap());
547
548 value::using(&mut 20, || {
549 assert_eq!(20, value::with(|v| *v).unwrap());
550
551 value::using_once(&mut 30, || {
552 assert_eq!(20, value::with(|v| *v).unwrap());
553
554 called_inner = true;
555 })
556 })
557 })
558 });
559
560 assert!(called_inner);
561 }
562}