Struct state::TypeMap

source ·
pub struct TypeMap<K: Kind> { /* private fields */ }
Expand description

A type map storing values based on types.

A type map stores at most one instance of given type as well as n thread-local instances of a given type.

Type Bounds

A TypeMap can store values that are both Send + Sync, just Send, or neither. The TypeMap! macro is used to specify the kind of type map:

use state::TypeMap;

// Values must implement `Send + Sync`. The type_map itself is `Send + Sync`.
let type_map: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();
let type_map: TypeMap![Sync + Send] = <TypeMap![Sync + Send]>::new();

// Values must implement `Send`. The type_map itself is `Send`, `!Sync`.
let type_map: TypeMap![Send] = <TypeMap![Send]>::new();

// Values needn't implement `Send` nor `Sync`. `TypeMap` is `!Send`, `!Sync`.
let type_map: TypeMap![] = <TypeMap![]>::new();

Setting State

Global state is set via the set() method and retrieved via the get() method. The type of the value being set must meet the bounds of the TypeMap.

use state::TypeMap;

fn f_send_sync<T: Send + Sync + Clone + 'static>(value: T) {
    let type_map = <TypeMap![Send + Sync]>::new();
    type_map.set(value.clone());

    let type_map = <TypeMap![Send]>::new();
    type_map.set(value.clone());

    let type_map = <TypeMap![]>::new();
    type_map.set(value.clone());
}

fn f_send<T: Send + Clone + 'static>(value: T) {
    // This would fail to compile since `T` may not be `Sync`.
    // let type_map = <TypeMap![Send + Sync]>::new();
    // type_map.set(value.clone());

    let type_map = <TypeMap![Send]>::new();
    type_map.set(value.clone());

    let type_map = <TypeMap![]>::new();
    type_map.set(value.clone());
}

fn f<T: 'static>(value: T) {
    // This would fail to compile since `T` may not be `Sync` or `Send`.
    // let type_map = <TypeMap![Send + Sync]>::new();
    // type_map.set(value.clone());

    // This would fail to compile since `T` may not be `Send`.
    // let type_map = <TypeMap![Send]>::new();
    // type_map.set(value.clone());

    let type_map = <TypeMap![]>::new();
    type_map.set(value);
}

// If `TypeMap` is `Send + Sync`, it can be `const`-constructed.
static TYPE_MAP: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();

TYPE_MAP.set(String::new());
TYPE_MAP.get::<String>();

Freezing

By default, all get, set, get_local, and set_local calls result in synchronization overhead for safety. However, if calling set or set_local is no longer required, the overhead can be eliminated by freezing the TypeMap. A frozen type map can only be read and never written to. Attempts to write to a frozen type map will be ignored.

To freeze a TypeMap, call freeze(). A frozen map can never be thawed. To check if a type map is frozen, call is_frozen().

Thread-Local State

Thread-local state on a Send + Sync type map is set via the set_local() method and retrieved via the get_local() method. The type of the value being set must be transferable across thread boundaries but need not be thread-safe. In other words, it must satisfy Send + 'static but not necessarily Sync. Values retrieved from thread-local state are exactly that: local to the current thread. As such, you cannot use thread-local state to synchronize across multiple threads.

Thread-local state is initialized on an as-needed basis. The function used to initialize the thread-local state is passed in as an argument to set_local. When the state is retrieved from a given thread for the first time, the function is executed to generate the initial value. The function is executed at most once per thread. The same function is used for initialization across all threads.

Note: Rust reuses thread IDs across multiple threads. This means that is possible to set thread-local state in thread A, have that thread die, start a new thread B, and access the state set in tread A in thread B.

Example

Set and later retrieve a value of type T:

use state::TypeMap;

static TYPE_MAP: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();

TYPE_MAP.set_local(|| T::new());
TYPE_MAP.get_local::<T>();

Implementations§

source§

impl TypeMap<SendSync>

source

pub const fn new() -> Self

Creates a new type map with no stored values.

Example

Create a globally available type map:

