use std::ops::Deref;
use std::ops::DerefMut;
use std::sync::Arc;
#[cfg(debug_assertions)]
use std::time::Duration;
#[cfg(debug_assertions)]
use std::time::Instant;
#[derive(Default, Clone, Debug)]
pub struct ExtensionsMutex {
extensions: Arc<parking_lot::Mutex<super::Extensions>>,
}
impl ExtensionsMutex {
#[deprecated]
pub fn lock(&self) -> ExtensionsGuard {
ExtensionsGuard::new(&self.extensions)
}
pub fn with_lock<'a, T, F: FnOnce(ExtensionsGuard<'a>) -> T>(&'a self, func: F) -> T {
let locked = ExtensionsGuard::new(&self.extensions);
func(locked)
}
}
pub struct ExtensionsGuard<'a> {
#[cfg(debug_assertions)]
start: Instant,
guard: parking_lot::MutexGuard<'a, super::Extensions>,
}
impl<'a> ExtensionsGuard<'a> {
fn new(guard: &'a parking_lot::Mutex<super::Extensions>) -> Self {
Self {
guard: guard.lock(),
#[cfg(debug_assertions)]
start: Instant::now(),
}
}
}
impl Deref for ExtensionsGuard<'_> {
type Target = super::Extensions;
fn deref(&self) -> &super::Extensions {
&self.guard
}
}
impl DerefMut for ExtensionsGuard<'_> {
fn deref_mut(&mut self) -> &mut super::Extensions {
&mut self.guard
}
}
#[cfg(debug_assertions)]
impl Drop for ExtensionsGuard<'_> {
fn drop(&mut self) {
if let Ok(runtime) = tokio::runtime::Handle::try_current() {
if runtime.runtime_flavor() == tokio::runtime::RuntimeFlavor::MultiThread {
let elapsed = self.start.elapsed();
if elapsed > Duration::from_millis(10) {
panic!(
"ExtensionsGuard held for {}ms. This is probably a bug that will stall the Router and cause performance problems. Run with `RUST_BACKTRACE=1` environment variable to display a backtrace",
elapsed.as_millis()
);
}
}
}
}
}