use std::ops::{Deref, DerefMut};
use std::sync::{LockResult, Mutex, PoisonError};
pub(crate) mod rank {
pub(crate) const ROTATION: u16 = 100;
pub(crate) const LAST_FETCHED: u16 = 200;
pub(crate) const TOKENS: u16 = 250;
pub(crate) const USAGE_STORE: u16 = 300;
pub(crate) const USAGE_STATUS: u16 = 350;
pub(crate) const CONFIG: u16 = 400;
pub(crate) const STATE: u16 = 500;
pub(crate) const ACTIVITY: u16 = 600;
pub(crate) const LEARNED: u16 = 700;
pub(crate) const OK_COUNT: u16 = 800;
pub(crate) const CACHE_HIT: u16 = 900;
pub(crate) const LAST_429: u16 = 1000;
pub(crate) const NEXT_REFRESH: u16 = 1100;
pub(crate) const REFETCH_QUEUE: u16 = 1200;
pub(crate) const LAST_ROTATED_WINDOW: u16 = 1300;
pub(crate) const PENDING_WINDOW_ROTATION: u16 = 1400;
pub(crate) const PENDING_SWITCH: u16 = 1500;
pub(crate) const PENDING_AUTO_START: u16 = 1600;
pub(crate) const PENDING_SWITCH_OFF: u16 = 1700;
}
#[cfg(debug_assertions)]
thread_local! {
static HELD: std::cell::RefCell<Vec<u16>> = const { std::cell::RefCell::new(Vec::new()) };
}
pub(crate) struct RankGuard {
#[cfg(debug_assertions)]
rank: u16,
}
impl RankGuard {
#[inline]
pub(crate) fn enter(_rank: u16) -> Self {
#[cfg(debug_assertions)]
{
HELD.with(|h| {
let mut h = h.borrow_mut();
debug_assert!(
h.last().is_none_or(|&top| _rank > top),
"lock-order violation: acquiring rank {_rank} while holding {:?} \
(would invert the global lock order and risk deadlock)",
h.as_slice(),
);
h.push(_rank);
});
Self { rank: _rank }
}
#[cfg(not(debug_assertions))]
{
Self {}
}
}
}
impl Drop for RankGuard {
#[inline]
fn drop(&mut self) {
#[cfg(debug_assertions)]
HELD.with(|h| {
let mut h = h.borrow_mut();
if let Some(pos) = h.iter().rposition(|&r| r == self.rank) {
h.remove(pos);
}
});
}
}
pub(crate) struct RankedMutex<T, const RANK: u16> {
inner: Mutex<T>,
}
impl<T, const RANK: u16> RankedMutex<T, RANK> {
pub(crate) fn new(value: T) -> Self {
Self {
inner: Mutex::new(value),
}
}
pub(crate) fn lock(&self) -> LockResult<RankedGuard<'_, T>> {
let rank = RankGuard::enter(RANK);
match self.inner.lock() {
Ok(guard) => Ok(RankedGuard { guard, _rank: rank }),
Err(poison) => Err(PoisonError::new(RankedGuard {
guard: poison.into_inner(),
_rank: rank,
})),
}
}
}
pub(crate) struct RankedGuard<'a, T> {
guard: std::sync::MutexGuard<'a, T>,
_rank: RankGuard,
}
impl<T> Deref for RankedGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.guard
}
}
impl<T> DerefMut for RankedGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.guard
}
}