[][src]Struct state::Container

pub struct Container { /* fields omitted */ }

A container for global type-based state.

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

Global State

Global state is set via the set method and retrieved via the get method. The type of the value being set must be thread-safe and transferable across thread boundaries. In other words, it must satisfy Sync + Send + 'static.

Example

Set and later retrieve a value of type T:

static CONTAINER: state::Container = state::Container::new();

CONTAINER.set(T::new());
CONTAINER.get::<T>();

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 Container. A frozen container can only be read and never written to. Attempts to write to a frozen container will fail.

To freeze a Container, call freeze(). A frozen container can never be thawed. To check if a container is frozen, call is_frozen().

Thread-Local State

Thread-local state 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 A in B.

Example

Set and later retrieve a value of type T:

static CONTAINER: state::Container = state::Container::new();

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

Implementations

impl Container[src]

pub const fn new() -> Container[src]

Creates a new container with no stored values.

Example

Create a globally available state container:

static CONTAINER: state::Container = state::Container::new();

pub fn freeze(&mut self)[src]

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

Example

use state::Container;

// A new container starts unfrozen and can be written to.
let mut container = Container::new();
assert_eq!(container.set(1usize), true);

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

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

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

pub fn is_frozen(&self) -> bool[src]

Returns true if the container is frozen and false otherwise.

Example

use state::Container;

// A new container starts unfrozen and is frozen using `freeze`.
let mut container = Container::new();
assert_eq!(container.is_frozen(), false);

container.freeze();
assert_eq!(container.is_frozen(), true);

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

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.

static CONTAINER: state::Container = state::Container::new();

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

pub fn try_get<T: Send + Sync + 'static>(&self) -> Option<&T>[src]

Attempts to retrieve the global state for type T.

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

Example

struct MyState(AtomicUsize);

static CONTAINER: state::Container = state::Container::new();

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

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

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

pub fn get<T: Send + Sync + 'static>(&self) -> &T[src]

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

struct MyState(AtomicUsize);

static CONTAINER: state::Container = state::Container::new();

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

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

pub fn set_local<T, F>(&self, state_init: F) -> bool where
    T: Send + 'static,
    F: Fn() -> T + 'static, 
[src]

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

struct MyState(Cell<usize>);

static CONTAINER: state::Container = state::Container::new();

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

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

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

struct MyState(Cell<usize>);

static CONTAINER: state::Container = state::Container::new();

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

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

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

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

struct MyState(Cell<usize>);

static CONTAINER: state::Container = state::Container::new();

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

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

Trait Implementations

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

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

The type returned in the event of a conversion error.