1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
use super::{delay_sender::DelaySender, event_handler::LoopEventHandler};
use crate::messaging::CanSend;
use std::fmt::Debug;

/// Any arbitrary logic that runs as part of the test loop.
///
/// This is not necessary (since one can just take the data and perform
/// arbitrary logic on it), but this is good for documentation and allows
/// the logs emitted as part of this function's execution to be segmented
/// in the TestLoop visualizer.
pub struct AdhocEvent<Data: 'static> {
    pub description: String,
    pub handler: Box<dyn FnOnce(&mut Data) + Send + 'static>,
}

impl<Data> Debug for AdhocEvent<Data> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.description)
    }
}

/// Allows DelaySender to be used to send or schedule adhoc events.
pub trait AdhocEventSender<Data: 'static> {
    fn send_adhoc_event(&self, description: &str, f: impl FnOnce(&mut Data) + Send + 'static);
    fn schedule_adhoc_event(
        &self,
        description: &str,
        f: impl FnOnce(&mut Data) + Send + 'static,
        delay: time::Duration,
    );
}

impl<Data: 'static, Event: From<AdhocEvent<Data>> + 'static> AdhocEventSender<Data>
    for DelaySender<Event>
{
    fn send_adhoc_event(&self, description: &str, f: impl FnOnce(&mut Data) + Send + 'static) {
        self.send(AdhocEvent { description: description.to_string(), handler: Box::new(f) })
    }
    fn schedule_adhoc_event(
        &self,
        description: &str,
        f: impl FnOnce(&mut Data) + Send + 'static,
        delay: time::Duration,
    ) {
        self.send_with_delay(
            AdhocEvent { description: description.to_string(), handler: Box::new(f) }.into(),
            delay,
        )
    }
}

/// Handler to handle adhoc events.
pub fn handle_adhoc_events<Data: 'static>() -> LoopEventHandler<Data, AdhocEvent<Data>> {
    LoopEventHandler::new_simple(|event: AdhocEvent<Data>, data| {
        (event.handler)(data);
    })
}