use state::TypeMap;

static TYPE_MAP: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();
source

pub fn set<T: Send + Sync + 'static>(&self, state: T) -> bool

Sets the global state for type T if it has not been set before and self is not frozen.

If the state for T has previously been set or self is frozen, the state is unchanged and false is returned. Otherwise true is returned.

Example

Set the state for AtomicUsize. The first set is succesful while the second fails.

use state::TypeMap;

static TYPE_MAP: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();

assert_eq!(TYPE_MAP.set(AtomicUsize::new(0)), true);
assert_eq!(TYPE_MAP.set(AtomicUsize::new(1)), false);
source

pub fn set_local<T, F>(&self, state_init: F) -> boolwhere T: Send + 'static, F: Fn() -> T + Send + Sync + 'static,

Sets the thread-local state for type T if it has not been set before.

The state for type T will be initialized via the state_init function as needed. If the state for T has previously been set, the state is unchanged and false is returned. Returns true if the thread-local state is successfully set to be initialized with state_init.

Example
use state::TypeMap;

static TYPE_MAP: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();

struct MyState(Cell<usize>);

assert_eq!(TYPE_MAP.set_local(|| MyState(Cell::new(1))), true);
assert_eq!(TYPE_MAP.set_local(|| MyState(Cell::new(2))), false);
source

pub fn try_get_local<T: Send + 'static>(&self) -> Option<&T>

Attempts to retrieve the thread-local state for type T.

Returns Some if the state has previously been set via set_local. Otherwise returns None.

Example
use state::TypeMap;

static TYPE_MAP: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();

struct MyState(Cell<usize>);

TYPE_MAP.set_local(|| MyState(Cell::new(10)));

let my_state = TYPE_MAP.try_get_local::<MyState>().expect("MyState");
assert_eq!(my_state.0.get(), 10);
source

pub fn get_local<T: Send + 'static>(&self) -> &T

Retrieves the thread-local state for type T.

Panics

Panics if the thread-local state for type T has not previously been set via set_local. Use try_get_local for a non-panicking version.

Example
use state::TypeMap;

static TYPE_MAP: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();

struct MyState(Cell<usize>);

TYPE_MAP.set_local(|| MyState(Cell::new(10)));

let my_state = TYPE_MAP.get_local::<MyState>();
assert_eq!(my_state.0.get(), 10);
source§

impl TypeMap<Send>

source

pub fn new() -> Self

Creates a new type map with no stored values.

Example
use std::cell::Cell;

use state::TypeMap;

let type_map = <TypeMap![Send]>::new();

let value: Cell<u8> = Cell::new(10);
type_map.set(value);
assert_eq!(type_map.get::<Cell<u8>>().get(), 10);

type_map.get::<Cell<u8>>().set(99);
assert_eq!(type_map.get::<Cell<u8>>().get(), 99);
source

pub fn set<T: Send + 'static>(&self, state: T) -> bool

Sets the global state for type T if it has not been set before and self is not frozen.

If the state for T has previously been set or self is frozen, the state is unchanged and false is returned. Otherwise true is returned.

Example

Set the state. The first set is succesful while the second fails.

use state::TypeMap;

let type_map = <TypeMap![Send]>::new();
assert!(type_map.set(AtomicUsize::new(0)));
assert!(!type_map.set(AtomicUsize::new(1)));
source§

impl TypeMap<Neither>

source

pub fn new() -> Self

Creates a new type_map with no stored values.

Example
use std::cell::Cell;
use state::TypeMap;

let type_map = <TypeMap![]>::new();

let value: Cell<u8> = Cell::new(10);
type_map.set(value);
assert_eq!(type_map.get::<Cell<u8>>().get(), 10);

type_map.get::<Cell<u8>>().set(99);
assert_eq!(type_map.get::<Cell<u8>>().get(), 99);
source

pub fn set<T: 'static>(&self, state: T) -> bool

Sets the global state for type T if it has not been set before and self is not frozen.

If the state for T has previously been set or self is frozen, the state is unchanged and false is returned. Otherwise true is returned.

