Skip to main content

dobby_rs_framework/hook_utils/
static_hook.rs

1use super::{Callback, HookHandle, hook_fn};
2use crate::{Error, Result};
3use core::marker::PhantomData;
4use log::debug;
5use std::sync::{Arc, Mutex};
6
7pub struct StaticHook<F> {
8    handle: Mutex<Option<HookHandle>>,
9    before: Mutex<Option<Callback>>,
10    after: Mutex<Option<Callback>>,
11    _marker: PhantomData<F>,
12}
13
14impl<F: Copy> StaticHook<F> {
15    pub const fn new() -> Self {
16        Self {
17            handle: Mutex::new(None),
18            before: Mutex::new(None),
19            after: Mutex::new(None),
20            _marker: PhantomData,
21        }
22    }
23    pub fn set_before<C: Fn() + Send + Sync + 'static>(&self, cb: C) {
24        *self.before.lock().unwrap() = Some(Arc::new(cb));
25    }
26    pub fn set_after<C: Fn() + Send + Sync + 'static>(&self, cb: C) {
27        *self.after.lock().unwrap() = Some(Arc::new(cb));
28    }
29    pub fn call_before(&self) {
30        debug!("static hook before-callback");
31        if let Some(cb) = self.before.lock().unwrap().clone() {
32            cb();
33        }
34    }
35    pub fn call_after(&self) {
36        debug!("static hook after-callback");
37        if let Some(cb) = self.after.lock().unwrap().clone() {
38            cb();
39        }
40    }
41    pub unsafe fn install(&self, target: F, detour: F) -> Result<()> {
42        let mut s = self.handle.lock().unwrap();
43        if s.is_some() {
44            return Err(Error::AlreadyHooked);
45        }
46        *s = Some(hook_fn(target, detour)?.inner);
47        Ok(())
48    }
49    pub unsafe fn uninstall(&self) -> Result<()> {
50        let h = self
51            .handle
52            .lock()
53            .unwrap()
54            .take()
55            .ok_or(Error::HookNotFound)?;
56        h.unhook()
57    }
58    pub fn original(&self) -> F {
59        unsafe {
60            self.handle
61                .lock()
62                .unwrap()
63                .as_ref()
64                .expect("hook not installed")
65                .original()
66        }
67    }
68}
69
70impl<F: Copy> Default for StaticHook<F> {
71    fn default() -> Self {
72        Self::new()
73    }
74}