use std::sync::Arc;
use std::sync::atomic::{AtomicU8, Ordering};
use crate::SkillTrustLevel;
#[derive(Clone, Debug)]
pub struct TurnTrustFloor(Arc<AtomicU8>);
impl TurnTrustFloor {
#[must_use]
pub fn new(initial: SkillTrustLevel) -> Self {
Self(Arc::new(AtomicU8::new(initial.severity())))
}
pub fn set(&self, level: SkillTrustLevel) {
self.0.store(level.severity(), Ordering::Relaxed);
}
pub fn fold(&self, level: SkillTrustLevel) {
let _ = self
.0
.try_update(Ordering::Relaxed, Ordering::Relaxed, |cur| {
let current = SkillTrustLevel::from_severity(cur);
Some(current.min_trust(level).severity())
});
}
#[must_use]
pub fn get(&self) -> SkillTrustLevel {
SkillTrustLevel::from_severity(self.0.load(Ordering::Relaxed))
}
}
impl Default for TurnTrustFloor {
fn default() -> Self {
Self::new(SkillTrustLevel::Trusted)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn set_replaces_unconditionally_in_either_direction() {
let floor = TurnTrustFloor::new(SkillTrustLevel::Quarantined);
floor.set(SkillTrustLevel::Trusted);
assert_eq!(floor.get(), SkillTrustLevel::Trusted);
floor.set(SkillTrustLevel::Blocked);
assert_eq!(floor.get(), SkillTrustLevel::Blocked);
}
#[test]
fn fold_lowers_trust() {
let floor = TurnTrustFloor::new(SkillTrustLevel::Trusted);
floor.fold(SkillTrustLevel::Quarantined);
assert_eq!(floor.get(), SkillTrustLevel::Quarantined);
}
#[test]
fn fold_never_raises_trust() {
let floor = TurnTrustFloor::new(SkillTrustLevel::Quarantined);
floor.fold(SkillTrustLevel::Trusted);
assert_eq!(
floor.get(),
SkillTrustLevel::Quarantined,
"fold must never raise trust above the current floor"
);
}
#[test]
fn fold_to_blocked_is_sticky_until_a_fresh_set() {
let floor = TurnTrustFloor::new(SkillTrustLevel::Verified);
floor.fold(SkillTrustLevel::Blocked);
floor.fold(SkillTrustLevel::Trusted);
assert_eq!(floor.get(), SkillTrustLevel::Blocked);
floor.set(SkillTrustLevel::Trusted);
assert_eq!(
floor.get(),
SkillTrustLevel::Trusted,
"only a fresh turn-start set recovers trust, never fold"
);
}
#[test]
fn clone_shares_the_same_underlying_cell() {
let floor = TurnTrustFloor::new(SkillTrustLevel::Trusted);
let clone = floor.clone();
clone.fold(SkillTrustLevel::Quarantined);
assert_eq!(
floor.get(),
SkillTrustLevel::Quarantined,
"clones must observe writes through any other clone"
);
}
#[test]
fn default_starts_trusted() {
assert_eq!(TurnTrustFloor::default().get(), SkillTrustLevel::Trusted);
}
}