Skip to main content

dais_core/
bus.rs

1use crate::commands::Command;
2
3/// MPSC command bus for dispatching user actions to the presentation engine.
4///
5/// All user actions — from keyboard input, mouse events, or future external
6/// control surfaces — are sent as [`Command`] values through this bus.
7/// The engine polls the receiving end each frame via `try_recv()`.
8pub struct CommandBus {
9    sender: crossbeam_channel::Sender<Command>,
10    receiver: crossbeam_channel::Receiver<Command>,
11}
12
13/// Cloneable handle for sending commands into the bus.
14///
15/// Input sources (keyboard handler, mouse handler, future REST API, etc.)
16/// each hold a `CommandSender` and dispatch commands independently.
17#[derive(Clone)]
18pub struct CommandSender {
19    inner: crossbeam_channel::Sender<Command>,
20}
21
22/// Receiving end of the command bus, held by the engine.
23pub struct CommandReceiver {
24    inner: crossbeam_channel::Receiver<Command>,
25}
26
27impl CommandBus {
28    /// Create a new command bus.
29    pub fn new() -> Self {
30        let (sender, receiver) = crossbeam_channel::unbounded();
31        Self { sender, receiver }
32    }
33
34    /// Get a cloneable sender handle for dispatching commands.
35    pub fn sender(&self) -> CommandSender {
36        CommandSender { inner: self.sender.clone() }
37    }
38
39    /// Consume the bus and return the receiver (for the engine).
40    pub fn into_receiver(self) -> CommandReceiver {
41        CommandReceiver { inner: self.receiver }
42    }
43}
44
45impl Default for CommandBus {
46    fn default() -> Self {
47        Self::new()
48    }
49}
50
51impl CommandSender {
52    /// Send a command to the engine. Returns an error if the receiver is dropped.
53    pub fn send(&self, command: Command) -> Result<(), crossbeam_channel::SendError<Command>> {
54        self.inner.send(command)
55    }
56}
57
58impl CommandReceiver {
59    /// Try to receive a command without blocking. Returns `None` if the bus is empty.
60    pub fn try_recv(&self) -> Option<Command> {
61        self.inner.try_recv().ok()
62    }
63
64    /// Drain all pending commands from the bus.
65    pub fn drain(&self) -> Vec<Command> {
66        let mut commands = Vec::new();
67        while let Some(cmd) = self.try_recv() {
68            commands.push(cmd);
69        }
70        commands
71    }
72}