1use crate::context::{EventContext, UserContext};
9use crate::modeling::event::EventPriority;
10use crate::modeling::model::Model;
11use crate::primitive::time::Duration;
12use std::cell::RefCell;
13use std::collections::VecDeque;
14use std::fmt;
15use std::rc::Rc;
16
17pub struct AgentStep<E, M: Model<E>> {
22 pub tag: &'static str,
24 pub delay: Duration,
26 pub priority: EventPriority,
28 #[allow(clippy::type_complexity)]
34 pub logic: Box<dyn FnOnce(&mut EventContext<E, M>, &mut M, &mut VecDeque<AgentStep<E, M>>)>,
35}
36
37impl<E, M: Model<E>> fmt::Debug for AgentStep<E, M> {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.debug_struct("AgentStep")
40 .field("tag", &self.tag)
41 .field("delay", &self.delay)
42 .field("priority", &self.priority)
43 .field("logic", &format_args!("Box<dyn FnOnce>({:p})", self.logic))
45 .finish()
46 }
47}
48
49pub struct AgentContinuation<E, M: Model<E>> {
50 future_steps: VecDeque<AgentStep<E, M>>,
51 to_event_payload: Rc<dyn Fn(AgentContinuation<E, M>) -> E>,
52}
53
54impl<E, M: Model<E>> fmt::Debug for AgentContinuation<E, M> {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 f.debug_struct("AgentContinuation")
57 .field("future_steps", &self.future_steps)
58 .field(
60 "to_event_payload",
61 &format_args!("Rc<dyn Fn>({:p})", Rc::as_ptr(&self.to_event_payload)),
62 )
63 .finish()
64 }
65}
66
67impl<E: 'static, M: Model<E> + 'static> AgentContinuation<E, M> {
68 pub fn new<F>(to_event_payload: F) -> Self
75 where
76 F: Fn(AgentContinuation<E, M>) -> E + 'static,
77 {
78 Self {
79 future_steps: VecDeque::new(),
80 to_event_payload: Rc::new(to_event_payload),
81 }
82 }
83
84 pub fn then_after<F>(
93 mut self,
94 tag: &'static str,
95 delay: Duration,
96 priority: EventPriority,
97 logic: F,
98 ) -> Self
99 where
100 F: FnOnce(&mut EventContext<E, M>, &mut M, &mut VecDeque<AgentStep<E, M>>) + 'static,
101 {
102 self.future_steps.push_back(AgentStep {
103 tag,
104 delay,
105 priority,
106 logic: Box::new(logic),
107 });
108
109 self
110 }
111}
112
113impl<E, M: Model<E>> AgentContinuation<E, M> {
114 pub fn peek_next_step(&self) -> Option<&AgentStep<E, M>> {
117 self.future_steps.front()
118 }
119
120 pub fn peek_next_step_tag(&self) -> Option<&'static str> {
122 self.peek_next_step().map(|step| step.tag)
123 }
124
125 pub fn get_remain_step_count(&self) -> usize {
127 self.future_steps.len()
128 }
129
130 pub fn execute_and_schedule(mut self, context: &mut EventContext<E, M>, model: &mut M) {
133 if let Some(current_step) = self.future_steps.pop_front() {
135 (current_step.logic)(context, model, &mut self.future_steps);
138
139 let next_info = self.future_steps.front().map(|s| (s.delay, s.priority));
141 if let Some((next_delay, next_priority)) = next_info {
142 let to_event_payload = Rc::clone(&self.to_event_payload);
144 let next_payload = to_event_payload(self);
145
146 context.schedule_event(next_delay, next_priority, next_payload);
147 }
148 }
149 }
150}
151
152pub struct AgentActionTicket<E, M: Model<E>> {
153 action: RefCell<Option<AgentContinuation<E, M>>>,
154}
155
156impl<E, M: Model<E>> fmt::Debug for AgentActionTicket<E, M> {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 match self.action.borrow().as_ref() {
159 Some(continuation) => fmt::Debug::fmt(continuation, f),
160 None => write!(f, "ExecutedAction"),
161 }
162 }
163}
164
165impl<E, M: Model<E>> AgentActionTicket<E, M> {
166 pub fn issue(continuation: AgentContinuation<E, M>) -> Self {
167 Self {
168 action: RefCell::new(Some(continuation)),
169 }
170 }
171
172 pub fn execute(&self) -> Option<AgentContinuation<E, M>> {
173 self.action.borrow_mut().take()
174 }
175
176 pub fn inspect<R, F>(&self, f: F) -> Option<R>
177 where
178 F: FnOnce(&AgentContinuation<E, M>) -> R,
179 {
180 self.action.borrow().as_ref().map(f)
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use crate::context::EventContext;
188 use crate::event_scheduler::EventScheduler;
189 use crate::modeling::event::{Event, EventPriority};
190 use crate::modeling::hook::instance::HookDelegate;
191 use crate::modeling::model::Model;
192 use crate::primitive::time::{Duration, MicroStepStatus, SimTime, TickStatus};
193 use crate::source_handler::SourceHandler;
194 use std::assert_matches;
195 use std::cell::RefCell;
196 use std::rc::Rc;
197
198 #[derive(Debug)]
200 enum TestEvent {
201 AgentContinuationEvent(AgentActionTicket<TestEvent, TestModel>),
202 SimpleEvent(u32),
203 }
204
205 #[derive(Debug, Default)]
207 struct TestModel {
208 pub counter: Rc<RefCell<u32>>,
209 }
210
211 impl Model<TestEvent> for TestModel {
212 fn handle_event(
213 &mut self,
214 context: &mut EventContext<TestEvent, Self>,
215 event: &Event<TestEvent>,
216 ) {
217 match &event.payload {
218 TestEvent::AgentContinuationEvent(ticket) => {
219 if let Some(continuation) = ticket.execute() {
220 continuation.execute_and_schedule(context, self);
221 }
222 }
223 TestEvent::SimpleEvent(val) => {
224 *self.counter.borrow_mut() += val;
225 }
226 }
227 }
228 }
229
230 fn create_mock_event_context() -> EventContext<TestEvent, TestModel> {
231 EventContext {
232 current_tick_status: TickStatus::initialize(),
233 current_micro_step_status: MicroStepStatus::initialize(),
234 hook_delegate: HookDelegate::new(),
235 source_handler: SourceHandler::new(),
236 event_scheduler: EventScheduler::new(),
237 }
238 }
239
240 #[test]
241 fn test_agent_step_creation() {
242 let step = AgentStep {
243 tag: "test_step",
244 delay: Duration::ticks(1),
245 priority: EventPriority::new(5),
246 logic: Box::new(|_, _: &mut TestModel, _| {}),
247 };
248
249 assert_eq!(step.tag, "test_step");
250 assert_eq!(step.delay, Duration::ticks(1));
251 assert_eq!(step.priority, EventPriority::new(5));
252 }
253
254 #[test]
255 fn test_agent_continuation_new() {
256 let continuation: AgentContinuation<TestEvent, TestModel> =
257 AgentContinuation::new(|_| TestEvent::SimpleEvent(0));
258 assert_eq!(continuation.get_remain_step_count(), 0);
259 assert!(continuation.future_steps.is_empty());
260 }
261
262 #[test]
263 fn test_agent_continuation_then_after() {
264 let continuation: AgentContinuation<TestEvent, TestModel> =
265 AgentContinuation::new(|_| TestEvent::SimpleEvent(0))
266 .then_after(
267 "step1",
268 Duration::ticks(1),
269 EventPriority::new(5),
270 |_, _, _| {},
271 )
272 .then_after(
273 "step2",
274 Duration::ticks(2),
275 EventPriority::new(10),
276 |_, _, _| {},
277 );
278
279 assert_eq!(continuation.get_remain_step_count(), 2);
280
281 let step1 = continuation.future_steps.front().unwrap();
282 assert_eq!(step1.tag, "step1");
283 assert_eq!(step1.delay, Duration::ticks(1));
284 assert_eq!(step1.priority, EventPriority::new(5));
285
286 let step2 = continuation.future_steps.get(1).unwrap();
287 assert_eq!(step2.tag, "step2");
288 assert_eq!(step2.delay, Duration::ticks(2));
289 assert_eq!(step2.priority, EventPriority::new(10));
290 }
291
292 #[test]
293 fn test_agent_continuation_peek_next_step() {
294 let continuation: AgentContinuation<TestEvent, TestModel> =
295 AgentContinuation::new(|_| TestEvent::SimpleEvent(0))
296 .then_after(
297 "first",
298 Duration::ticks(1),
299 EventPriority::new(5),
300 |_, _, _| {},
301 )
302 .then_after(
303 "second",
304 Duration::ticks(2),
305 EventPriority::new(10),
306 |_, _, _| {},
307 );
308
309 assert_eq!(continuation.peek_next_step_tag(), Some("first"));
310 assert_eq!(
311 continuation.peek_next_step().unwrap().delay,
312 Duration::ticks(1)
313 );
314 }
315
316 #[test]
317 fn test_agent_continuation_get_remain_step_count() {
318 let continuation: AgentContinuation<TestEvent, TestModel> =
319 AgentContinuation::new(|_| TestEvent::SimpleEvent(0))
320 .then_after(
321 "s1",
322 Duration::ticks(1),
323 EventPriority::new(5),
324 |_, _, _| {},
325 )
326 .then_after(
327 "s2",
328 Duration::ticks(2),
329 EventPriority::new(10),
330 |_, _, _| {},
331 )
332 .then_after(
333 "s3",
334 Duration::ticks(3),
335 EventPriority::new(0),
336 |_, _, _| {},
337 );
338
339 assert_eq!(continuation.get_remain_step_count(), 3);
340 }
341
342 #[test]
343 fn test_agent_continuation_execute_and_schedule_single_step() {
344 let counter = Rc::new(RefCell::new(0));
345 let mut context = create_mock_event_context();
346 let mut model = TestModel {
347 counter: Rc::clone(&counter),
348 };
349
350 let continuation: AgentContinuation<TestEvent, TestModel> =
351 AgentContinuation::new(|_| TestEvent::SimpleEvent(0)).then_after(
352 "single_step",
353 Duration::ticks(1),
354 EventPriority::new(5),
355 |_, model: &mut TestModel, _| {
356 *model.counter.borrow_mut() += 10;
357 },
358 );
359
360 continuation.execute_and_schedule(&mut context, &mut model);
361
362 assert_eq!(*counter.borrow(), 10);
363 }
364
365 #[test]
366 fn test_agent_continuation_execute_and_schedule_multiple_steps() {
367 let counter = Rc::new(RefCell::new(0));
368 let mut context = create_mock_event_context();
369 let mut model = TestModel {
370 counter: Rc::clone(&counter),
371 };
372
373 let continuation: AgentContinuation<TestEvent, TestModel> = AgentContinuation::new(|c| {
374 TestEvent::AgentContinuationEvent(AgentActionTicket::issue(c))
375 })
376 .then_after(
377 "step1",
378 Duration::ticks(1),
379 EventPriority::new(5),
380 |_, model, _| {
381 *model.counter.borrow_mut() += 1;
382 },
383 )
384 .then_after(
385 "step2",
386 Duration::ticks(2),
387 EventPriority::new(10),
388 |_, model, _| {
389 *model.counter.borrow_mut() += 10;
390 },
391 );
392
393 context.schedule_event(
394 Duration::one(),
395 EventPriority::minimum(),
396 TestEvent::AgentContinuationEvent(AgentActionTicket::issue(continuation)),
397 );
398 context.event_scheduler.flush_pending();
399 let events = context.event_scheduler.drain_ready(SimTime::from_ticks(1));
400 for event in events {
401 model.handle_event(&mut context, &event);
402 }
403
404 assert_eq!(*counter.borrow(), 1); context.event_scheduler.flush_pending();
407 let mut scheduled_events = context.event_scheduler.drain_ready(SimTime::from_ticks(2));
408
409 assert_eq!(scheduled_events.len(), 1);
410 let event = scheduled_events.pop_front().unwrap();
411 assert_eq!(event.priority, EventPriority::new(10));
412 assert_matches!(event.payload, TestEvent::AgentContinuationEvent(_));
413
414 if let TestEvent::AgentContinuationEvent(ticket) = event.payload {
415 assert_eq!(
416 ticket.inspect(|c| c.peek_next_step_tag()).unwrap(),
417 Some("step2")
418 );
419 } else {
420 panic!("Expected AgentContinuationEvent payload");
421 }
422 }
423
424 #[test]
425 fn test_agent_continuation_execute_and_schedule_no_steps() {
426 let counter = Rc::new(RefCell::new(0));
427 let mut context = create_mock_event_context();
428 let mut model = TestModel {
429 counter: Rc::clone(&counter),
430 };
431
432 let continuation: AgentContinuation<TestEvent, TestModel> =
433 AgentContinuation::new(|_| TestEvent::SimpleEvent(0));
434
435 continuation.execute_and_schedule(&mut context, &mut model);
436 context.event_scheduler.flush_pending();
437
438 assert_eq!(*counter.borrow(), 0);
439 assert_eq!(context.event_scheduler.ready_queue_len(), 0);
440 }
441
442 #[test]
443 fn test_agent_action_ticket_issue_and_execute() {
444 let continuation: AgentContinuation<TestEvent, TestModel> =
445 AgentContinuation::new(|_| TestEvent::SimpleEvent(0));
446 let ticket = AgentActionTicket::issue(continuation);
447
448 let executed_continuation = ticket.execute().unwrap();
449 assert_eq!(executed_continuation.get_remain_step_count(), 0);
450
451 assert!(ticket.execute().is_none()); }
453
454 #[test]
455 fn test_agent_action_ticket_inspect() {
456 let continuation: AgentContinuation<TestEvent, TestModel> =
457 AgentContinuation::new(|_| TestEvent::SimpleEvent(0)).then_after(
458 "inspect_step",
459 Duration::ticks(1),
460 EventPriority::new(5),
461 |_, _, _| {},
462 );
463 let ticket = AgentActionTicket::issue(continuation);
464
465 let tag = ticket.inspect(|c| c.peek_next_step_tag().unwrap()).unwrap();
466 assert_eq!(tag, "inspect_step");
467
468 let _ = ticket.execute(); assert!(ticket.inspect(|c| c.peek_next_step_tag()).is_none()); }
471}