use libc::c_void;
use std::ptr::null;
use std::sync::RwLock;
use std::sync::Arc;
use send_wrapper::SendWrapper;
use crate::callback_data::*;
use crate::hexchat_entry_points::PHEXCHAT;
use crate::user_data::*;
static mut HOOK_LIST: Option<RwLock<Vec<Hook>>> = None;
use UserData::*;
struct HookData {
hook_ptr : *const c_void,
cbd_box_ptr : *const c_void,
}
#[derive(Clone)]
pub struct Hook {
data: Arc<RwLock<Option<SendWrapper<HookData>>>>,
}
unsafe impl Send for Hook {}
impl Hook {
pub (crate) fn new() -> Self {
let hook = Hook {
data: Arc::new(
RwLock::new(
Some(
SendWrapper::new(
HookData {
hook_ptr : null::<c_void>(),
cbd_box_ptr : null::<c_void>(),
})))),
};
if let Some(hook_list_rwlock) = unsafe { &HOOK_LIST } {
let wlock = hook_list_rwlock.write();
let hook_list = &mut *wlock.unwrap();
hook_list.retain(|h|
!h.data.read().unwrap().as_ref().unwrap().hook_ptr.is_null()
);
hook_list.push(hook.clone());
}
hook
}
pub (crate) fn set(&self, ptr: *const c_void) {
if let Some(hl_rwlock) = unsafe { &HOOK_LIST } {
let _rlock = hl_rwlock.read();
self.data.write().unwrap().as_mut().unwrap().hook_ptr = ptr;
}
}
pub (crate) fn set_cbd(&self, ptr: *const c_void) {
if let Some(hl_rwlock) = unsafe { &HOOK_LIST } {
let _rlock = hl_rwlock.read();
self.data.write().unwrap().as_mut().unwrap().cbd_box_ptr = ptr;
}
}
pub fn unhook(&self) -> UserData {
unsafe {
if let Some(hl_rwlock) = &HOOK_LIST {
let _rlock = hl_rwlock.read();
let ptr_data = &mut self.data.write().unwrap();
if !ptr_data.as_ref().unwrap().hook_ptr.is_null() {
let hc = &*PHEXCHAT;
let hp = ptr_data.as_ref().unwrap().hook_ptr;
let _ = (hc.c_unhook)(hc, hp);
ptr_data.as_mut().unwrap().hook_ptr = null::<c_void>();
let cd = ptr_data.as_ref().unwrap().cbd_box_ptr;
let cd = &mut (*(cd as *mut CallbackData));
let cd = &mut Box::from_raw(cd);
return cd.take_data();
}
}
NoData
}
}
pub (crate) fn init() {
unsafe {
HOOK_LIST = Some(RwLock::new(Vec::new()));
}
}
pub (crate) fn deinit() {
if let Some(hl_rwlock) = unsafe { &HOOK_LIST } {
let rlock = hl_rwlock.read();
let hook_list = &*rlock.unwrap();
for hook in hook_list {
hook.unhook();
}
}
unsafe {
let _ = HOOK_LIST.take();
}
}
}