Crate illicit[−][src]
Expand description
An implicit environment which is indexed by type.
Offering values to the local environment
Add types to the local environment by creating and enter
ing a Layer
,
and retrieve them using get
or expect
:
#[derive(Copy, Clone, Debug, PartialEq)]
enum Theme {
Light,
Dark,
}
// no theme has been set yet
assert!(illicit::get::<Theme>().is_err());
illicit::Layer::new().offer(Theme::Light).enter(|| {
assert_eq!(*illicit::expect::<Theme>(), Theme::Light,);
});
// previous theme "expired"
assert!(illicit::get::<Theme>().is_err());
Receiving arguments “by environment”
Annotate functions which require access to types in the environment with
from_env
:
impl Theme {
/// Calls `child` with this theme set as current.
fn set<R>(self, child: impl FnOnce() -> R) -> R {
illicit::Layer::new().offer(self).enter(child)
}
/// Retrieves the current theme. Panics if none has been set.
#[illicit::from_env(current_theme: &Theme)]
fn current() -> Self {
*current_theme
}
}
Theme::Light.set(|| {
assert_eq!(Theme::current(), Theme::Light);
// we can set a temporary override for part of our call tree
Theme::Dark.set(|| assert_eq!(Theme::current(), Theme::Dark));
// but it only lasts as long as the inner `enter` call
assert_eq!(Theme::current(), Theme::Light);
});
Caution
This provides convenient sugar for values stored in the current environment as an alternative to thread-locals or a manually propagated context object. However this approach incurs a significant cost in that the following code will panic:
println!("{:?}", Theme::current());
See the attribute’s documentation for more details, and please consider whether this is appropriate for your use case before taking it on as a dependency.
Debugging
Use Snapshot::get
to retrieve a copy of the current local environment.
Comparisons
execution-context
illicit
provides capabilities very similar in ways to
execution-context. Both crates allow one to propagate implicit values to
“downstream” code, and they both allow that downstream code to provide its
own additional values to the context. Both crates prevent mutation of
contained types without interior mutability.
One notable difference is how they handle multi-threading.
execution-context
requires types contained in a “flow-local” to implement
Send
so that contexts can be sent between threads. In contrast, while
illicit
supports the reuse of contexts, it prioritizes the single-threaded
use case and does not require Send
.
The other noteworthy difference is in how they’re “addressed”:
execution-context
defines static variables that are referenced by
name/symbol, whereas illicit
allows the definition of a single local value
per type and does not rely on naming. This offers some nice properties but
it also sacrifices the static guarantee that there will always be a default
value.
thread_local!
This crate is implemented on top of a thread-local variable which stores the context, and can be seen as utilities for dynamically creating and destroying thread-locals for arbitrary types. The other key difference is that the ability to temporarily override a thread-local is built-in.
The main cost over writing one’s own thread-local is that this does incur
the additional overhead of a HashMap
access, some TypeId
comparison, and
some pointer dereferences.
Structs
A failure to find a particular type in the local context.
A container for the local environment, usually used to represent a pending addition to it.
A point-in-time representation of the implicit environment.
Traits
Implemented by types that can offer themselves as context to a child call.
Functions
Returns a reference to a value in the current environment, as
get
does, but panics if the value has not been set.
Returns a reference to a value in the current environment if it is present.
Removes the provided type from the current environment for the remainder of its scope. Parent environments may still possess a reference to the value.
Attribute Macros
Defines required illicit::get
values for a function. Binds the provided
types as if references to them were implicit function arguments: