detours 0.2.0

Detours is a software package for monitoring and instrumenting API calls on Windows.
use std::{cell::UnsafeCell, ffi::c_void, mem::transmute_copy, ptr::null_mut};

#[allow(non_camel_case_types, non_snake_case)]
pub mod ffi {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

pub use detours_macros::detour;

pub struct Transaction {
    _private: (),
}

impl Transaction {
    pub unsafe fn attach<F: Copy>(&mut self, detour: &Detour<F>, target: *mut c_void) {
        unsafe {
            *detour.target.get() = target;

            ffi::DetourAttach(
                detour.target.get(),
                core::mem::transmute_copy(&detour.detour),
            );
        }
    }

    pub unsafe fn detach<F: Copy>(&mut self, detour: &Detour<F>) {
        unsafe {
            ffi::DetourDetach(
                detour.target.get(),
                core::mem::transmute_copy(&detour.detour),
            )
        };
    }
}

pub fn transaction<R>(f: impl FnOnce(&mut Transaction) -> R) -> R {
    unsafe { ffi::DetourTransactionBegin() };

    let mut tx = Transaction { _private: () };

    let result = f(&mut tx);

    unsafe { ffi::DetourTransactionCommit() };

    result
}

pub struct Detour<F> {
    target: UnsafeCell<*mut c_void>,
    detour: F,
}

unsafe impl<F> Sync for Detour<F> {}

impl<F: Copy> Detour<F> {
    pub const fn new(detour: F) -> Self {
        Self {
            target: UnsafeCell::new(null_mut()),
            detour,
        }
    }

    pub unsafe fn target(&self) -> F {
        unsafe { transmute_copy(&*self.target.get()) }
    }
}