1use kvas_ecs::Entity;
21use serde_json::Value;
22
23#[derive(Clone, Debug, PartialEq)]
25pub struct Signal {
26 pub sequence: u64,
28 pub channel: String,
30 pub sender: Option<Entity>,
32 pub target: Option<Entity>,
34 pub payload: Value,
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
40pub enum SignalError {
41 EmptyChannel,
43 Full,
45 SequenceExhausted,
47 TargetNotAlive,
49}
50
51impl std::fmt::Display for SignalError {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 f.write_str(match self {
54 Self::EmptyChannel => "signal channel is empty",
55 Self::Full => "signal pending buffer is full",
56 Self::SequenceExhausted => "signal sequence exhausted",
57 Self::TargetNotAlive => "signal target is not alive",
58 })
59 }
60}
61impl std::error::Error for SignalError {}
62
63#[derive(Clone, Debug)]
67pub struct SignalBus {
68 incoming: Vec<Signal>,
69 pending: Vec<Signal>,
70 capacity: usize,
71 sequence: u64,
72}
73
74impl Default for SignalBus {
75 fn default() -> Self {
76 Self::with_capacity(256)
77 }
78}
79
80impl SignalBus {
81 pub fn with_capacity(capacity: usize) -> Self {
83 Self { incoming: Vec::new(), pending: Vec::new(), capacity, sequence: 0 }
84 }
85 pub fn send(&mut self, channel: &str, payload: Value, sender: Option<Entity>, target: Option<Entity>) -> Result<u64, SignalError> {
89 if channel.trim().is_empty() {
90 return Err(SignalError::EmptyChannel);
91 }
92 if self.pending.len() >= self.capacity {
93 return Err(SignalError::Full);
94 }
95 let sequence = self.sequence.checked_add(1).ok_or(SignalError::SequenceExhausted)?;
96 self.pending.push(Signal { sequence, channel: channel.to_owned(), sender, target, payload });
97 self.sequence = sequence;
98 Ok(sequence)
99 }
100 pub fn begin_frame(&mut self) {
103 self.incoming.clear();
104 std::mem::swap(&mut self.incoming, &mut self.pending);
105 }
106 pub fn incoming(&self) -> &[Signal] {
108 &self.incoming
109 }
110 pub fn channel<'a>(&'a self, channel: &'a str) -> impl Iterator<Item = &'a Signal> {
112 self.incoming.iter().filter(move |signal| signal.channel == channel)
113 }
114 pub fn for_entity(&self, entity: Entity) -> impl Iterator<Item = &Signal> {
116 self.incoming.iter().filter(move |signal| signal.target.is_none_or(|target| target == entity))
117 }
118 pub fn pending_len(&self) -> usize {
120 self.pending.len()
121 }
122 pub fn capacity(&self) -> usize {
124 self.capacity
125 }
126 pub fn clear(&mut self) {
128 self.incoming.clear();
129 self.pending.clear();
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 #[test]
137 fn buffering_limits_and_entity_generations_are_respected() {
138 let mut world = kvas_ecs::World::new();
139 let old = world.spawn();
140 let mut bus = SignalBus::with_capacity(2);
141 assert_eq!(bus.send("", Value::Null, None, None), Err(SignalError::EmptyChannel));
142 assert_eq!(bus.send("a", Value::Null, None, Some(old)), Ok(1));
143 assert_eq!(bus.send("a", Value::Null, None, None), Ok(2));
144 assert_eq!(bus.send("a", Value::Null, None, None), Err(SignalError::Full));
145 assert!(bus.incoming().is_empty());
146 bus.begin_frame();
147 assert_eq!(bus.for_entity(old).count(), 2);
148 world.despawn(old);
149 let new = world.spawn();
150 assert_eq!(old.index(), new.index());
151 assert_eq!(bus.for_entity(new).count(), 1);
152 assert_eq!(bus.send("a", Value::Null, None, None), Ok(3));
153 bus.begin_frame();
154 assert_eq!(bus.incoming().len(), 1);
155 assert_eq!(bus.incoming()[0].sequence, 3);
156 bus.clear();
157 assert_eq!(bus.pending_len(), 0);
158 assert!(bus.incoming().is_empty());
159 }
160}