pub struct Projection { /* private fields */ }Expand description
Pull-based, queryable view of the event stream
Projection consumes events from an EventReceiver in the background and provides read
access to accumulated state at any time. TUI applications query the projection on each render
frame without interacting with the event system directly.
Construction starts a background drain task via tokio::spawn. The task reads events from
the receiver, translates each into an Entry, and appends it to internal storage. When the
event channel closes (all senders dropped), the task marks the projection as complete.
Query methods take &self and return cloned snapshots of the accumulated state. The drain
task and query callers synchronize through a RwLock, allowing concurrent reads from
multiple render frames without blocking on each other.
§Examples
use clawless_core::event::{Event, event_channel};
use clawless_tui::projection::Projection;
let (sender, receiver) = event_channel();
let projection = Projection::new(receiver);
sender.send(Event::Message("processing".to_string()))
.await
.expect("should send");
drop(sender);
// Wait for the drain task, which finishes once the dropped sender closes the channel
while !projection.is_complete() {
tokio::task::yield_now().await;
}
let messages = projection.messages();
assert_eq!(messages.len(), 1);Implementations§
Source§impl Projection
impl Projection
Sourcepub fn new(receiver: EventReceiver) -> Self
pub fn new(receiver: EventReceiver) -> Self
Creates a new projection that drains events from the given receiver
Spawns a background task that reads events from receiver, translates each into an
Entry, and appends it to internal storage. The task runs until the event channel
closes, at which point it marks the projection as complete.
The returned projection is immediately ready to query. Early queries return empty results until events arrive.
§Panics
Panics if called outside of a Tokio runtime.
§Examples
use clawless_core::event::event_channel;
use clawless_tui::projection::Projection;
let (_sender, receiver) = event_channel();
let projection = Projection::new(receiver);
assert!(projection.entries().is_empty());Sourcepub fn entries(&self) -> Vec<Entry>
pub fn entries(&self) -> Vec<Entry>
Returns all accumulated entries in receive order
Returns a cloned snapshot of the entry list. The snapshot is consistent: it reflects all events drained up to the moment the read lock is acquired.
§Panics
Panics if the internal lock is poisoned.
Sourcepub fn messages(&self) -> Vec<Entry>
pub fn messages(&self) -> Vec<Entry>
Returns accumulated message entries only
Equivalent to calling entries and filtering to Entry::Message variants.
§Panics
Panics if the internal lock is poisoned.
Sourcepub fn details(&self) -> Vec<Entry>
pub fn details(&self) -> Vec<Entry>
Returns accumulated detail entries only
Equivalent to calling entries and filtering to Entry::Detail variants.
§Panics
Panics if the internal lock is poisoned.
Sourcepub fn artifacts(&self) -> Vec<Entry>
pub fn artifacts(&self) -> Vec<Entry>
Returns accumulated artifact entries only
Equivalent to calling entries and filtering to Entry::Artifact variants.
§Panics
Panics if the internal lock is poisoned.
Sourcepub fn is_complete(&self) -> bool
pub fn is_complete(&self) -> bool
Reports whether the event stream has closed and all buffered events have been drained
Returns true once all EventSenders have been dropped and the drain task has
processed every buffered event. Before that point, returns false.
§Panics
Panics if the internal lock is poisoned.