use std::cell::{Cell, RefCell};
use smallvec::SmallVec;
use std::rc::Rc;
use std::sync::atomic::{AtomicU64, Ordering};
pub struct HandlerList<F: ?Sized> {
handlers: RefCell<Option<Rc<Handlers<F>>>>,
next_id: HandlerIds,
}
type Handlers<F> = SmallVec<[(u64, Rc<F>); 2]>;
pub struct HandlerSnapshot<F: ?Sized>(Option<Rc<Handlers<F>>>);
impl<F: ?Sized> Clone for HandlerSnapshot<F> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<F: ?Sized> std::ops::Deref for HandlerSnapshot<F> {
type Target = [(u64, Rc<F>)];
#[inline]
fn deref(&self) -> &[(u64, Rc<F>)] {
match &self.0 {
Some(handlers) => handlers,
None => &[],
}
}
}
enum HandlerIds {
Own(Cell<u64>),
Shared(Rc<Cell<u64>>),
Ordered,
}
static ORDERED_IDS: AtomicU64 = AtomicU64::new(1);
impl HandlerIds {
fn next(&self) -> u64 {
let cell = match self {
Self::Own(cell) => cell,
Self::Shared(cell) => cell,
Self::Ordered => return ORDERED_IDS.fetch_add(1, Ordering::Relaxed),
};
let id = cell.get();
cell.set(id + 1);
id
}
}
impl<F: ?Sized> Default for HandlerList<F> {
fn default() -> Self {
Self::new()
}
}
impl<F: ?Sized> HandlerList<F> {
pub fn new() -> Self {
Self { handlers: RefCell::new(None), next_id: HandlerIds::Own(Cell::new(1)) }
}
pub fn with_shared_ids(ids: Rc<Cell<u64>>) -> Self {
Self { handlers: RefCell::new(None), next_id: HandlerIds::Shared(ids) }
}
pub fn with_ordered_ids() -> Self {
Self { handlers: RefCell::new(None), next_id: HandlerIds::Ordered }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.handlers.borrow().as_ref().is_none_or(|handlers| handlers.is_empty())
}
pub fn len(&self) -> usize {
self.handlers.borrow().as_ref().map_or(0, |handlers| handlers.len())
}
pub fn add(&self, handler: Rc<F>) -> u64 {
let id = self.next_id.next();
let mut handlers = self.handlers.borrow_mut();
let handlers = handlers.get_or_insert_with(|| Rc::new(SmallVec::new()));
Rc::make_mut_or_clone(handlers).push((id, handler));
id
}
pub fn remove(&self, token: u64) -> bool {
let mut handlers = self.handlers.borrow_mut();
let Some(handlers) = handlers.as_mut() else {
return false;
};
match handlers.iter().position(|(id, _)| *id == token) {
Some(index) => {
Rc::make_mut_or_clone(handlers).remove(index);
true
}
None => false,
}
}
#[inline]
pub fn snapshot(&self) -> HandlerSnapshot<F> {
HandlerSnapshot(self.handlers.borrow().clone())
}
}
trait MakeMutOrClone<T> {
fn make_mut_or_clone(this: &mut Self) -> &mut T;
}
impl<F: ?Sized> MakeMutOrClone<Handlers<F>> for Rc<Handlers<F>> {
fn make_mut_or_clone(this: &mut Self) -> &mut Handlers<F> {
if Rc::get_mut(this).is_none() {
let copy: Handlers<F> = this.iter().map(|(id, f)| (*id, f.clone())).collect();
*this = Rc::new(copy);
}
Rc::get_mut(this).expect("uniquely owned after copy")
}
}