Skip to main content

EventBus

Struct EventBus 

Source
pub struct EventBus { /* private fields */ }
Expand description

Type-erased event bus for pub/sub communication.

The EventBus routes events to registered handlers based on event type. It uses lock-free data structures for the hot dispatch path and copy-on-write for subscription updates.

§Thread Safety

EventBus is Clone, Send, and Sync. Cloning creates a new handle to the same underlying bus. Multiple threads can dispatch events concurrently without blocking.

§Handler Ordering

Handlers are called in priority order (lower priority number = earlier). For handlers with the same priority, registration order is preserved.

§Two Usage Patterns

  1. Simple/Tests: Use new() with emit_async() and process_queue()
  2. Runtime: Use new_with_channel() with sender() and take_receiver()

Implementations§

Source§

impl EventBus

Source

pub fn new() -> Self

Create a new empty event bus.

This creates an EventBus without a channel. Use emit_async() and process_queue() for deferred event processing.

For runtime integration with a dedicated processor thread, use new_with_channel() instead.

Source

pub fn new_with_channel(capacity: usize) -> Self

Create an event bus with a channel for dedicated processor thread.

This is the preferred constructor for runtime integration where events are processed by a dedicated OS thread using blocking_recv().

§Arguments
  • capacity - Bounded channel capacity (typically 1024)
§Usage Pattern
let bus = EventBus::new_with_channel(1024);

// Get sender for emitting events
let sender = bus.sender().unwrap();

// Take receiver for processor thread
let mut receiver = bus.take_receiver().unwrap();

// Spawn processor thread
std::thread::spawn(move || {
    while let Some(event) = receiver.blocking_recv() {
        // Process event
    }
});

// Emit events from anywhere
sender.send(MyEvent { ... });
Source

pub fn sender(&self) -> Option<EventSender>

Get a cloneable sender for emitting events via channel.

Returns None if the EventBus was created without a channel.

§Example
let bus = EventBus::new_with_channel(1024);
let sender = bus.sender().expect("bus has channel");

sender.try_send(MyEvent { ... });
Source

pub fn take_receiver(&self) -> Option<BoundedReceiver<DynEvent>>

Take the receiver for the dedicated processor thread.

Can only be called once. Subsequent calls return None.

§Example
let bus = EventBus::new_with_channel(1024);
let receiver = bus.take_receiver().expect("bus has channel");

// Spawn processor thread
std::thread::spawn(move || {
    while let Some(event) = receiver.blocking_recv() {
        // Process event
    }
});
Source

pub fn subscribe<E, F>(&self, priority: u32, handler: F) -> Subscription
where E: Event, F: Fn(&E) -> EventResult + Send + Sync + 'static,

Subscribe a handler for events of type E.

Returns a Subscription handle that unsubscribes when dropped.

§Arguments
  • priority - Handler priority (lower = called earlier). Convention:
    • 0-50: Core/critical handlers
    • 100: Default priority
    • 200+: Low priority (cleanup, logging)
  • handler - Function called for each event of type E
§Example
use reovim_kernel::api::v1::*;

#[derive(Debug)]
struct MyEvent { value: i32 }
impl Event for MyEvent {}

let bus = EventBus::new();

let sub = bus.subscribe::<MyEvent, _>(100, |event| {
    println!("Received: {:?}", event.value);
    EventResult::Handled
});

// Handler is active while `sub` is alive
bus.emit(MyEvent { value: 42 });

// Dropping `sub` removes the handler
drop(sub);
Source

