use super::error::SignalError;
use std::any::TypeId;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
pub type ReceiverFunction = dyn Fn(
Arc<dyn std::any::Any + Send + Sync>,
) -> Pin<Box<dyn Future<Output = Result<(), SignalError>> + Send>>
+ Send
+ Sync;
pub struct ReceiverRegistryEntry {
pub signal_name: &'static str,
pub receiver_name: &'static str,
pub sender_type_fn: Option<fn() -> TypeId>,
pub dispatch_uid: Option<&'static str>,
pub priority: i32,
pub receiver_factory: fn() -> Arc<ReceiverFunction>,
}
impl ReceiverRegistryEntry {
pub const fn new(
signal_name: &'static str,
receiver_name: &'static str,
receiver_factory: fn() -> Arc<ReceiverFunction>,
) -> Self {
Self {
signal_name,
receiver_name,
sender_type_fn: None,
dispatch_uid: None,
priority: 0,
receiver_factory,
}
}
pub const fn with_sender_type(mut self, sender_type_fn: fn() -> TypeId) -> Self {
self.sender_type_fn = Some(sender_type_fn);
self
}
pub const fn with_dispatch_uid(mut self, dispatch_uid: &'static str) -> Self {
self.dispatch_uid = Some(dispatch_uid);
self
}
pub const fn with_priority(mut self, priority: i32) -> Self {
self.priority = priority;
self
}
}
inventory::collect!(ReceiverRegistryEntry);
pub fn auto_connect_receivers() {
for entry in inventory::iter::<ReceiverRegistryEntry> {
let receiver = (entry.receiver_factory)();
connect_receiver_to_signal(entry, receiver);
}
}
fn connect_receiver_to_signal(entry: &ReceiverRegistryEntry, receiver: Arc<ReceiverFunction>) {
use super::registry::get_signal_with_string;
type AnyData = Arc<dyn std::any::Any + Send + Sync>;
let signal = get_signal_with_string::<AnyData>(entry.signal_name);
let receiver_wrapper = move |data: Arc<AnyData>| {
let receiver = Arc::clone(&receiver);
receiver(data)
};
let sender_type_id = entry.sender_type_fn.map(|f| f());
signal.connect_with_options(
receiver_wrapper,
sender_type_id,
entry.dispatch_uid.map(|s| s.to_string()),
entry.priority,
);
}