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>
impl TypeMap<SendSync>
sourcepub const fn new() -> Self
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();
sourcepub fn set<T: Send + Sync + 'static>(&self, state: T) -> bool
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§impl TypeMap<Send>
impl TypeMap<Send>
sourcepub fn new() -> Self
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);
sourcepub fn set<T: Send + 'static>(&self, state: T) -> bool
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>
impl TypeMap<Neither>
sourcepub fn new() -> Self
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);
sourcepub fn set<T: 'static>(&self, state: T) -> bool
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>
impl<K: Kind> TypeMap<K>
sourcepub fn try_get<T: 'static>(&self) -> Option<&T>
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);
sourcepub fn get<T: 'static>(&self) -> &T
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);
sourcepub fn freeze(&mut self)
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);
sourcepub fn is_frozen(&self) -> bool
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);
sourcepub fn len(&self) -> usize
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);