Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-event/src/registry.rs')
-rw-r--r--helix-event/src/registry.rs131
1 files changed, 0 insertions, 131 deletions
diff --git a/helix-event/src/registry.rs b/helix-event/src/registry.rs
deleted file mode 100644
index 551d7014..00000000
--- a/helix-event/src/registry.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-//! A global registry where events are registered and can be
-//! subscribed to by registering hooks. The registry identifies event
-//! types using their type name so multiple event with the same type name
-//! may not be registered (will cause a panic to ensure soundness)
-
-use std::any::TypeId;
-
-use anyhow::{bail, Result};
-use hashbrown::hash_map::Entry;
-use hashbrown::HashMap;
-use parking_lot::RwLock;
-
-use crate::hook::ErasedHook;
-use crate::runtime_local;
-
-pub struct Registry {
- events: HashMap<&'static str, TypeId, foldhash::fast::FixedState>,
- handlers: HashMap<&'static str, Vec<ErasedHook>, foldhash::fast::FixedState>,
-}
-
-impl Registry {
- pub fn register_event<E: Event + 'static>(&mut self) {
- let ty = TypeId::of::<E>();
- assert_eq!(ty, TypeId::of::<E::Static>());
- match self.events.entry(E::ID) {
- Entry::Occupied(entry) => {
- if entry.get() == &ty {
- // don't warn during tests to avoid log spam
- #[cfg(not(feature = "integration_test"))]
- panic!("Event {} was registered multiple times", E::ID);
- } else {
- panic!("Multiple events with ID {} were registered", E::ID);
- }
- }
- Entry::Vacant(ent) => {
- ent.insert(ty);
- self.handlers.insert(E::ID, Vec::new());
- }
- }
- }
-
- /// # Safety
- ///
- /// `hook` must be totally generic over all lifetime parameters of `E`. For
- /// example if `E` was a known type `Foo<'a, 'b> then the correct trait bound
- /// would be `F: for<'a, 'b, 'c> Fn(&'a mut Foo<'b, 'c>)` but there is no way to
- /// express that kind of constraint for a generic type with the rust type system
- /// right now.
- pub unsafe fn register_hook<E: Event>(
- &mut self,
- hook: impl Fn(&mut E) -> Result<()> + 'static + Send + Sync,
- ) {
- // ensure event type ids match so we can rely on them always matching
- let id = E::ID;
- let Some(&event_id) = self.events.get(id) else {
- panic!("Tried to register handler for unknown event {id}");
- };
- assert!(
- TypeId::of::<E::Static>() == event_id,
- "Tried to register invalid hook for event {id}"
- );
- let hook = ErasedHook::new(hook);
- self.handlers.get_mut(id).unwrap().push(hook);
- }
-
- pub fn register_dynamic_hook(
- &mut self,
- hook: impl Fn() -> Result<()> + 'static + Send + Sync,
- id: &str,
- ) -> Result<()> {
- // ensure event type ids match so we can rely on them always matching
- if self.events.get(id).is_none() {
- bail!("Tried to register handler for unknown event {id}");
- };
- let hook = ErasedHook::new_dynamic(hook);
- self.handlers.get_mut(id).unwrap().push(hook);
- Ok(())
- }
-
- pub fn dispatch<E: Event>(&self, mut event: E) {
- let Some(hooks) = self.handlers.get(E::ID) else {
- log::error!("Dispatched unknown event {}", E::ID);
- return;
- };
- let event_id = self.events[E::ID];
-
- assert_eq!(
- TypeId::of::<E::Static>(),
- event_id,
- "Tried to dispatch invalid event {}",
- E::ID
- );
-
- for hook in hooks {
- // safety: event type is the same
- if let Err(err) = unsafe { hook.call(&mut event) } {
- log::error!("{} hook failed: {err:#?}", E::ID);
- crate::status::report_blocking(err);
- }
- }
- }
-}
-
-runtime_local! {
- static REGISTRY: RwLock<Registry> = RwLock::new(Registry {
- // hardcoded random number is good enough here we don't care about DOS resistance
- // and avoids the additional complexity of `Option<Registry>`
- events: HashMap::with_hasher(foldhash::fast::FixedState::with_seed(72536814787)),
- handlers: HashMap::with_hasher(foldhash::fast::FixedState::with_seed(72536814787)),
- });
-}
-
-pub(crate) fn with<T>(f: impl FnOnce(&Registry) -> T) -> T {
- f(&REGISTRY.read())
-}
-
-pub(crate) fn with_mut<T>(f: impl FnOnce(&mut Registry) -> T) -> T {
- f(&mut REGISTRY.write())
-}
-
-/// # Safety
-/// The number of specified lifetimes and the static type *must* be correct.
-/// This is ensured automatically by the [`events`](crate::events)
-/// macro.
-pub unsafe trait Event: Sized {
- /// Globally unique (case sensitive) string that identifies this type.
- /// A good candidate is the events type name
- const ID: &'static str;
- const LIFETIMES: usize;
- type Static: Event + 'static;
-}