#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/master/examples/res/image/zng-logo-icon.png")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/master/examples/res/image/zng-logo.png")]
#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
#![warn(unused_extern_crates)]
#![warn(missing_docs)]
use std::{
any::{Any, TypeId},
cell::RefCell,
fmt, mem, ops,
sync::Arc,
thread::LocalKey,
time::Duration,
};
use parking_lot::*;
use zng_txt::Txt;
use zng_unique_id::{unique_id_32, IdMap, IdSet};
unique_id_32! {
pub struct AppId;
}
zng_unique_id::impl_unique_id_name!(AppId);
zng_unique_id::impl_unique_id_fmt!(AppId);
impl serde::Serialize for AppId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let name = self.name();
if name.is_empty() {
use serde::ser::Error;
return Err(S::Error::custom("cannot serialize unnamed `AppId`"));
}
name.serialize(serializer)
}
}
impl<'de> serde::Deserialize<'de> for AppId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let name = Txt::deserialize(deserializer)?;
Ok(AppId::named(name))
}
}
#[derive(Clone, Copy)]
enum LocalValueKind {
Local,
Var,
App,
}
impl LocalValueKind {
fn include_local(self) -> bool {
!matches!(self, Self::Var)
}
fn include_var(self) -> bool {
!matches!(self, Self::Local)
}
}
type LocalValue = (Arc<dyn Any + Send + Sync>, LocalValueKind);
type LocalData = IdMap<TypeId, LocalValue>;
#[must_use = "ends the app scope on drop"]
pub struct AppScope {
id: AppId,
_same_thread: std::rc::Rc<()>,
}
impl Drop for AppScope {
fn drop(&mut self) {
LocalContext::end_app(self.id);
}
}
#[derive(Clone)]
pub struct LocalContext {
data: LocalData,
tracing: Option<tracing::dispatcher::Dispatch>,
}
impl fmt::Debug for LocalContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let app = self
.data
.get(&TypeId::of::<AppId>())
.map(|(v, _)| v.downcast_ref::<AppId>().unwrap())
.copied();
f.debug_struct("LocalContext")
.field("<app>", &app)
.field("<entries>", &(self.data.len() - 1))
.finish()
}
}
impl Default for LocalContext {
fn default() -> Self {
Self::new()
}
}
impl LocalContext {
pub const fn new() -> Self {
Self {
data: LocalData::new(),
tracing: None,
}
}
pub fn start_app(id: AppId) -> AppScope {
let valid = LOCAL.with_borrow_mut_dyn(|c| match c.entry(TypeId::of::<AppId>()) {
hashbrown::hash_map::Entry::Occupied(_) => false,
hashbrown::hash_map::Entry::Vacant(e) => {
e.insert((Arc::new(id), LocalValueKind::App));
true
}
});
assert!(valid, "cannot start app, another app is already in the thread context");
AppScope {
id,
_same_thread: std::rc::Rc::new(()),
}
}
fn end_app(id: AppId) {
let valid = LOCAL.with_borrow_mut_dyn(|c| {
if c.get(&TypeId::of::<AppId>())
.map(|(v, _)| v.downcast_ref::<AppId>() == Some(&id))
.unwrap_or(false)
{
Some(mem::take(&mut *c))
} else {
None
}
});
if let Some(data) = valid {
let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || {
drop(data); }));
if let Err(p) = r {
tracing::error!("panic on app drop. {}", panic_str(&p));
eprintln!("panic on app drop. {}", panic_str(&p));
std::process::exit(i32::from_le_bytes(*b"appa"));
}
} else {
tracing::error!("can only drop app in one of its threads");
eprintln!("can only drop app in one of its threads");
std::process::exit(i32::from_le_bytes(*b"appa"));
}
}
pub fn current_app() -> Option<AppId> {
LOCAL.with_borrow_dyn(|c| {
c.get(&TypeId::of::<AppId>())
.map(|(v, _)| v.downcast_ref::<AppId>().unwrap())
.copied()
})
}
pub fn register_cleanup(cleanup: impl FnOnce(AppId) + Send + 'static) {
let id = Self::current_app().expect("no app in context");
Self::register_cleanup_dyn(Box::new(move || cleanup(id)));
}
fn register_cleanup_dyn(cleanup: Box<dyn FnOnce() + Send>) {
let cleanup = RunOnDrop::new(cleanup);
type CleanupList = Vec<RunOnDrop<Box<dyn FnOnce() + Send>>>;
LOCAL.with_borrow_mut_dyn(|c| {
let c = c
.entry(TypeId::of::<CleanupList>())
.or_insert_with(|| (Arc::new(Mutex::new(CleanupList::new())), LocalValueKind::App));
c.0.downcast_ref::<Mutex<CleanupList>>().unwrap().lock().push(cleanup);
});
}
pub fn capture() -> Self {
Self {
data: LOCAL.with_borrow_dyn(|c| c.clone()),
tracing: Some(tracing::dispatcher::get_default(|d| d.clone())),
}
}
pub fn capture_filtered(filter: CaptureFilter) -> Self {
match filter {
CaptureFilter::None => Self::new(),
CaptureFilter::All => Self::capture(),
CaptureFilter::ContextVars { exclude } => {
let mut data = LocalData::new();
LOCAL.with_borrow_dyn(|c| {
for (k, (v, kind)) in c.iter() {
if kind.include_var() && !exclude.0.contains(k) {
data.insert(*k, (v.clone(), *kind));
}
}
});
Self { data, tracing: None }
}
CaptureFilter::ContextLocals { exclude } => {
let mut data = LocalData::new();
LOCAL.with_borrow_dyn(|c| {
for (k, (v, kind)) in c.iter() {
if kind.include_local() && !exclude.0.contains(k) {
data.insert(*k, (v.clone(), *kind));
}
}
});
Self {
data,
tracing: Some(tracing::dispatcher::get_default(|d| d.clone())),
}
}
CaptureFilter::Include(set) => {
let mut data = LocalData::new();
LOCAL.with_borrow_dyn(|c| {
for (k, v) in c.iter() {
if set.0.contains(k) {
data.insert(*k, v.clone());
}
}
});
Self {
data,
tracing: if set.contains(&TracingDispatcherContext) {
Some(tracing::dispatcher::get_default(|d| d.clone()))
} else {
None
},
}
}
CaptureFilter::Exclude(set) => {
let mut data = LocalData::new();
LOCAL.with_borrow_dyn(|c| {
for (k, v) in c.iter() {
if !set.0.contains(k) {
data.insert(*k, v.clone());
}
}
});
Self {
data,
tracing: if !set.contains(&TracingDispatcherContext) {
Some(tracing::dispatcher::get_default(|d| d.clone()))
} else {
None
},
}
}
}
}
pub fn value_set(&self) -> ContextValueSet {
let mut set = ContextValueSet::new();
LOCAL.with_borrow_dyn(|c| {
for k in c.keys() {
set.0.insert(*k);
}
});
set
}
pub fn with_context<R>(&mut self, f: impl FnOnce() -> R) -> R {
let data = mem::take(&mut self.data);
let prev = LOCAL.with_borrow_mut_dyn(|c| mem::replace(c, data));
let _tracing_restore = self.tracing.as_ref().map(tracing::dispatcher::set_default);
let _restore = RunOnDrop::new(|| {
self.data = LOCAL.with_borrow_mut_dyn(|c| mem::replace(c, prev));
});
f()
}
pub fn with_context_blend<R>(&mut self, over: bool, f: impl FnOnce() -> R) -> R {
if self.data.is_empty() {
f()
} else {
let prev = LOCAL.with_borrow_mut_dyn(|c| {
let (mut base, over) = if over { (c.clone(), &self.data) } else { (self.data.clone(), &*c) };
for (k, v) in over {
base.insert(*k, v.clone());
}
mem::replace(c, base)
});
let _restore = RunOnDrop::new(|| {
LOCAL.with_borrow_mut_dyn(|c| {
*c = prev;
});
});
f()
}
}
fn contains(key: TypeId) -> bool {
LOCAL.with_borrow_dyn(|c| c.contains_key(&key))
}
fn get(key: TypeId) -> Option<LocalValue> {
LOCAL.with_borrow_dyn(|c| c.get(&key).cloned())
}
fn set(key: TypeId, value: LocalValue) -> Option<LocalValue> {
LOCAL.with_borrow_mut_dyn(|c| c.insert(key, value))
}
fn remove(key: TypeId) -> Option<LocalValue> {
LOCAL.with_borrow_mut_dyn(|c| c.remove(&key))
}
fn with_value_ctx<T: Send + Sync + 'static>(
key: &'static ContextLocal<T>,
kind: LocalValueKind,
value: &mut Option<Arc<T>>,
f: impl FnOnce(),
) {
let key = key.key();
let prev = Self::set(key, (value.take().expect("no `value` to set"), kind));
let _restore = RunOnDrop::new(move || {
let back = if let Some(prev) = prev {
Self::set(key, prev)
} else {
Self::remove(key)
}
.unwrap();
*value = Some(Arc::downcast(back.0).unwrap());
});
f();
}
fn with_default_ctx<T: Send + Sync + 'static>(key: &'static ContextLocal<T>, f: impl FnOnce()) {
let key = key.key();
let prev = Self::remove(key);
let _restore = RunOnDrop::new(move || {
if let Some(prev) = prev {
Self::set(key, prev);
}
});
f()
}
}
thread_local! {
static LOCAL: RefCell<LocalData> = const {
RefCell::new(LocalData::new())
};
}
pub struct FullLocalContext(LocalContext);
impl FullLocalContext {}
impl ops::Deref for FullLocalContext {
type Target = LocalContext;
fn deref(&self) -> &Self::Target {
&self.0
}
}
trait LocalKeyDyn {
fn with_borrow_dyn<R>(&'static self, f: impl FnOnce(&LocalData) -> R) -> R;
fn with_borrow_mut_dyn<R>(&'static self, f: impl FnOnce(&mut LocalData) -> R) -> R;
}
impl LocalKeyDyn for LocalKey<RefCell<LocalData>> {
fn with_borrow_dyn<R>(&'static self, f: impl FnOnce(&LocalData) -> R) -> R {
let mut r = None;
let f = |l: &LocalData| r = Some(f(l));
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnOnce(&LocalData)> = Box::new(f);
self.with_borrow(f);
r.unwrap()
}
fn with_borrow_mut_dyn<R>(&'static self, f: impl FnOnce(&mut LocalData) -> R) -> R {
let mut r = None;
let f = |l: &mut LocalData| r = Some(f(l));
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnOnce(&mut LocalData)> = Box::new(f);
self.with_borrow_mut(f);
r.unwrap()
}
}
#[doc(hidden)]
pub struct AppLocalConst<T: Send + Sync + 'static> {
value: RwLock<T>,
}
impl<T: Send + Sync + 'static> AppLocalConst<T> {
pub const fn new(init: T) -> Self {
Self { value: RwLock::new(init) }
}
}
#[doc(hidden)]
pub struct AppLocalOption<T: Send + Sync + 'static> {
value: RwLock<Option<T>>,
init: fn() -> T,
}
impl<T: Send + Sync + 'static> AppLocalOption<T> {
pub const fn new(init: fn() -> T) -> Self {
Self {
value: RwLock::new(None),
init,
}
}
fn read_impl(&'static self, read: RwLockReadGuard<'static, Option<T>>) -> MappedRwLockReadGuard<T> {
if read.is_some() {
return RwLockReadGuard::map(read, |v| v.as_ref().unwrap());
}
drop(read);
let mut write = self.value.write();
if write.is_some() {
drop(write);
return self.read();
}
let value = (self.init)();
*write = Some(value);
let read = RwLockWriteGuard::downgrade(write);
RwLockReadGuard::map(read, |v| v.as_ref().unwrap())
}
fn write_impl(&'static self, mut write: RwLockWriteGuard<'static, Option<T>>) -> MappedRwLockWriteGuard<T> {
if write.is_some() {
return RwLockWriteGuard::map(write, |v| v.as_mut().unwrap());
}
let value = (self.init)();
*write = Some(value);
RwLockWriteGuard::map(write, |v| v.as_mut().unwrap())
}
}
#[doc(hidden)]
pub struct AppLocalVec<T: Send + Sync + 'static> {
value: RwLock<Vec<(AppId, T)>>,
init: fn() -> T,
}
impl<T: Send + Sync + 'static> AppLocalVec<T> {
pub const fn new(init: fn() -> T) -> Self {
Self {
value: RwLock::new(vec![]),
init,
}
}
fn cleanup(&'static self, id: AppId) {
self.try_cleanup(id, 0);
}
fn try_cleanup(&'static self, id: AppId, tries: u8) {
if let Some(mut w) = self.value.try_write_for(if tries == 0 {
Duration::from_millis(50)
} else {
Duration::from_millis(500)
}) {
if let Some(i) = w.iter().position(|(s, _)| *s == id) {
w.swap_remove(i);
}
} else if tries > 5 {
tracing::error!("failed to cleanup `app_local` for {id:?}, was locked after app drop");
} else {
std::thread::spawn(move || {
self.try_cleanup(id, tries + 1);
});
}
}
fn read_impl(&'static self, read: RwLockReadGuard<'static, Vec<(AppId, T)>>) -> MappedRwLockReadGuard<T> {
let id = LocalContext::current_app().expect("no app running, `app_local` can only be accessed inside apps");
if let Some(i) = read.iter().position(|(s, _)| *s == id) {
return RwLockReadGuard::map(read, |v| &v[i].1);
}
drop(read);
let mut write = self.value.write();
if write.iter().any(|(s, _)| *s == id) {
drop(write);
return self.read();
}
let value = (self.init)();
let i = write.len();
write.push((id, value));
LocalContext::register_cleanup(Box::new(move |id| self.cleanup(id)));
let read = RwLockWriteGuard::downgrade(write);
RwLockReadGuard::map(read, |v| &v[i].1)
}
fn write_impl(&'static self, mut write: RwLockWriteGuard<'static, Vec<(AppId, T)>>) -> MappedRwLockWriteGuard<T> {
let id = LocalContext::current_app().expect("no app running, `app_local` can only be accessed inside apps");
if let Some(i) = write.iter().position(|(s, _)| *s == id) {
return RwLockWriteGuard::map(write, |v| &mut v[i].1);
}
let value = (self.init)();
let i = write.len();
write.push((id, value));
LocalContext::register_cleanup(move |id| self.cleanup(id));
RwLockWriteGuard::map(write, |v| &mut v[i].1)
}
}
#[doc(hidden)]
pub trait AppLocalImpl<T: Send + Sync + 'static>: Send + Sync + 'static {
fn read(&'static self) -> MappedRwLockReadGuard<T>;
fn try_read(&'static self) -> Option<MappedRwLockReadGuard<T>>;
fn write(&'static self) -> MappedRwLockWriteGuard<T>;
fn try_write(&'static self) -> Option<MappedRwLockWriteGuard<T>>;
}
impl<T: Send + Sync + 'static> AppLocalImpl<T> for AppLocalVec<T> {
fn read(&'static self) -> MappedRwLockReadGuard<T> {
self.read_impl(self.value.read_recursive())
}
fn try_read(&'static self) -> Option<MappedRwLockReadGuard<T>> {
Some(self.read_impl(self.value.try_read_recursive()?))
}
fn write(&'static self) -> MappedRwLockWriteGuard<T> {
self.write_impl(self.value.write())
}
fn try_write(&'static self) -> Option<MappedRwLockWriteGuard<T>> {
Some(self.write_impl(self.value.try_write()?))
}
}
impl<T: Send + Sync + 'static> AppLocalImpl<T> for AppLocalOption<T> {
fn read(&'static self) -> MappedRwLockReadGuard<T> {
self.read_impl(self.value.read_recursive())
}
fn try_read(&'static self) -> Option<MappedRwLockReadGuard<T>> {
Some(self.read_impl(self.value.try_read_recursive()?))
}
fn write(&'static self) -> MappedRwLockWriteGuard<T> {
self.write_impl(self.value.write())
}
fn try_write(&'static self) -> Option<MappedRwLockWriteGuard<T>> {
Some(self.write_impl(self.value.try_write()?))
}
}
impl<T: Send + Sync + 'static> AppLocalImpl<T> for AppLocalConst<T> {
fn read(&'static self) -> MappedRwLockReadGuard<T> {
RwLockReadGuard::map(self.value.read(), |l| l)
}
fn try_read(&'static self) -> Option<MappedRwLockReadGuard<T>> {
Some(RwLockReadGuard::map(self.value.try_read()?, |l| l))
}
fn write(&'static self) -> MappedRwLockWriteGuard<T> {
RwLockWriteGuard::map(self.value.write(), |l| l)
}
fn try_write(&'static self) -> Option<MappedRwLockWriteGuard<T>> {
Some(RwLockWriteGuard::map(self.value.try_write()?, |l| l))
}
}
pub struct AppLocal<T: Send + Sync + 'static> {
inner: &'static dyn AppLocalImpl<T>,
}
impl<T: Send + Sync + 'static> AppLocal<T> {
#[doc(hidden)]
pub const fn new(inner: &'static dyn AppLocalImpl<T>) -> Self {
AppLocal { inner }
}
#[inline]
pub fn read(&'static self) -> MappedRwLockReadGuard<T> {
self.inner.read()
}
#[inline]
pub fn try_read(&'static self) -> Option<MappedRwLockReadGuard<T>> {
self.inner.try_read()
}
#[inline]
pub fn write(&'static self) -> MappedRwLockWriteGuard<T> {
self.inner.write()
}
pub fn try_write(&'static self) -> Option<MappedRwLockWriteGuard<T>> {
self.inner.try_write()
}
#[inline]
pub fn get(&'static self) -> T
where
T: Clone,
{
self.read().clone()
}
#[inline]
pub fn set(&'static self, value: T) {
*self.write() = value;
}
#[inline]
pub fn try_get(&'static self) -> Option<T>
where
T: Clone,
{
self.try_read().map(|l| l.clone())
}
#[inline]
pub fn try_set(&'static self, value: T) -> Result<(), T> {
match self.try_write() {
Some(mut l) => {
*l = value;
Ok(())
}
None => Err(value),
}
}
#[inline]
pub fn read_map<O>(&'static self, map: impl FnOnce(&T) -> &O) -> MappedRwLockReadGuard<O> {
MappedRwLockReadGuard::map(self.read(), map)
}
#[inline]
pub fn try_read_map<O>(&'static self, map: impl FnOnce(&T) -> &O) -> Option<MappedRwLockReadGuard<O>> {
let lock = self.try_read()?;
Some(MappedRwLockReadGuard::map(lock, map))
}
#[inline]
pub fn write_map<O>(&'static self, map: impl FnOnce(&mut T) -> &mut O) -> MappedRwLockWriteGuard<O> {
MappedRwLockWriteGuard::map(self.write(), map)
}
#[inline]
pub fn try_write_map<O>(&'static self, map: impl FnOnce(&mut T) -> &mut O) -> Option<MappedRwLockWriteGuard<O>> {
let lock = self.try_write()?;
Some(MappedRwLockWriteGuard::map(lock, map))
}
}
#[macro_export]
macro_rules! app_local {
($(
$(#[$meta:meta])*
$vis:vis static $IDENT:ident : $T:ty = $(const { $init_const:expr })? $($init:expr)?;
)+) => {$(
$crate::app_local_impl! {
$(#[$meta])*
$vis static $IDENT: $T = $(const { $init_const })? $($init)?;
}
)+};
}
#[doc(hidden)]
#[macro_export]
macro_rules! app_local_impl_single {
(
$(#[$meta:meta])*
$vis:vis static $IDENT:ident : $T:ty = const { $init:expr };
) => {
$(#[$meta])*
$vis static $IDENT: $crate::AppLocal<$T> = {
static IMPL: $crate::AppLocalConst<$T> = $crate::AppLocalConst::new($init);
$crate::AppLocal::new(&IMPL)
};
};
(
$(#[$meta:meta])*
$vis:vis static $IDENT:ident : $T:ty = $init:expr;
) => {
$(#[$meta])*
$vis static $IDENT: $crate::AppLocal<$T> = {
fn init() -> $T {
std::convert::Into::into($init)
}
static IMPL: $crate::AppLocalOption<$T> = $crate::AppLocalOption::new(init);
$crate::AppLocal::new(&IMPL)
};
};
(
$(#[$meta:meta])*
$vis:vis static $IDENT:ident : $T:ty = ($tt:tt)*
) => {
std::compile_error!("expected `const { $expr };` or `$expr;`")
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! app_local_impl_multi {
(
$(#[$meta:meta])*
$vis:vis static $IDENT:ident : $T:ty = const { $init:expr };
) => {
$(#[$meta])*
$vis static $IDENT: $crate::AppLocal<$T> = {
const fn init() -> $T {
$init
}
static IMPL: $crate::AppLocalVec<$T> = $crate::AppLocalVec::new(init);
$crate::AppLocal::new(&IMPL)
};
};
(
$(#[$meta:meta])*
$vis:vis static $IDENT:ident : $T:ty = $init:expr;
) => {
$(#[$meta])*
$vis static $IDENT: $crate::AppLocal<$T> = {
fn init() -> $T {
std::convert::Into::into($init)
}
static IMPL: $crate::AppLocalVec<$T> = $crate::AppLocalVec::new(init);
$crate::AppLocal::new(&IMPL)
};
};
(
$(#[$meta:meta])*
$vis:vis static $IDENT:ident : $T:ty = ($tt:tt)*
) => {
std::compile_error!("expected `const { $expr };` or `$expr;`")
};
}
#[cfg(feature = "multi_app")]
#[doc(hidden)]
pub use app_local_impl_multi as app_local_impl;
#[cfg(not(feature = "multi_app"))]
#[doc(hidden)]
pub use app_local_impl_single as app_local_impl;
#[doc(hidden)]
pub struct ContextLocalData<T: Send + Sync + 'static> {
key: fn() -> TypeId,
default_init: fn() -> T,
default_value: Option<Arc<T>>,
}
impl<T: Send + Sync + 'static> ContextLocalData<T> {
#[doc(hidden)]
pub const fn new(key: fn() -> TypeId, default_init: fn() -> T) -> Self {
Self {
key,
default_init,
default_value: None,
}
}
}
pub struct ContextLocal<T: Send + Sync + 'static> {
data: AppLocal<ContextLocalData<T>>,
}
impl<T: Send + Sync + 'static> ContextLocal<T> {
#[doc(hidden)]
pub const fn new(storage: &'static dyn AppLocalImpl<ContextLocalData<T>>) -> Self {
Self {
data: AppLocal::new(storage),
}
}
fn key(&'static self) -> TypeId {
(self.data.read().key)()
}
pub fn with_context<R>(&'static self, value: &mut Option<Arc<T>>, f: impl FnOnce() -> R) -> R {
let mut r = None;
let f = || r = Some(f());
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnOnce()> = Box::new(f);
LocalContext::with_value_ctx(self, LocalValueKind::Local, value, f);
r.unwrap()
}
pub fn with_context_var<R>(&'static self, value: &mut Option<Arc<T>>, f: impl FnOnce() -> R) -> R {
let mut r = None;
let f = || r = Some(f());
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnOnce()> = Box::new(f);
LocalContext::with_value_ctx(self, LocalValueKind::Var, value, f);
r.unwrap()
}
pub fn with_default<R>(&'static self, f: impl FnOnce() -> R) -> R {
let mut r = None;
let f = || r = Some(f());
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnOnce()> = Box::new(f);
LocalContext::with_default_ctx(self, f);
r.unwrap()
}
pub fn is_default(&'static self) -> bool {
let cl = self.data.read();
!LocalContext::contains((cl.key)())
}
pub fn get(&'static self) -> Arc<T> {
let cl = self.data.read();
match LocalContext::get((cl.key)()) {
Some(c) => Arc::downcast(c.0).unwrap(),
None => match &cl.default_value {
Some(d) => d.clone(),
None => {
drop(cl);
let mut cl = self.data.write();
match &cl.default_value {
None => {
let d = Arc::new((cl.default_init)());
cl.default_value = Some(d.clone());
d
}
Some(d) => d.clone(),
}
}
},
}
}
pub fn get_clone(&'static self) -> T
where
T: Clone,
{
let cl = self.data.read();
match LocalContext::get((cl.key)()) {
Some(c) => c.0.downcast_ref::<T>().unwrap().clone(),
None => match &cl.default_value {
Some(d) => d.as_ref().clone(),
None => {
drop(cl);
let mut cl = self.data.write();
match &cl.default_value {
None => {
let val = (cl.default_init)();
let r = val.clone();
cl.default_value = Some(Arc::new(val));
r
}
Some(d) => d.as_ref().clone(),
}
}
},
}
}
}
impl<T: Send + Sync + 'static> ContextLocal<RwLock<T>> {
pub fn read_only(&'static self) -> ReadOnlyRwLock<T> {
ReadOnlyRwLock::new(self.get())
}
pub fn read(&'static self) -> RwLockReadGuardOwned<T> {
RwLockReadGuardOwned::lock(self.get())
}
pub fn read_recursive(&'static self) -> RwLockReadGuardOwned<T> {
RwLockReadGuardOwned::lock_recursive(self.get())
}
pub fn write(&'static self) -> RwLockWriteGuardOwned<T> {
RwLockWriteGuardOwned::lock(self.get())
}
pub fn try_read(&'static self) -> Option<RwLockReadGuardOwned<T>> {
RwLockReadGuardOwned::try_lock(self.get())
}
pub fn try_read_recursive(&'static self) -> Option<RwLockReadGuardOwned<T>> {
RwLockReadGuardOwned::try_lock_recursive(self.get())
}
pub fn try_write(&'static self) -> Option<RwLockWriteGuardOwned<T>> {
RwLockWriteGuardOwned::try_lock(self.get())
}
}
pub struct RwLockReadGuardOwned<T: 'static> {
lock: parking_lot::RwLockReadGuard<'static, T>,
_owned: Arc<RwLock<T>>,
}
impl<T> RwLockReadGuardOwned<T> {
pub fn lock(own: Arc<RwLock<T>>) -> Self {
Self {
lock: unsafe { mem::transmute(own.read()) },
_owned: own,
}
}
pub fn lock_recursive(own: Arc<RwLock<T>>) -> Self {
Self {
lock: unsafe { mem::transmute(own.read_recursive()) },
_owned: own,
}
}
pub fn try_lock(own: Arc<RwLock<T>>) -> Option<Self> {
let lock = own.try_read()?;
Some(Self {
lock: unsafe { mem::transmute(lock) },
_owned: own,
})
}
pub fn try_lock_recursive(own: Arc<RwLock<T>>) -> Option<Self> {
let lock = own.try_read_recursive()?;
Some(Self {
lock: unsafe { mem::transmute(lock) },
_owned: own,
})
}
pub fn map<O>(guard: Self, map: impl FnOnce(&T) -> &O) -> MappedRwLockReadGuardOwned<T, O> {
MappedRwLockReadGuardOwned {
lock: parking_lot::RwLockReadGuard::map(guard.lock, map),
_owned: guard._owned,
}
}
}
impl<T> ops::Deref for RwLockReadGuardOwned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.lock.deref()
}
}
pub struct MappedRwLockReadGuardOwned<T: 'static, O: 'static> {
lock: parking_lot::MappedRwLockReadGuard<'static, O>,
_owned: Arc<RwLock<T>>,
}
impl<T, O> MappedRwLockReadGuardOwned<T, O> {
pub fn map<O2>(guard: Self, map: impl FnOnce(&O) -> &O2) -> MappedRwLockReadGuardOwned<T, O2> {
MappedRwLockReadGuardOwned {
lock: parking_lot::MappedRwLockReadGuard::map(guard.lock, map),
_owned: guard._owned,
}
}
}
impl<T, O> ops::Deref for MappedRwLockReadGuardOwned<T, O> {
type Target = O;
fn deref(&self) -> &Self::Target {
self.lock.deref()
}
}
pub struct RwLockWriteGuardOwned<T: 'static> {
lock: parking_lot::RwLockWriteGuard<'static, T>,
_owned: Arc<RwLock<T>>,
}
impl<T> RwLockWriteGuardOwned<T> {
pub fn lock(own: Arc<RwLock<T>>) -> Self {
Self {
lock: unsafe { mem::transmute(own.write()) },
_owned: own,
}
}
pub fn try_lock(own: Arc<RwLock<T>>) -> Option<Self> {
let lock = own.try_write()?;
Some(Self {
lock: unsafe { mem::transmute(lock) },
_owned: own,
})
}
pub fn map<O>(guard: Self, map: impl FnOnce(&mut T) -> &mut O) -> MappedRwLockWriteGuardOwned<T, O> {
MappedRwLockWriteGuardOwned {
lock: parking_lot::RwLockWriteGuard::map(guard.lock, map),
_owned: guard._owned,
}
}
}
impl<T> ops::Deref for RwLockWriteGuardOwned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.lock.deref()
}
}
impl<T> ops::DerefMut for RwLockWriteGuardOwned<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.lock.deref_mut()
}
}
pub struct MappedRwLockWriteGuardOwned<T: 'static, O: 'static> {
lock: parking_lot::MappedRwLockWriteGuard<'static, O>,
_owned: Arc<RwLock<T>>,
}
impl<T, O> MappedRwLockWriteGuardOwned<T, O> {
pub fn map<O2>(guard: Self, map: impl FnOnce(&mut O) -> &mut O2) -> MappedRwLockWriteGuardOwned<T, O2> {
MappedRwLockWriteGuardOwned {
lock: parking_lot::MappedRwLockWriteGuard::map(guard.lock, map),
_owned: guard._owned,
}
}
}
impl<T, O> ops::Deref for MappedRwLockWriteGuardOwned<T, O> {
type Target = O;
fn deref(&self) -> &Self::Target {
self.lock.deref()
}
}
impl<T, O> ops::DerefMut for MappedRwLockWriteGuardOwned<T, O> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.lock.deref_mut()
}
}
pub struct ReadOnlyRwLock<T>(Arc<RwLock<T>>);
impl<T> Clone for ReadOnlyRwLock<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> ReadOnlyRwLock<T> {
pub fn new(l: Arc<RwLock<T>>) -> Self {
Self(l)
}
pub fn read(&self) -> parking_lot::RwLockReadGuard<T> {
self.0.read()
}
pub fn read_recursive(&self) -> parking_lot::RwLockReadGuard<T> {
self.0.read_recursive()
}
pub fn try_read(&self) -> Option<parking_lot::RwLockReadGuard<T>> {
self.0.try_read()
}
pub fn try_read_recursive(&self) -> Option<parking_lot::RwLockReadGuard<T>> {
self.0.try_read_recursive()
}
pub fn ptr_eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0, &other.0)
}
}
#[macro_export]
macro_rules! context_local {
($(
$(#[$meta:meta])*
$vis:vis static $IDENT:ident : $T:ty = $init:expr;
)+) => {$(
$crate::context_local_impl! {
$(#[$meta])*
$vis static $IDENT: $T = $init;
}
)+};
}
#[doc(hidden)]
#[macro_export]
macro_rules! context_local_impl_single {
($(
$(#[$meta:meta])*
$vis:vis static $IDENT:ident : $T:ty = $init:expr;
)+) => {$(
$(#[$meta])*
$vis static $IDENT: $crate::ContextLocal<$T> = {
fn init() -> $T {
std::convert::Into::into($init)
}
fn key() -> std::any::TypeId {
struct Key { }
std::any::TypeId::of::<Key>()
}
static IMPL: $crate::AppLocalConst<$crate::ContextLocalData<$T>> =
$crate::AppLocalConst::new(
$crate::ContextLocalData::new(key, init)
);
$crate::ContextLocal::new(&IMPL)
};
)+};
}
#[doc(hidden)]
#[macro_export]
macro_rules! context_local_impl_multi {
($(
$(#[$meta:meta])*
$vis:vis static $IDENT:ident : $T:ty = $init:expr;
)+) => {$(
$(#[$meta])*
$vis static $IDENT: $crate::ContextLocal<$T> = {
fn init() -> $T {
std::convert::Into::into($init)
}
fn key() -> std::any::TypeId {
struct Key { }
std::any::TypeId::of::<Key>()
}
static IMPL: $crate::AppLocalVec<$crate::ContextLocalData<$T>> =
$crate::AppLocalVec::new(
|| $crate::ContextLocalData::new(key, init)
);
$crate::ContextLocal::new(&IMPL)
};
)+};
}
#[cfg(feature = "multi_app")]
#[doc(hidden)]
pub use context_local_impl_multi as context_local_impl;
#[cfg(not(feature = "multi_app"))]
#[doc(hidden)]
pub use context_local_impl_single as context_local_impl;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CaptureFilter {
None,
All,
ContextVars {
exclude: ContextValueSet,
},
ContextLocals {
exclude: ContextValueSet,
},
Include(ContextValueSet),
Exclude(ContextValueSet),
}
pub trait ContextLocalKeyProvider {
fn context_local_key(&'static self) -> TypeId;
}
impl<T: Send + Sync + 'static> ContextLocalKeyProvider for ContextLocal<T> {
fn context_local_key(&'static self) -> TypeId {
self.key()
}
}
pub struct TracingDispatcherContext;
impl ContextLocalKeyProvider for TracingDispatcherContext {
fn context_local_key(&'static self) -> TypeId {
TypeId::of::<tracing::dispatcher::Dispatch>()
}
}
#[derive(Default, Clone, PartialEq, Eq)]
pub struct ContextValueSet(IdSet<TypeId>);
impl ContextValueSet {
pub const fn new() -> Self {
Self(crate::IdSet::new())
}
pub fn insert(&mut self, value: &'static impl ContextLocalKeyProvider) -> bool {
self.0.insert(value.context_local_key())
}
pub fn remove(&mut self, value: &'static impl ContextLocalKeyProvider) -> bool {
self.0.remove(&value.context_local_key())
}
pub fn contains(&self, value: &'static impl ContextLocalKeyProvider) -> bool {
self.0.contains(&value.context_local_key())
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn insert_all(&mut self, other: &Self) {
self.0.extend(other.0.iter().copied());
}
pub fn remove_all(&mut self, other: &Self) {
for o in other.0.iter() {
self.0.remove(o);
}
}
}
impl fmt::Debug for ContextValueSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ContextValueSet").field("len()", &self.len()).finish()
}
}
pub struct RunOnDrop<F: FnOnce()>(Option<F>);
impl<F: FnOnce()> RunOnDrop<F> {
pub fn new(clean: F) -> Self {
RunOnDrop(Some(clean))
}
}
impl<F: FnOnce()> Drop for RunOnDrop<F> {
fn drop(&mut self) {
if let Some(clean) = self.0.take() {
clean();
}
}
}
fn panic_str<'s>(payload: &'s Box<dyn std::any::Any + Send + 'static>) -> &'s str {
if let Some(s) = payload.downcast_ref::<&str>() {
s
} else if let Some(s) = payload.downcast_ref::<String>() {
s
} else {
"<unknown-panic-message-type>"
}
}