use std::any::{Any, type_name};
use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use crate::messaging::{Actor, LateBoundSender};
use super::pending_events_sender::RawPendingEventsSender;
use super::sender::TestLoopSender;
pub struct TestLoopData {
data: Vec<Box<dyn Any>>,
raw_pending_events_sender: RawPendingEventsSender,
shutting_down: Arc<AtomicBool>,
}
impl TestLoopData {
pub(crate) fn new(
raw_pending_events_sender: RawPendingEventsSender,
shutting_down: Arc<AtomicBool>,
) -> Self {
Self { data: Vec::new(), raw_pending_events_sender, shutting_down }
}
pub fn register_data<T>(&mut self, data: T) -> TestLoopDataHandle<T> {
let id = self.data.len();
self.data.push(Box::new(data));
TestLoopDataHandle::new(id)
}
pub fn register_actor<A>(
&mut self,
identifier: &str,
actor: A,
adapter: Option<Arc<LateBoundSender<TestLoopSender<A>>>>,
) -> TestLoopSender<A>
where
A: Actor + 'static,
{
let actor_handle = self.register_data(actor);
let sender = TestLoopSender::new(
actor_handle,
self.raw_pending_events_sender.for_identifier(identifier),
self.shutting_down.clone(),
);
self.queue_start_actor_event(identifier, sender.clone());
if let Some(adapter) = adapter {
adapter.bind(sender.clone());
}
sender
}
fn queue_start_actor_event<A>(&self, identifier: &str, mut sender: TestLoopSender<A>)
where
A: Actor + 'static,
{
let callback = move |data: &mut TestLoopData| {
let actor = data.get_mut(&sender.actor_handle());
actor.start_actor(&mut sender);
};
self.raw_pending_events_sender
.for_identifier(identifier)
.send(format!("StartActor({:?})", type_name::<A>()), Box::new(callback));
}
pub fn get<T>(&self, handle: &TestLoopDataHandle<T>) -> &T {
self.data
.get(handle.id)
.expect("Handle id out of bounds. Does handle belong to this TestLoopData?")
.downcast_ref()
.expect("Handle type mismatched. Does handle belong to this TestLoopData?")
}
pub fn get_mut<T>(&mut self, handle: &TestLoopDataHandle<T>) -> &mut T {
self.data
.get_mut(handle.id)
.expect("Handle id out of bounds. Does handle belong to this TestLoopData?")
.downcast_mut()
.expect("Handle type mismatched. Does handle belong to this TestLoopData?")
}
}
pub struct TestLoopDataHandle<T>
where
T: 'static,
{
id: usize,
_phantom: PhantomData<fn(T)>,
}
impl<T> Clone for TestLoopDataHandle<T> {
fn clone(&self) -> Self {
Self { id: self.id, _phantom: PhantomData }
}
}
impl<T> TestLoopDataHandle<T> {
fn new(id: usize) -> Self {
Self { id, _phantom: PhantomData }
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use crate::test_loop::data::TestLoopData;
use crate::test_loop::pending_events_sender::RawPendingEventsSender;
#[derive(Debug, PartialEq)]
struct TestData {
pub value: usize,
}
#[test]
fn test_register_data() {
let mut data = TestLoopData::new(
RawPendingEventsSender::new(|_| {}),
Arc::new(AtomicBool::new(false)),
);
let test_data = TestData { value: 42 };
let handle = data.register_data(test_data);
assert_eq!(data.get(&handle), &TestData { value: 42 });
data.get_mut(&handle).value = 43;
assert_eq!(data.get(&handle), &TestData { value: 43 });
}
}