use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Default)]
pub struct Focus {
current: Arc<AtomicU64>,
next_id: AtomicU64,
}
impl Focus {
pub fn new() -> Self {
Self::default()
}
pub fn handle(&self) -> FocusHandle {
let id = self.next_id.fetch_add(1, Ordering::Relaxed) + 1;
FocusHandle {
id,
current: Arc::clone(&self.current),
}
}
pub fn blur_all(&self) {
self.current.store(0, Ordering::Relaxed);
}
}
#[derive(Clone)]
pub struct FocusHandle {
id: u64,
current: Arc<AtomicU64>,
}
impl FocusHandle {
pub fn focus(&self) {
self.current.store(self.id, Ordering::Relaxed);
}
pub fn blur(&self) {
let _ = self
.current
.compare_exchange(self.id, 0, Ordering::Relaxed, Ordering::Relaxed);
}
pub fn is_focused(&self) -> bool {
self.current.load(Ordering::Relaxed) == self.id
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn exactly_one_handle_focused() {
let focus = Focus::new();
let a = focus.handle();
let b = focus.handle();
assert!(!a.is_focused() && !b.is_focused());
a.focus();
assert!(a.is_focused() && !b.is_focused());
b.focus();
assert!(!a.is_focused() && b.is_focused());
}
#[test]
fn blur_only_affects_the_holder() {
let focus = Focus::new();
let a = focus.handle();
let b = focus.handle();
a.focus();
b.blur(); assert!(a.is_focused());
a.blur();
assert!(!a.is_focused() && !b.is_focused());
}
#[test]
fn clones_share_identity() {
let focus = Focus::new();
let a = focus.handle();
let a2 = a.clone();
a.focus();
assert!(a2.is_focused());
}
}