use crate::sync::{AtomicU8, Ordering};
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum StreamPolicy {
#[default]
PerThread,
PerTask,
Single,
}
const SET_BY_USER: u8 = 0b1000_0000;
static POLICY: AtomicU8 = AtomicU8::new(0);
fn encode(policy: StreamPolicy) -> u8 {
match policy {
StreamPolicy::PerThread => 0,
StreamPolicy::PerTask => 1,
StreamPolicy::Single => 2,
}
}
fn decode(bits: u8) -> StreamPolicy {
match bits & !SET_BY_USER {
1 => StreamPolicy::PerTask,
2 => StreamPolicy::Single,
_ => StreamPolicy::PerThread,
}
}
pub fn set_policy(policy: StreamPolicy) {
POLICY.store(encode(policy) | SET_BY_USER, Ordering::Relaxed);
}
pub fn policy() -> StreamPolicy {
decode(POLICY.load(Ordering::Relaxed))
}
#[doc(hidden)]
pub fn set_policy_from_config(policy: StreamPolicy) {
let _ = POLICY.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| {
if current & SET_BY_USER != 0 {
None
} else {
Some(encode(policy))
}
});
}
#[cfg(all(test, feature = "std"))]
pub(crate) fn tests_reset_policy() {
POLICY.store(0, Ordering::Relaxed);
}
#[cfg(all(test, feature = "std"))]
pub(crate) fn tests_policy_lock() -> std::sync::MutexGuard<'static, ()> {
static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
LOCK.lock().unwrap_or_else(|poisoned| poisoned.into_inner())
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
#[test]
fn explicit_policy_wins_over_config() {
let _guard = tests_policy_lock();
set_policy_from_config(StreamPolicy::Single);
assert_eq!(policy(), StreamPolicy::Single);
set_policy(StreamPolicy::PerTask);
set_policy_from_config(StreamPolicy::Single);
assert_eq!(policy(), StreamPolicy::PerTask);
tests_reset_policy();
}
}