1 unstable release

Uses new Rust 2024

new 0.1.0 May 18, 2025

#1458 in Rust patterns

46 downloads per month

MIT license

9KB
126 lines

Thread-local storage with guarded scopes.

This crate provides thread-local variables whose values can be temporarily overridden within a scope. Each time you call set, a new value is pushed onto the thread-local stack, and a [Guard] is returned. When the guard is dropped, the associated value is removed from the stack. This enables safe, nested overrides of thread-local state.

Usage

Use the [guarded_thread_local] macro to define a thread-local key. Call set to override the value for the current thread and receive a guard. The value is accessible via get while the guard is alive.

use guarded_tls::guarded_thread_local;

guarded_thread_local!(static FOO: String);

let _guard1 = FOO.set("abc".into());
assert_eq!(FOO.get(), "abc");

let guard2 = FOO.set("def".into());
assert_eq!(FOO.get(), "def");

drop(guard2);
assert_eq!(FOO.get(), "abc");

Notes

  • get requires the value type to implement [Clone].
  • Accessing the value without having a guard will panic.
  • Guards dropped out of order have well-defined behavior.

See Also

  • scoped-tls: a similar crate for scoped thread-local values.

The main difference between this crate and scoped-tls is that this crate doesn't require the nesting of functions, making it some application easier to manage. For instance creating a test fixture that holds a [Guard].

guarded_tls::guarded_thread_local!(static FOO: u32);

fn create_fixture() -> MyFixture {
    MyFixture { foo_guard: FOO.set(123) }
}

fn my_test() {
    let fixture = create_fixture();

    // Test code here that assumes `FOO` is set.
    assert_eq!(FOO.get(), 123);
}

my_test();

No runtime deps