use std::{
cell::RefCell,
sync::{Arc, Mutex, MutexGuard, Weak},
};
use crate::{simulation::SimulationDispatcher, Addr, Behavior, Message, ProcessContext};
pub struct ReactiveMocker<T: 'static> {
addr: Addr,
mock: Arc<Mutex<MockReactive<T>>>,
data: Arc<Mutex<T>>,
}
#[mockall::automock]
#[allow(clippy::needless_lifetimes)] pub trait Reactive<T> {
fn process_request<'a>(
&mut self,
mock_data: &mut T,
context: &mut ProcessContext<'a>,
request: &crate::Request,
);
fn process_response<'a>(
&mut self,
mock_data: &mut T,
context: &mut ProcessContext<'a>,
response: &crate::Response,
);
fn process_notification<'a>(
&mut self,
mock_data: &mut T,
context: &mut ProcessContext<'a>,
request: &crate::Notification,
);
}
impl<T> ReactiveMocker<T> {
pub fn new(dispatcher: &RefCell<SimulationDispatcher>, data: T) -> Self {
let mut me = Self {
addr: Addr::INVALID,
mock: Arc::new(Mutex::new(MockReactive::new())),
data: Arc::new(Mutex::new(data)),
};
me.register(dispatcher);
me
}
pub fn data(&self) -> MutexGuard<'_, T> {
self.data.lock().unwrap()
}
pub fn data_to_weak(&self) -> Weak<Mutex<T>> {
Arc::downgrade(&self.data)
}
pub fn mock(&self) -> MutexGuard<'_, MockReactive<T>> {
self.mock.lock().unwrap()
}
pub fn addr(&self) -> Addr {
self.addr.clone()
}
fn register(&mut self, dispatcher: &RefCell<SimulationDispatcher>) {
self.addr = dispatcher
.borrow_mut()
.register_reactive(Box::new(ReactiveMocker {
addr: Addr::INVALID, mock: self.mock.clone(),
data: self.data.clone(),
}));
}
}
impl<T> Behavior for ReactiveMocker<T> {
fn process_message(&mut self, context: &mut ProcessContext, msg: &Message) {
let data = &mut *self.data.lock().unwrap();
let mut mock = self.mock.lock().unwrap();
match msg {
Message::Request(request) => mock.process_request(data, context, request),
Message::Response(response) => mock.process_response(data, context, response),
Message::Notification(notification) => {
mock.process_notification(data, context, notification)
}
}
}
}