use std::mem;
use std::sync::{ Arc, Mutex, MutexGuard };
use toml_edit as toml;
use crate::structs::rid::{ RID, RIDHolder };
use crate::traits::exportable::{ Voidable, Exportable };
use crate::traits::element::Element;
#[derive(Debug, Clone, Copy)]
enum ConnectionType {
Once,
UntilDisconnected
}
type MutableArc<T> = Arc<Mutex<T>>;
type EventHandler<T> = RIDHolder<(*mut dyn FnMut(&T), ConnectionType)>;
#[derive(Debug)]
pub struct Signal<T> {
hooks: MutableArc<EventHandler<T>>
}
impl <T> Signal<T> {
pub fn new() -> Self {
Signal {
hooks: Arc::new(Mutex::new(RIDHolder::new()))
}
}
pub unsafe fn connect<'a>(&self, callback: impl FnMut(&T) + 'a) -> RID {
let callback_box: Box<dyn FnMut(&T) + 'a> = Box::new(callback);
let callback_ext: Box<dyn FnMut(&T)> = unsafe { mem::transmute(callback_box) };
let callback_raw: *mut dyn FnMut(&T) = Box::into_raw(callback_ext);
self.hooks.lock().unwrap().push((callback_raw, ConnectionType::UntilDisconnected))
}
pub unsafe fn connect_once<'a>(&self, callback: impl FnMut(&T) + 'a) -> RID {
let callback_box: Box<dyn FnMut(&T) + 'a> = Box::new(callback);
let callback_ext: Box<dyn FnMut(&T)> = unsafe { mem::transmute(callback_box) };
let callback_raw: *mut dyn FnMut(&T) = Box::into_raw(callback_ext);
self.hooks.lock().unwrap().push((callback_raw, ConnectionType::Once))
}
pub fn emit<E: Element<T>>(&self, parameters: E) {
let mut hooks: MutexGuard<EventHandler<T>> = self.hooks.lock().unwrap();
let mut removed_signals: Vec<RID> = Vec::with_capacity(hooks.len());
let parameters: &T = parameters.as_inner();
for (&rid, &(hook, mode)) in hooks.iter_enumerated() {
unsafe {
(*hook)(parameters);
}
match mode {
ConnectionType::UntilDisconnected => (),
ConnectionType::Once => removed_signals.push(rid)
}
}
for idx in removed_signals.into_iter().rev() {
hooks.take(idx);
}
}
pub fn disconnect(&self, rid: RID) -> bool {
self.hooks.lock().unwrap().take(rid).is_some()
}
}
impl <T> Clone for Signal<T> {
fn clone(&self) -> Self {
Self::new()
}
}
impl <T> Default for Signal<T> {
fn default() -> Self {
Self::new()
}
}
impl <T> Voidable for Signal<T> {
fn void() -> Self {
Self::new()
}
}
impl <T> Exportable for Signal<T> {
unsafe fn is_ghost_export(&self) -> bool { true }
fn to_value(&self) -> toml::Value {
unimplemented!()
}
fn from_value(_value: toml::Value) -> Option<Self> where Self: Sized {
unimplemented!()
}
}