Skip to main content

cougr_core/
event.rs

1use soroban_sdk::{contracttype, symbol_short, Bytes, Env, Symbol, TryFromVal, Val, Vec};
2
3#[contracttype]
4#[derive(Debug, Clone)]
5pub struct Event {
6    pub event_type: Symbol,
7    pub data: Bytes,
8    pub timestamp: u64,
9}
10impl Event {
11    pub fn new(event_type: Symbol, data: Bytes) -> Self {
12        Self {
13            event_type,
14            data,
15            timestamp: 0,
16        }
17    }
18    pub fn with_timestamp(event_type: Symbol, data: Bytes, timestamp: u64) -> Self {
19        Self {
20            event_type,
21            data,
22            timestamp,
23        }
24    }
25    pub fn event_type(&self) -> &Symbol {
26        &self.event_type
27    }
28    pub fn data(&self) -> &Bytes {
29        &self.data
30    }
31    pub fn timestamp(&self) -> u64 {
32        self.timestamp
33    }
34}
35
36pub struct EventReader<'a> {
37    events: &'a [Event],
38    event_type: Symbol,
39    read_index: usize,
40}
41impl<'a> EventReader<'a> {
42    pub fn new(events: &'a [Event], event_type: Symbol) -> Self {
43        Self {
44            events,
45            event_type,
46            read_index: 0,
47        }
48    }
49    pub fn read(&mut self) -> Option<&Event> {
50        while self.read_index < self.events.len() {
51            let event = &self.events[self.read_index];
52            self.read_index += 1;
53            if event.event_type() == &self.event_type {
54                return Some(event);
55            }
56        }
57        None
58    }
59    pub fn has_more(&self) -> bool {
60        self.read_index < self.events.len()
61    }
62    pub fn reset(&mut self) {
63        self.read_index = 0;
64    }
65}
66
67pub struct EventWriter<'a> {
68    events: &'a mut Vec<Event>,
69}
70impl<'a> EventWriter<'a> {
71    pub fn new(events: &'a mut Vec<Event>) -> Self {
72        Self { events }
73    }
74    pub fn send(&mut self, event: Event) {
75        self.events.push_back(event);
76    }
77    pub fn send_with_data(&mut self, event_type: Symbol, data: Bytes) {
78        let event = Event::new(event_type, data);
79        self.send(event);
80    }
81    pub fn send_batch(&mut self, events: Vec<Event>) {
82        for event in events {
83            self.send(event);
84        }
85    }
86}
87
88pub trait EventTrait {
89    fn event_type() -> Symbol;
90    fn serialize(&self, env: &Env) -> Bytes;
91    fn deserialize(env: &Env, data: &Bytes) -> Option<Self>
92    where
93        Self: Sized;
94}
95
96#[contracttype]
97#[derive(Clone)]
98pub struct CollisionEvent {
99    pub entity_a: u64,
100    pub entity_b: u64,
101    pub collision_type: Symbol,
102}
103impl CollisionEvent {
104    pub fn new(entity_a: u64, entity_b: u64, collision_type: Symbol) -> Self {
105        Self {
106            entity_a,
107            entity_b,
108            collision_type,
109        }
110    }
111}
112impl EventTrait for CollisionEvent {
113    fn event_type() -> Symbol {
114        symbol_short!("collision")
115    }
116    fn serialize(&self, env: &Env) -> Bytes {
117        let mut bytes = Bytes::new(env);
118        bytes.append(&Bytes::from_slice(env, &self.entity_a.to_be_bytes()));
119        bytes.append(&Bytes::from_slice(env, &self.entity_b.to_be_bytes()));
120        // Serialize the collision_type symbol by converting to Val and then to u64
121        let symbol_val: Val = self.collision_type.to_val();
122        let symbol_bits = symbol_val.get_payload();
123        bytes.append(&Bytes::from_slice(env, &symbol_bits.to_be_bytes()));
124        bytes
125    }
126    fn deserialize(env: &Env, data: &Bytes) -> Option<Self> {
127        if data.len() < 24 {
128            return None;
129        }
130        let entity_a = u64::from_be_bytes([
131            data.get(0)?,
132            data.get(1)?,
133            data.get(2)?,
134            data.get(3)?,
135            data.get(4)?,
136            data.get(5)?,
137            data.get(6)?,
138            data.get(7)?,
139        ]);
140        let entity_b = u64::from_be_bytes([
141            data.get(8)?,
142            data.get(9)?,
143            data.get(10)?,
144            data.get(11)?,
145            data.get(12)?,
146            data.get(13)?,
147            data.get(14)?,
148            data.get(15)?,
149        ]);
150        // Deserialize the symbol from its Val representation
151        let symbol_bits = u64::from_be_bytes([
152            data.get(16)?,
153            data.get(17)?,
154            data.get(18)?,
155            data.get(19)?,
156            data.get(20)?,
157            data.get(21)?,
158            data.get(22)?,
159            data.get(23)?,
160        ]);
161        let symbol_val = Val::from_payload(symbol_bits);
162        let collision_type: Symbol = Symbol::try_from_val(env, &symbol_val).ok()?;
163        Some(Self {
164            entity_a,
165            entity_b,
166            collision_type,
167        })
168    }
169}
170
171#[contracttype]
172#[derive(Clone)]
173pub struct DamageEvent {
174    pub target_entity: u64,
175    pub damage_amount: i32,
176    pub damage_type: Symbol,
177}
178impl DamageEvent {
179    pub fn new(target_entity: u64, damage_amount: i32, damage_type: Symbol) -> Self {
180        Self {
181            target_entity,
182            damage_amount,
183            damage_type,
184        }
185    }
186}
187impl EventTrait for DamageEvent {
188    fn event_type() -> Symbol {
189        symbol_short!("damage")
190    }
191    fn serialize(&self, env: &Env) -> Bytes {
192        let mut bytes = Bytes::new(env);
193        bytes.append(&Bytes::from_slice(env, &self.target_entity.to_be_bytes()));
194        bytes.append(&Bytes::from_slice(env, &self.damage_amount.to_be_bytes()));
195        // Serialize the damage_type symbol by converting to Val and then to u64
196        let symbol_val: Val = self.damage_type.to_val();
197        let symbol_bits = symbol_val.get_payload();
198        bytes.append(&Bytes::from_slice(env, &symbol_bits.to_be_bytes()));
199        bytes
200    }
201    fn deserialize(env: &Env, data: &Bytes) -> Option<Self> {
202        if data.len() < 20 {
203            return None;
204        }
205        let target_entity = u64::from_be_bytes([
206            data.get(0)?,
207            data.get(1)?,
208            data.get(2)?,
209            data.get(3)?,
210            data.get(4)?,
211            data.get(5)?,
212            data.get(6)?,
213            data.get(7)?,
214        ]);
215        let damage_amount =
216            i32::from_be_bytes([data.get(8)?, data.get(9)?, data.get(10)?, data.get(11)?]);
217        // Deserialize the symbol from its Val representation
218        let symbol_bits = u64::from_be_bytes([
219            data.get(12)?,
220            data.get(13)?,
221            data.get(14)?,
222            data.get(15)?,
223            data.get(16)?,
224            data.get(17)?,
225            data.get(18)?,
226            data.get(19)?,
227        ]);
228        let symbol_val = Val::from_payload(symbol_bits);
229        let damage_type: Symbol = Symbol::try_from_val(env, &symbol_val).ok()?;
230        Some(Self {
231            target_entity,
232            damage_amount,
233            damage_type,
234        })
235    }
236}
237
238#[cfg(test)]
239mod tests {
240    use super::*;
241    use alloc::vec::Vec as StdVec;
242    use soroban_sdk::{symbol_short, Env, Vec};
243
244    #[test]
245    fn test_event_creation() {
246        let env = Env::default();
247        let event_type = symbol_short!("testevent");
248        let mut data = Bytes::new(&env);
249        data.append(&Bytes::from_array(&env, &[1, 2, 3, 4]));
250        let event = Event::new(event_type, data.clone());
251
252        assert_eq!(event.event_type(), &symbol_short!("testevent"));
253        assert_eq!(event.data(), &data);
254        assert_eq!(event.timestamp(), 0);
255    }
256
257    #[test]
258    fn test_collision_event_serialization() {
259        let env = Env::default();
260        let collision_event = CollisionEvent::new(123, 456, symbol_short!("physical"));
261
262        let data = collision_event.serialize(&env);
263        let deserialized = CollisionEvent::deserialize(&env, &data).unwrap();
264
265        assert_eq!(collision_event.entity_a, deserialized.entity_a);
266        assert_eq!(collision_event.entity_b, deserialized.entity_b);
267        assert_eq!(collision_event.collision_type, deserialized.collision_type);
268    }
269
270    #[test]
271    fn test_damage_event_serialization() {
272        let env = Env::default();
273        let damage_event = DamageEvent::new(789, 50, symbol_short!("fire"));
274
275        let data = damage_event.serialize(&env);
276        let deserialized = DamageEvent::deserialize(&env, &data).unwrap();
277
278        assert_eq!(damage_event.target_entity, deserialized.target_entity);
279        assert_eq!(damage_event.damage_amount, deserialized.damage_amount);
280        assert_eq!(damage_event.damage_type, deserialized.damage_type);
281    }
282
283    #[test]
284    fn test_event_writer_and_reader_filter_by_type() {
285        let env = Env::default();
286        let mut events = Vec::new(&env);
287        {
288            let mut writer = EventWriter::new(&mut events);
289            writer.send_with_data(symbol_short!("spawn"), Bytes::from_array(&env, &[1]));
290            writer.send_with_data(symbol_short!("move"), Bytes::from_array(&env, &[2]));
291            writer.send_with_data(symbol_short!("spawn"), Bytes::from_array(&env, &[3]));
292        }
293
294        let mut snapshot = StdVec::new();
295        for i in 0..events.len() {
296            snapshot.push(events.get(i).unwrap());
297        }
298        let mut reader = EventReader::new(&snapshot, symbol_short!("spawn"));
299
300        let first = reader.read().cloned().unwrap();
301        let second = reader.read().cloned().unwrap();
302
303        assert_eq!(first.event_type(), &symbol_short!("spawn"));
304        assert_eq!(first.data(), &Bytes::from_array(&env, &[1]));
305        assert_eq!(second.event_type(), &symbol_short!("spawn"));
306        assert_eq!(second.data(), &Bytes::from_array(&env, &[3]));
307        assert!(reader.read().is_none());
308        assert!(!reader.has_more());
309    }
310
311    #[test]
312    fn test_event_reader_reset_rewinds_sequence() {
313        let env = Env::default();
314        let event = Event::with_timestamp(symbol_short!("tick"), Bytes::from_array(&env, &[9]), 42);
315        let events = [event.clone()];
316        let mut reader = EventReader::new(&events, symbol_short!("tick"));
317
318        assert_eq!(reader.read().unwrap().timestamp(), 42);
319        assert!(reader.read().is_none());
320
321        reader.reset();
322
323        assert_eq!(reader.read().unwrap().timestamp(), 42);
324    }
325}