pub mod error;
mod value;
mod registry;
mod scope;
mod storage;
mod snapshot;
mod wire;
mod helpers;
#[cfg(feature = "context-key")]
mod context_key;
mod config;
#[cfg(feature = "context-future")]
mod context_future;
#[macro_use]
mod macros;
pub use error::ContextError;
pub use scope::ScopeGuard;
pub use snapshot::ContextSnapshot;
#[cfg(feature = "context-key")]
pub use context_key::ContextKey;
pub use registry::{RegistryBuilder, RegistrationOptions,
initialize, try_initialize,
with_metadata, keys_with_metadata};
#[cfg(test)]
pub(crate) use registry::{register, try_register, register_with, try_register_with,
register_local, try_register_local,
register_migration, try_register_migration};
pub use storage::{enter_scope, enter_named_scope, scope, scope_chain, force_thread_local};
pub use storage::{scope_async, named_scope_async};
pub use snapshot::{snapshot, attach, wrap_with_context, wrap_with_context_fn};
pub use helpers::spawn_with_context;
pub use helpers::{with_context, spawn_with_context_async};
#[cfg(feature = "context-future")]
pub use context_future::{ContextFuture, with_context_future};
pub use wire::{serialize_context, deserialize_context, make_wire_bytes, make_wire_bytes_v};
#[cfg(feature = "base64")]
pub use wire::{serialize_context_string, deserialize_context_string};
pub use config::{set_max_context_size, max_context_size,
set_max_scope_chain_len, max_scope_chain_len};
use std::any::TypeId;
pub fn get_context<T>(key: &'static str) -> T
where
T: Clone + Default + Send + Sync + 'static,
{
try_get_context::<T>(key)
.expect("dcontext::get_context: key not registered")
.unwrap_or_default()
}
pub fn get_context_option<T>(key: &'static str) -> Option<T>
where
T: Clone + Default + Send + Sync + 'static,
{
try_get_context::<T>(key)
.expect("dcontext::get_context_option: key not registered")
}
pub fn try_get_context<T>(key: &'static str) -> Result<Option<T>, ContextError>
where
T: Clone + Default + Send + Sync + 'static,
{
let arc = storage::get_value(key);
match arc {
Some(val) => {
let any_ref = val.as_any();
match any_ref.downcast_ref::<T>() {
Some(typed) => Ok(Some(typed.clone())),
None => {
let registered_name =
registry::with_registration(key, |r| r.type_name).unwrap_or("unknown");
Err(ContextError::TypeMismatch(
key.to_string(),
registered_name.to_string(),
std::any::type_name::<T>().to_string(),
))
}
}
}
None => {
match registry::with_registration(key, |r| (r.type_id, r.type_name)) {
None => Err(ContextError::NotRegistered(key.to_string())),
Some((tid, type_name)) if tid != TypeId::of::<T>() => {
Err(ContextError::TypeMismatch(
key.to_string(),
type_name.to_string(),
std::any::type_name::<T>().to_string(),
))
}
Some(_) => Ok(None),
}
}
}
}
pub fn set_context<T>(key: &'static str, value: T)
where
T: Clone + Send + Sync + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
try_set_context(key, value).expect("dcontext::set_context failed");
}
pub fn try_set_context<T>(key: &'static str, value: T) -> Result<(), ContextError>
where
T: Clone + Send + Sync + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
match registry::with_registration(key, |r| (r.type_id, r.type_name)) {
None => return Err(ContextError::NotRegistered(key.to_string())),
Some((tid, type_name)) if tid != TypeId::of::<T>() => {
return Err(ContextError::TypeMismatch(
key.to_string(),
type_name.to_string(),
std::any::type_name::<T>().to_string(),
));
}
Some(_) => {}
}
storage::set_value(key, std::sync::Arc::new(value));
Ok(())
}
pub fn set_context_local<T>(key: &'static str, value: T)
where
T: Clone + Send + Sync + 'static,
{
try_set_context_local(key, value).expect("dcontext::set_context_local failed");
}
pub fn try_set_context_local<T>(key: &'static str, value: T) -> Result<(), ContextError>
where
T: Clone + Send + Sync + 'static,
{
match registry::with_registration(key, |r| (r.type_id, r.type_name)) {
None => return Err(ContextError::NotRegistered(key.to_string())),
Some((tid, type_name)) if tid != TypeId::of::<T>() => {
return Err(ContextError::TypeMismatch(
key.to_string(),
type_name.to_string(),
std::any::type_name::<T>().to_string(),
));
}
Some(_) => {}
}
storage::set_value(key, std::sync::Arc::new(crate::value::LocalValue(value)));
Ok(())
}
pub fn with_context_value<R>(
key: &str,
f: impl FnOnce(&dyn std::any::Any) -> R,
) -> Option<R> {
storage::get_value(key).map(|arc_val| f(arc_val.as_any()))
}
pub fn update_context<T>(key: &'static str, f: impl FnOnce(T) -> T)
where
T: Clone + Default + Send + Sync + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
try_update_context::<T>(key, f).expect("dcontext::update_context failed");
}
pub fn try_update_context<T>(key: &'static str, f: impl FnOnce(T) -> T) -> Result<(), ContextError>
where
T: Clone + Default + Send + Sync + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
let old = try_get_context::<T>(key)?.unwrap_or_default();
let new = f(old);
try_set_context(key, new)
}
pub fn update_context_local<T>(key: &'static str, f: impl FnOnce(T) -> T)
where
T: Clone + Default + Send + Sync + 'static,
{
try_update_context_local::<T>(key, f).expect("dcontext::update_context_local failed");
}
pub fn try_update_context_local<T>(key: &'static str, f: impl FnOnce(T) -> T) -> Result<(), ContextError>
where
T: Clone + Default + Send + Sync + 'static,
{
let old = try_get_context::<T>(key)?.unwrap_or_default();
let new = f(old);
try_set_context_local(key, new)
}
#[cfg(test)]
mod tests;