pub fn subscribe_with_context<E, F>( &self, priority: u32, handler: F, ) -> Subscription
where E: Event, F: Fn(&E, &mut HandlerContext<'_>) -> EventResult + Send + Sync + 'static,

Subscribe a context-aware handler for events of type E.

Similar to subscribe, but the handler receives a HandlerContext that allows emitting new events, requesting renders, etc.

§Arguments
  • priority - Handler priority (lower = called earlier)
  • handler - Function called for each event, with access to context
§Example
use reovim_kernel::api::v1::*;

#[derive(Debug)]
struct MyEvent { value: i32 }
impl Event for MyEvent {}

#[derive(Debug)]
struct FollowUpEvent;
impl Event for FollowUpEvent {}

let bus = EventBus::new();

let sub = bus.subscribe_with_context::<MyEvent, _>(100, |event, ctx| {
    // Emit a follow-up event
    ctx.emit(FollowUpEvent);
    // Request render
    ctx.request_render();
    EventResult::Handled
});
Source

pub fn subscribe_targeted<E, F>( &self, target: &str, priority: u32, handler: F, ) -> Subscription
where E: TargetedEvent, F: Fn(&E, &mut HandlerContext<'_>) -> EventResult + Send + Sync + 'static,

Subscribe a handler for targeted events, filtering by target.

The handler is only called when event.target() matches the specified target string.

§Arguments
  • target - Target string to filter events
  • priority - Handler priority (lower = called earlier)
  • handler - Function called for matching events
§Example
use reovim_kernel::api::v1::*;

#[derive(Debug)]
struct PluginInput {
    target: &'static str,
    value: i32,
}
impl Event for PluginInput {}
impl TargetedEvent for PluginInput {
    fn target(&self) -> &str { self.target }
}

let bus = EventBus::new();

// Only receives events where target == "my_plugin"
let sub = bus.subscribe_targeted::<PluginInput, _>("my_plugin", 100, |event, ctx| {
    println!("My plugin received: {}", event.value);
    EventResult::Handled
});
Source

pub fn emit<E: Event>(&self, event: E) -> EventResult

Emit an event synchronously.

Dispatches the event to all registered handlers in priority order. Returns the combined result of all handlers.

§Handler Behavior
  • Handlers are called in priority order (lower = first)
  • If any handler returns Consumed, dispatch stops
  • Otherwise continues until all handlers have been called
§Example
use reovim_kernel::api::v1::*;

#[derive(Debug)]
struct MyEvent;
impl Event for MyEvent {}

let bus = EventBus::new();
let result = bus.emit(MyEvent);
assert!(result.is_not_handled()); // No handlers registered
Source

pub fn emit_scoped<E: Event>(&self, event: E, scope: &EventScope) -> EventResult

Emit an event with scope tracking.

The scope’s counter is incremented before dispatch and decremented after all handlers complete. This allows callers to wait for all effects of the event to complete.

§Example
use reovim_kernel::api::v1::*;

#[derive(Debug)]
struct MyEvent;
impl Event for MyEvent {}

let bus = EventBus::new();
let scope = EventScope::new();

scope.increment(); // Manually increment before emit_scoped
let result = bus.emit_scoped(MyEvent, &scope);
// Scope counter is now decremented
Source

pub fn emit_async<E: Event>(&self, event: E)

Queue an event for later processing.

The event is stored in an internal queue and processed when process_queue() is called. This is useful for deferring event dispatch to avoid reentrancy issues.

§Example
use reovim_kernel::api::v1::*;

#[derive(Debug)]
struct MyEvent;
impl Event for MyEvent {}

let bus = EventBus::new();

bus.emit_async(MyEvent);
bus.emit_async(MyEvent);

// Events are queued but not dispatched yet
let count = bus.process_queue();
assert_eq!(count, 2);
Source

pub fn emit_async_scoped<E: Event>(&self, event: E, scope: &EventScope)

Queue an event with scope tracking for later processing.

Like emit_async, but attaches a scope for lifecycle tracking. The scope is incremented when queued and decremented after dispatch.

Source

pub fn process_queue(&self) -> usize

Process all queued events.

Drains the queue and dispatches each event synchronously. Returns the number of events processed.

§Scope Handling

For events with attached scopes, the scope is decremented after each event is dispatched.

Source

pub fn dispatch(&self, event: &DynEvent) -> EventResult

Dispatch a type-erased event to registered handlers.

This is the core dispatch logic, used by both emit and process_queue.

Source

pub fn dispatch_with_context( &self, event: &DynEvent, ctx: &mut HandlerContext<'_>, ) -> DispatchResult

Dispatch an event with handler context.

This allows handlers to emit new events, request renders, etc. Returns a DispatchResult containing the event result and any side effects (emitted events, render requests).

§Example
let mut ctx = HandlerContext::new().with_scope(Some(scope));
let result = bus.dispatch_with_context(&event, &mut ctx);

if result.render_requested {
    // Handle render request
}

// Process emitted events
for event in result.emitted_events {
    bus.dispatch(&event);
}
Source

pub fn handler_count<E: Event>(&self) -> usize

Get the number of handlers registered for a specific event type.

Useful for debugging and testing.

Source

pub fn total_handler_count(&self) -> usize

Get the total number of handlers registered across all event types.

Source

pub fn queue_len(&self) -> usize

Get the number of events in the async queue.

Source

pub fn queue_is_empty(&self) -> bool

Check if the async queue is empty.

Trait Implementations§

Source§

impl Clone for EventBus

Source§

fn clone(&self) -> EventBus

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for EventBus

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for EventBus

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.