callback_collection.rs

  1use std::sync::Arc;
  2use std::{hash::Hash, sync::Weak};
  3
  4use parking_lot::Mutex;
  5
  6use collections::{btree_map, BTreeMap, HashMap};
  7
  8use crate::MutableAppContext;
  9
 10pub type Mapping<K, F> = Mutex<HashMap<K, BTreeMap<usize, Option<F>>>>;
 11
 12pub struct CallbackCollection<K: Hash + Eq, F> {
 13    internal: Arc<Mapping<K, F>>,
 14}
 15
 16impl<K: Hash + Eq, F> Clone for CallbackCollection<K, F> {
 17    fn clone(&self) -> Self {
 18        Self {
 19            internal: self.internal.clone(),
 20        }
 21    }
 22}
 23
 24impl<K: Hash + Eq + Copy, F> Default for CallbackCollection<K, F> {
 25    fn default() -> Self {
 26        CallbackCollection {
 27            internal: Arc::new(Mutex::new(Default::default())),
 28        }
 29    }
 30}
 31
 32impl<K: Hash + Eq + Copy, F> CallbackCollection<K, F> {
 33    pub fn downgrade(&self) -> Weak<Mapping<K, F>> {
 34        Arc::downgrade(&self.internal)
 35    }
 36
 37    #[cfg(test)]
 38    pub fn is_empty(&self) -> bool {
 39        self.internal.lock().is_empty()
 40    }
 41
 42    pub fn add_callback(&mut self, id: K, subscription_id: usize, callback: F) {
 43        self.internal
 44            .lock()
 45            .entry(id)
 46            .or_default()
 47            .insert(subscription_id, Some(callback));
 48    }
 49
 50    pub fn remove(&mut self, id: K) {
 51        self.internal.lock().remove(&id);
 52    }
 53
 54    pub fn add_or_remove_callback(&mut self, id: K, subscription_id: usize, callback: F) {
 55        match self
 56            .internal
 57            .lock()
 58            .entry(id)
 59            .or_default()
 60            .entry(subscription_id)
 61        {
 62            btree_map::Entry::Vacant(entry) => {
 63                entry.insert(Some(callback));
 64            }
 65
 66            btree_map::Entry::Occupied(entry) => {
 67                // TODO: This seems like it should never be called because no code
 68                // should ever attempt to remove an existing callback
 69                debug_assert!(entry.get().is_none());
 70                entry.remove();
 71            }
 72        }
 73    }
 74
 75    pub fn emit_and_cleanup<C: FnMut(&mut F, &mut MutableAppContext) -> bool>(
 76        &mut self,
 77        id: K,
 78        cx: &mut MutableAppContext,
 79        mut call_callback: C,
 80    ) {
 81        let callbacks = self.internal.lock().remove(&id);
 82        if let Some(callbacks) = callbacks {
 83            for (subscription_id, callback) in callbacks {
 84                if let Some(mut callback) = callback {
 85                    let alive = call_callback(&mut callback, cx);
 86                    if alive {
 87                        match self
 88                            .internal
 89                            .lock()
 90                            .entry(id)
 91                            .or_default()
 92                            .entry(subscription_id)
 93                        {
 94                            btree_map::Entry::Vacant(entry) => {
 95                                entry.insert(Some(callback));
 96                            }
 97                            btree_map::Entry::Occupied(entry) => {
 98                                entry.remove();
 99                            }
100                        }
101                    }
102                }
103            }
104        }
105    }
106}