use std::cell::RefCell;
use crate::{
live::sender::{DispatchSender, EventSender},
messages::{DataEvent, ExecutionEvent, SystemCommand, SystemEvent},
};
#[must_use]
pub fn get_data_event_sender() -> EventSender<DataEvent> {
DATA_EVENT_SENDER.with(|sender| {
sender
.borrow()
.as_ref()
.expect("Data event sender should be initialized by runner")
.clone()
})
}
#[must_use]
pub fn try_get_data_event_sender() -> Option<EventSender<DataEvent>> {
DATA_EVENT_SENDER.with(|sender| sender.borrow().as_ref().cloned())
}
pub fn set_data_event_sender(sender: impl Into<EventSender<DataEvent>>) {
let sender = sender.into();
DATA_EVENT_SENDER.with(|s| {
let mut slot = s.borrow_mut();
assert!(slot.is_none(), "Data event sender can only be set once");
*slot = Some(sender);
});
}
pub fn replace_data_event_sender(sender: impl Into<EventSender<DataEvent>>) {
let sender = sender.into();
DATA_EVENT_SENDER.with(|s| {
*s.borrow_mut() = Some(sender);
});
}
#[must_use]
pub fn get_system_event_sender() -> EventSender<SystemEvent> {
SYSTEM_EVENT_SENDER.with(|sender| {
sender
.borrow()
.as_ref()
.expect("System event sender should be initialized by runner")
.clone()
})
}
#[must_use]
pub fn try_get_system_event_sender() -> Option<EventSender<SystemEvent>> {
SYSTEM_EVENT_SENDER.with(|sender| sender.borrow().as_ref().cloned())
}
pub fn set_system_event_sender(sender: impl Into<EventSender<SystemEvent>>) {
let sender = sender.into();
SYSTEM_EVENT_SENDER.with(|s| {
let mut slot = s.borrow_mut();
assert!(slot.is_none(), "System event sender can only be set once");
*slot = Some(sender);
});
}
pub fn replace_system_event_sender(sender: impl Into<EventSender<SystemEvent>>) {
let sender = sender.into();
SYSTEM_EVENT_SENDER.with(|s| {
*s.borrow_mut() = Some(sender);
});
}
#[must_use]
pub fn get_system_command_sender() -> DispatchSender<SystemCommand> {
SYSTEM_COMMAND_SENDER.with(|sender| {
sender
.borrow()
.as_ref()
.expect("System command sender should be initialized by runner")
.clone()
})
}
#[must_use]
pub fn try_get_system_command_sender() -> Option<DispatchSender<SystemCommand>> {
SYSTEM_COMMAND_SENDER.with(|sender| sender.borrow().as_ref().cloned())
}
pub fn set_system_command_sender(sender: impl Into<DispatchSender<SystemCommand>>) {
let sender = sender.into();
SYSTEM_COMMAND_SENDER.with(|s| {
let mut slot = s.borrow_mut();
assert!(slot.is_none(), "System command sender can only be set once");
*slot = Some(sender);
});
}
pub fn replace_system_command_sender(sender: impl Into<DispatchSender<SystemCommand>>) {
let sender = sender.into();
SYSTEM_COMMAND_SENDER.with(|s| {
*s.borrow_mut() = Some(sender);
});
}
#[must_use]
pub fn get_exec_event_sender() -> EventSender<ExecutionEvent> {
EXEC_EVENT_SENDER.with(|sender| {
sender
.borrow()
.as_ref()
.expect("Execution event sender should be initialized by runner")
.clone()
})
}
#[must_use]
pub fn try_get_exec_event_sender() -> Option<EventSender<ExecutionEvent>> {
EXEC_EVENT_SENDER.with(|sender| sender.borrow().as_ref().cloned())
}
pub fn set_exec_event_sender(sender: impl Into<EventSender<ExecutionEvent>>) {
let sender = sender.into();
EXEC_EVENT_SENDER.with(|s| {
let mut slot = s.borrow_mut();
assert!(
slot.is_none(),
"Execution event sender can only be set once"
);
*slot = Some(sender);
});
}
pub fn replace_exec_event_sender(sender: impl Into<EventSender<ExecutionEvent>>) {
let sender = sender.into();
EXEC_EVENT_SENDER.with(|s| {
*s.borrow_mut() = Some(sender);
});
}
thread_local! {
static DATA_EVENT_SENDER: RefCell<Option<EventSender<DataEvent>>> = const { RefCell::new(None) };
static EXEC_EVENT_SENDER: RefCell<Option<EventSender<ExecutionEvent>>> = const { RefCell::new(None) };
static SYSTEM_EVENT_SENDER: RefCell<Option<EventSender<SystemEvent>>> = const { RefCell::new(None) };
static SYSTEM_COMMAND_SENDER: RefCell<Option<DispatchSender<SystemCommand>>> = const { RefCell::new(None) };
}
#[cfg(test)]
mod tests {
use std::sync::{Arc, Barrier};
use rstest::rstest;
use super::*;
#[rstest]
fn test_replace_data_event_sender_overwrites_previous() {
assert_sender_replaced(replace_data_event_sender, get_data_event_sender);
}
#[rstest]
fn test_replace_exec_event_sender_overwrites_previous() {
assert_sender_replaced(replace_exec_event_sender, get_exec_event_sender);
}
#[rstest]
fn test_replace_system_event_sender_overwrites_previous() {
assert_sender_replaced(replace_system_event_sender, get_system_event_sender);
}
#[rstest]
fn test_replace_system_command_sender_overwrites_previous() {
assert_sender_replaced(replace_system_command_sender, get_system_command_sender);
}
#[rstest]
fn test_event_senders_are_thread_local() {
assert_sender_thread_local(replace_data_event_sender, get_data_event_sender);
assert_sender_thread_local(replace_exec_event_sender, get_exec_event_sender);
assert_sender_thread_local(replace_system_event_sender, get_system_event_sender);
assert_sender_thread_local(replace_system_command_sender, get_system_command_sender);
}
#[rstest]
fn test_set_data_event_sender_panics_on_double_set() {
let result = std::thread::spawn(|| {
let (tx1, _rx1) = tokio::sync::mpsc::unbounded_channel();
let (tx2, _rx2) = tokio::sync::mpsc::unbounded_channel();
set_data_event_sender(tx1);
set_data_event_sender(tx2);
})
.join();
assert!(result.is_err());
}
#[rstest]
fn test_set_exec_event_sender_panics_on_double_set() {
let result = std::thread::spawn(|| {
let (tx1, _rx1) = tokio::sync::mpsc::unbounded_channel();
let (tx2, _rx2) = tokio::sync::mpsc::unbounded_channel();
set_exec_event_sender(tx1);
set_exec_event_sender(tx2);
})
.join();
assert!(result.is_err());
}
#[rstest]
fn test_set_system_event_sender_panics_on_double_set() {
let result = std::thread::spawn(|| {
let (tx1, _rx1) = tokio::sync::mpsc::unbounded_channel();
let (tx2, _rx2) = tokio::sync::mpsc::unbounded_channel();
set_system_event_sender(tx1);
set_system_event_sender(tx2);
})
.join();
assert!(result.is_err());
}
#[rstest]
fn test_set_system_command_sender_panics_on_double_set() {
let result = std::thread::spawn(|| {
let (tx1, _rx1) = tokio::sync::mpsc::unbounded_channel();
let (tx2, _rx2) = tokio::sync::mpsc::unbounded_channel();
set_system_command_sender(tx1);
set_system_command_sender(tx2);
})
.join();
assert!(result.is_err());
}
#[rstest]
fn test_try_get_exec_event_sender_returns_none_when_unset() {
let result = std::thread::spawn(try_get_exec_event_sender)
.join()
.unwrap();
assert!(result.is_none());
}
#[rstest]
fn test_try_get_system_event_sender_returns_none_when_unset() {
let result = std::thread::spawn(try_get_system_event_sender)
.join()
.unwrap();
assert!(result.is_none());
}
#[rstest]
fn test_try_get_system_command_sender_returns_none_when_unset() {
let result = std::thread::spawn(try_get_system_command_sender)
.join()
.unwrap();
assert!(result.is_none());
}
fn assert_sender_replaced<T: Send + 'static, S: SenderChannel<T> + Send + 'static>(
replace: fn(tokio::sync::mpsc::UnboundedSender<T>),
get: fn() -> S,
) {
std::thread::spawn(move || {
let (tx1, _rx1) = tokio::sync::mpsc::unbounded_channel();
let (tx2, _rx2) = tokio::sync::mpsc::unbounded_channel();
replace(tx1.clone());
replace(tx2.clone());
let sender = get();
assert!(!sender.targets(&tx1));
assert!(sender.targets(&tx2));
})
.join()
.expect("sender replacement test thread should join");
}
fn assert_sender_thread_local<T: Send + 'static, S: SenderChannel<T> + Send + 'static>(
replace: fn(tokio::sync::mpsc::UnboundedSender<T>),
get: fn() -> S,
) {
let barrier = Arc::new(Barrier::new(2));
let (tx1, _rx1) = tokio::sync::mpsc::unbounded_channel();
let (tx2, _rx2) = tokio::sync::mpsc::unbounded_channel();
let expected1 = tx1.clone();
let expected2 = tx2.clone();
let barrier1 = Arc::clone(&barrier);
let thread1 = std::thread::spawn(move || {
replace(tx1);
barrier1.wait();
assert!(get().targets(&expected1));
});
let thread2 = std::thread::spawn(move || {
replace(tx2);
barrier.wait();
assert!(get().targets(&expected2));
});
thread1
.join()
.expect("first sender isolation test thread should join");
thread2
.join()
.expect("second sender isolation test thread should join");
}
trait SenderChannel<T> {
fn targets(&self, sender: &tokio::sync::mpsc::UnboundedSender<T>) -> bool;
}
impl<T> SenderChannel<T> for tokio::sync::mpsc::UnboundedSender<T> {
fn targets(&self, sender: &Self) -> bool {
self.same_channel(sender)
}
}
impl<T> SenderChannel<T> for EventSender<T> {
fn targets(&self, sender: &tokio::sync::mpsc::UnboundedSender<T>) -> bool {
self.same_channel(&sender.clone().into())
}
}
}