use super::CustomSignalHub;
use crate::signal::{ConnectionHandle, GenericSignal, Signal1};
use alloc::boxed::Box;
use alloc::sync::Arc;
#[derive(Default)]
pub struct EventSignalBinder {
hub: Option<Arc<CustomSignalHub>>,
forwards: alloc::vec::Vec<Forwarded>,
}
impl EventSignalBinder {
pub fn new(hub: Arc<CustomSignalHub>) -> Self {
Self { hub: Some(hub), forwards: alloc::vec::Vec::new() }
}
pub fn detached() -> Self {
Self { hub: None, forwards: alloc::vec::Vec::new() }
}
pub fn is_attached(&self) -> bool {
self.hub.is_some()
}
pub fn len(&self) -> usize {
self.forwards.len()
}
pub fn is_empty(&self) -> bool {
self.forwards.is_empty()
}
pub fn forward_unit(&mut self, event_name: &str, signal: &GenericSignal) {
let Some(hub) = self.hub.clone() else {
return;
};
let name = alloc::string::String::from(event_name);
let handle = signal.connect(move || hub.emit(&name));
self.forwards.push(Forwarded { source: ForwardSource::Unit(signal.clone()), handle });
}
pub fn forward_mapped<T, F>(&mut self, event_name: &str, signal: &Signal1<T>, mut observe: F)
where
T: Clone + Send + 'static,
F: FnMut(&T) + Send + Sync + 'static,
{
let Some(hub) = self.hub.clone() else {
return;
};
let name = alloc::string::String::from(event_name);
let handle = signal.connect(move |value: Arc<T>| {
observe(&value);
hub.emit(&name);
});
let source = signal.clone();
self.forwards.push(Forwarded {
source: ForwardSource::Typed(Box::new(move |handle| {
source.disconnect(handle);
})),
handle,
});
}
pub fn unbind_all(&mut self) {
for entry in core::mem::take(&mut self.forwards) {
entry.source.disconnect(entry.handle);
}
}
}
enum ForwardSource {
Unit(GenericSignal),
Typed(Box<dyn Fn(ConnectionHandle) + Send>),
}
impl ForwardSource {
fn disconnect(&self, handle: ConnectionHandle) {
match self {
Self::Unit(signal) => {
signal.disconnect(handle);
}
Self::Typed(disconnect) => disconnect(handle),
}
}
}
struct Forwarded {
source: ForwardSource,
handle: ConnectionHandle,
}
impl core::fmt::Debug for EventSignalBinder {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("EventSignalBinder")
.field("attached", &self.is_attached())
.field("subscriptions", &self.forwards.len())
.finish()
}
}
impl Drop for EventSignalBinder {
fn drop(&mut self) {
self.unbind_all();
}
}