Example

Set the state. The first set is succesful while the second fails.

use std::cell::Cell;
use state::TypeMap;

let type_map = <TypeMap![]>::new();
assert!(type_map.set(Cell::new(10)));
assert!(!type_map.set(Cell::new(17)));
source§

impl<K: Kind> TypeMap<K>

source

pub fn try_get<T: 'static>(&self) -> Option<&T>

Attempts to retrieve the global state for type T.

Returns Some if the state has previously been set. Otherwise returns None.

Example
use state::TypeMap;

static TYPE_MAP: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();

struct MyState(AtomicUsize);

// State for `T` is initially unset.
assert!(TYPE_MAP.try_get::<MyState>().is_none());

TYPE_MAP.set(MyState(AtomicUsize::new(0)));

let my_state = TYPE_MAP.try_get::<MyState>().expect("MyState");
assert_eq!(my_state.0.load(Ordering::Relaxed), 0);
source

pub fn get<T: 'static>(&self) -> &T

Retrieves the global state for type T.

Panics

Panics if the state for type T has not previously been set(). Use try_get() for a non-panicking version.

Example
use state::TypeMap;

static TYPE_MAP: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();

struct MyState(AtomicUsize);

TYPE_MAP.set(MyState(AtomicUsize::new(0)));

let my_state = TYPE_MAP.get::<MyState>();
assert_eq!(my_state.0.load(Ordering::Relaxed), 0);
source

pub fn freeze(&mut self)

Freezes the type_map. A frozen type_map disallows writes allowing for synchronization-free reads.

Example
use state::TypeMap;

// A new type_map starts unfrozen and can be written to.
let mut type_map = <TypeMap![Send + Sync]>::new();
assert_eq!(type_map.set(1usize), true);

// While unfrozen, `get`s require synchronization.
assert_eq!(type_map.get::<usize>(), &1);

// After freezing, calls to `set` or `set_local `will fail.
type_map.freeze();
assert_eq!(type_map.set(1u8), false);
assert_eq!(type_map.set("hello"), false);

// Calls to `get` or `get_local` are synchronization-free when frozen.
assert_eq!(type_map.try_get::<u8>(), None);
assert_eq!(type_map.get::<usize>(), &1);
source

pub fn is_frozen(&self) -> bool

Returns true if the type_map is frozen and false otherwise.

Example
use state::TypeMap;

// A new type_map starts unfrozen and is frozen using `freeze`.
let mut type_map = <TypeMap![Send]>::new();
assert_eq!(type_map.is_frozen(), false);

type_map.freeze();
assert_eq!(type_map.is_frozen(), true);
source

pub fn len(&self) -> usize

Returns the number of distinctly typed values in self.

Example
use state::TypeMap;

let type_map = <TypeMap![Send + Sync]>::new();
assert_eq!(type_map.len(), 0);

assert_eq!(type_map.set(1usize), true);
assert_eq!(type_map.len(), 1);

assert_eq!(type_map.set(2usize), false);
assert_eq!(type_map.len(), 1);

assert_eq!(type_map.set(1u8), true);
assert_eq!(type_map.len(), 2);
source

pub fn is_empty(&self) -> bool

Returns true if self contains zero values.

Example
use state::TypeMap;

let type_map = <TypeMap![Send + Sync]>::new();
assert!(type_map.is_empty());

assert_eq!(type_map.set(1usize), true);
assert!(!type_map.is_empty());

Trait Implementations§

source§

impl<K: Kind> Debug for TypeMap<K>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Send for TypeMap<Send>

source§

impl Send for TypeMap<SendSync>

source§

impl Sync for TypeMap<SendSync>

Auto Trait Implementations§

§

impl<K> !RefUnwindSafe for TypeMap<K>

§

impl<K> !Send for TypeMap<K>

§

impl<K> !Sync for TypeMap<K>

§

impl<K> Unpin for TypeMap<K>

§

impl<K> !UnwindSafe for TypeMap<K>

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.