Crate scoped_tls_hkt

source ·
Expand description

Scoped thread-local storage

This module provides the ability to generate scoped thread-local variables. In this sense, scoped indicates that thread local storage actually stores a reference to a value, and this reference is only placed in storage for a scoped amount of time.

There are no restrictions on what types can be placed into a scoped variable, but all scoped variables are initialized to the equivalent of null. Scoped thread local storage is useful when a value is present for a known period of time and it is not required to relinquish ownership of the contents.

Examples

Basic usage

use scoped_tls_hkt::scoped_thread_local;

scoped_thread_local!(static FOO: u32);

// Initially each scoped slot is empty.
assert!(!FOO.is_set());

// When inserting a value, the value is only in place for the duration
// of the closure specified.
FOO.set(&1, || {
    FOO.with(|slot| {
        assert_eq!(*slot, 1);
    });
});

Mutable value

use scoped_tls_hkt::scoped_thread_local;

scoped_thread_local!(static mut FOO: u32);

// Initially each scoped slot is empty.
assert!(!FOO.is_set());

// When inserting a value, the value is only in place for the duration
// of the closure specified.
let mut x = 1;
FOO.set(&mut x, || {
    FOO.with(|slot| {
        assert_eq!(*slot, 1);

        // We can mutate the value
        *slot = 42;
    });
});

// Changes will be visible externally
assert_eq!(x, 42);

Higher-kinded types

use scoped_tls_hkt::scoped_thread_local;

// Must implement Copy
#[derive(Copy, Clone)]
struct Foo<'a> {
    x: &'a str, // Lifetime is covariant
    y: i32,
}

scoped_thread_local!(static FOO: for<'a> Foo<'a>);

// Initially each scoped slot is empty.
assert!(!FOO.is_set());

// When inserting a value, the value is only in place for the duration
// of the closure specified.
FOO.set(Foo { x: "Hello", y: 42 }, || {
    FOO.with(|slot| {
        assert_eq!(slot.x, "Hello");
        assert_eq!(slot.y, 42);
    });
});

Mutable higher-kinded types

For mutable HKTs, the types must implement the ReborrowMut trait, and the Result associated type should be the Self type, but with the lifetime substituted with the trait’s lifetime parameter.

The ReborrowMut trait is implemented automatically for many built-in types, including primitive types, references, mutable references and tuples (up to length 10). Where this is insufficient, you can implement the trait yourself: doing so should not require any unsafe code.

use scoped_tls_hkt::scoped_thread_local;

scoped_thread_local!(static mut FOO: for<'a> (&'a mut i32, &'a mut f32));

// Initially each scoped slot is empty.
assert!(!FOO.is_set());

// References to local variables can be stored.
let mut x = 1;
let mut y = 2.0;
FOO.set((&mut x, &mut y), || {
    FOO.with(|(u, v)| {
        assert_eq!(*u, 1);
        assert_eq!(*v, 2.0);
        *u = 42;
    });
});

assert_eq!(x, 42);

Macros

  • The macro. See the module level documentation for the description and examples.

Structs

  • Type representing a thread local storage key corresponding to a reference to the type parameter T.
  • Type representing a thread local storage key corresponding to a mutable reference to the type parameter T.

Traits

  • Trait representing the act of “reborrowing” a mutable reference to produce a new one with a shorter lifetime.