near_async/test_loop/
data.rs

1use std::any::{Any, type_name};
2use std::marker::PhantomData;
3use std::sync::Arc;
4use std::sync::atomic::AtomicBool;
5
6use crate::messaging::{Actor, LateBoundSender};
7
8use super::pending_events_sender::RawPendingEventsSender;
9use super::sender::TestLoopSender;
10
11/// TestLoopData is the container for all data that is stored and accessed by the test loop.
12///
13/// TestLoopData is used to mainly register actors, which can be accessed using a handle during
14/// the execution of the TestLoop.
15///
16/// ```rust, ignore
17/// let mut data = TestLoopData::new(raw_pending_events_sender, shutting_down);
18///
19/// let actor = TestActor::new();
20/// let adapter = LateBoundSender::new();
21///
22/// let sender: TestLoopSender<TestActor> = data.register_actor("client1", actor, Some(adapter));
23///
24/// // We can now send messages to the actor using the sender and adapter.
25/// sender.send(TestMessage {});
26/// adapter.send(TestMessage {});
27/// ```
28///
29/// We have the ability to register data of any type, and then access it using a handle. This is
30/// useful if we would like to have some arbitrary callback event in testloop to access this data.
31///
32/// ```rust, ignore
33/// let mut data = TestLoopData::new(raw_pending_events_sender, shutting_down);
34/// let handle: TestLoopDataHandle<usize> = data.register_data(42);
35/// assert_eq!(data.get(&handle), 42);
36/// ```
37///
38/// Note that the handler from one TestLoopData cannot be used to access data from another.
39///
40pub struct TestLoopData {
41    // Container of the data. We store it as a vec of Any so that we can store any type of data.
42    data: Vec<Box<dyn Any>>,
43    // Sender to send events to the test loop. Used mainly for registering actors.
44    raw_pending_events_sender: RawPendingEventsSender,
45    // Atomic bool to check if the test loop is shutting down. Used mainly for registering actors.
46    shutting_down: Arc<AtomicBool>,
47}
48
49impl TestLoopData {
50    pub(crate) fn new(
51        raw_pending_events_sender: RawPendingEventsSender,
52        shutting_down: Arc<AtomicBool>,
53    ) -> Self {
54        Self { data: Vec::new(), raw_pending_events_sender, shutting_down }
55    }
56
57    /// Function to register data of any type in the TestLoopData.
58    /// Returns a handler to the data that can be used to access the data later.
59    pub fn register_data<T>(&mut self, data: T) -> TestLoopDataHandle<T> {
60        let id = self.data.len();
61        self.data.push(Box::new(data));
62        TestLoopDataHandle::new(id)
63    }
64
65    /// Function to register an actor in the TestLoopData.
66    /// We provide an identifier which is used to group events from the same client.
67    /// Usually the identifier is the account_id of the client.
68    /// This function additionally schedules the start event for the actor on testloop.
69    /// Returns a TestLoopSender<Actor> that can be used to send messages to the actor.
70    pub fn register_actor<A>(
71        &mut self,
72        identifier: &str,
73        actor: A,
74        adapter: Option<Arc<LateBoundSender<TestLoopSender<A>>>>,
75    ) -> TestLoopSender<A>
76    where
77        A: Actor + 'static,
78    {
79        let actor_handle = self.register_data(actor);
80        let sender = TestLoopSender::new(
81            actor_handle,
82            self.raw_pending_events_sender.for_identifier(identifier),
83            self.shutting_down.clone(),
84        );
85        self.queue_start_actor_event(identifier, sender.clone());
86        if let Some(adapter) = adapter {
87            adapter.bind(sender.clone());
88        }
89        sender
90    }
91
92    // Helper function to queue the start actor event on the test loop while registering an actor.
93    fn queue_start_actor_event<A>(&self, identifier: &str, mut sender: TestLoopSender<A>)
94    where
95        A: Actor + 'static,
96    {
97        let callback = move |data: &mut TestLoopData| {
98            let actor = data.get_mut(&sender.actor_handle());
99            actor.start_actor(&mut sender);
100        };
101        self.raw_pending_events_sender
102            .for_identifier(identifier)
103            .send(format!("StartActor({:?})", type_name::<A>()), Box::new(callback));
104    }
105
106    /// Function to get reference to the data stored in TestLoopData.
107    pub fn get<T>(&self, handle: &TestLoopDataHandle<T>) -> &T {
108        self.data
109            .get(handle.id)
110            .expect("Handle id out of bounds. Does handle belong to this TestLoopData?")
111            .downcast_ref()
112            .expect("Handle type mismatched. Does handle belong to this TestLoopData?")
113    }
114
115    /// Function to get mutable reference to the data stored in TestLoopData.
116    pub fn get_mut<T>(&mut self, handle: &TestLoopDataHandle<T>) -> &mut T {
117        self.data
118            .get_mut(handle.id)
119            .expect("Handle id out of bounds. Does handle belong to this TestLoopData?")
120            .downcast_mut()
121            .expect("Handle type mismatched. Does handle belong to this TestLoopData?")
122    }
123}
124
125/// This is a handle to the data stored in TestLoopData.
126/// test_loop_data.get(&handle) will return the data stored in TestLoopData.
127/// test_loop_data.get_mut(&handle) will return a mutable reference to the data stored in TestLoopData.
128pub struct TestLoopDataHandle<T>
129where
130    T: 'static,
131{
132    // This is an index into the data vector in TestLoopData.
133    id: usize,
134    // Saving the type info here as fn(T) to implicitly implement Send + Sync.
135    _phantom: PhantomData<fn(T)>,
136}
137
138impl<T> Clone for TestLoopDataHandle<T> {
139    fn clone(&self) -> Self {
140        Self { id: self.id, _phantom: PhantomData }
141    }
142}
143
144impl<T> TestLoopDataHandle<T> {
145    fn new(id: usize) -> Self {
146        Self { id, _phantom: PhantomData }
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use std::sync::Arc;
153    use std::sync::atomic::AtomicBool;
154
155    use crate::test_loop::data::TestLoopData;
156    use crate::test_loop::pending_events_sender::RawPendingEventsSender;
157
158    #[derive(Debug, PartialEq)]
159    struct TestData {
160        pub value: usize,
161    }
162
163    #[test]
164    fn test_register_data() {
165        let mut data = TestLoopData::new(
166            RawPendingEventsSender::new(|_| {}),
167            Arc::new(AtomicBool::new(false)),
168        );
169        let test_data = TestData { value: 42 };
170        let handle = data.register_data(test_data);
171        assert_eq!(data.get(&handle), &TestData { value: 42 });
172
173        data.get_mut(&handle).value = 43;
174        assert_eq!(data.get(&handle), &TestData { value: 43 });
175    }
176}