use core::sync::atomic::{AtomicU8, Ordering};
#[cfg(feature = "supports-colors")]
pub fn with_override<T, F: FnOnce() -> T>(enabled: bool, f: F) -> T {
let previous = OVERRIDE.inner();
OVERRIDE.set_force(enabled);
let _guard = ResetOverrideGuard { previous };
f()
}
struct ResetOverrideGuard {
previous: u8,
}
impl Drop for ResetOverrideGuard {
fn drop(&mut self) {
OVERRIDE.set_unchecked(self.previous);
}
}
#[cfg(feature = "supports-colors")]
pub fn set_override(enabled: bool) {
OVERRIDE.set_force(enabled);
}
#[cfg(feature = "supports-colors")]
pub fn unset_override() {
OVERRIDE.unset();
}
pub(crate) static OVERRIDE: Override = Override::none();
pub(crate) struct Override(AtomicU8);
const FORCE_MASK: u8 = 0b10;
const FORCE_ENABLE: u8 = 0b11;
const FORCE_DISABLE: u8 = 0b10;
const NO_FORCE: u8 = 0b00;
impl Override {
const fn none() -> Self {
Self(AtomicU8::new(NO_FORCE))
}
fn inner(&self) -> u8 {
self.0.load(Ordering::SeqCst)
}
pub(crate) fn is_force_enabled_or_disabled(&self) -> (bool, bool) {
let inner = self.inner();
(inner == FORCE_ENABLE, inner == FORCE_DISABLE)
}
fn set_force(&self, enable: bool) {
self.set_unchecked(FORCE_MASK | (enable as u8));
}
fn unset(&self) {
self.set_unchecked(0);
}
fn set_unchecked(&self, value: u8) {
self.0.store(value, Ordering::SeqCst);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn with_override_on_panic() {
set_override(false);
std::panic::catch_unwind(|| {
with_override(true, || {
assert_eq!(OVERRIDE.inner(), FORCE_ENABLE);
panic!("test");
});
})
.expect_err("test should panic");
assert_eq!(
OVERRIDE.inner(),
FORCE_DISABLE,
"override should have been reset"
);
}
}