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 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 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 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 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}