Macro detour::static_detours [] [src]

macro_rules! static_detours {
    (@parse_attributes ($($input:tt)*) | $(#[$attribute:meta])* $next:tt $($rest:tt)*) => { ... };
    (@parse_access_modifier ($($input:tt)*) | pub struct $($rest:tt)*) => { ... };
    (@parse_access_modifier ($($input:tt)*) | struct $($rest:tt)*) => { ... };
    (@parse_name ($($input:tt)*) | $name:ident : $($rest:tt)*) => { ... };
    (@parse_unsafe ($($input:tt)*) | unsafe $($rest:tt)*) => { ... };
    (@parse_unsafe ($($input:tt)*) | $($rest:tt)*) => { ... };
    (@parse_calling_convention ($($input:tt)*) ($($modifier:tt)*) | extern $cc:tt fn $($rest:tt)*) => { ... };
    (@parse_calling_convention ($($input:tt)*) ($($modifier:tt)*) | extern fn $($rest:tt)*) => { ... };
    (@parse_calling_convention ($($input:tt)*) ($($modifier:tt)*) | fn $($rest:tt)*) => { ... };
    (@parse_prototype ($($input:tt)*) | ($($argument_type:ty),*) -> $return_type:ty ; $($rest:tt)*) => { ... };
    (@parse_prototype ($($input:tt)*) | ($($argument_type:ty),*) $($rest:tt)*) => { ... };
    (@parse_terminator ($($input:tt)*) | ; $($rest:tt)*) => { ... };
    (@parse_entries ($($input:tt)*) | $($rest:tt)+) => { ... };
    (@parse_entries ($($input:tt)*) | ) => { ... };
    (@aggregate ($($attribute:meta)*) ($($visibility:tt)*) ($name:ident)
                ($($modifier:tt)*) ($($argument_type:ty)*) ($return_type:ty)) => { ... };
    (@create_detour ($($argument_name:ident)*) ($($attribute:meta)*) ($($visibility:tt)*)
                    ($name:ident) ($($modifier:tt)*) ($($argument_type:ty)*)
                    ($return_type:ty) ($fn_type:ty)) => { ... };
    (@argument_names ($label:ident) ($($input:tt)*) ($($token:tt)*)) => { ... };
    (@argument_names ($label:ident) ($($input:tt)*) ($hd_name:tt $($tl_name:tt)*) ($hd:tt $($tl:tt)*) ($($acc:tt)*) ) => { ... };
    (@argument_names ($label:ident) ($($input:tt)*) ($($name:tt)*) () ($($acc:tt)*)) => { ... };
    (@generate $item:item) => { ... };
    ($($t:tt)+) => { ... };
}

A macro for defining type-safe detours.

This macro creates a StaticDetourController, which returns a StaticDetour upon initialization. It can accept both functions and closures as its second argument. Due to the requirements of the implementation, const_fn is needed if the macro is to be used.

A static detour may only have one active detour at a time. Therefore another initialize call can only be done once the previous instance has been dropped. This is because the closures are being stored as static variables.

Example

#![feature(const_fn, const_atomic_ptr_new, const_ptr_null_mut)]
#[macro_use] extern crate detour;

use detour::Detour;

static_detours! {
    struct Test: /* extern "X" */ fn(i32) -> i32;
}

fn add5(val: i32) -> i32 { val + 5 }
fn add10(val: i32) -> i32 { val + 10 }

fn main() {
    let mut hook = unsafe { Test.initialize(add5, add10).unwrap() };

    assert_eq!(add5(1), 6);
    assert_eq!(hook.call(1), 6);

    unsafe { hook.enable().unwrap(); }

    assert_eq!(add5(1), 11);
    assert_eq!(hook.call(1), 6);

    // You can also call using the static object
    assert_eq!(unsafe { Test.get().unwrap().call(1) }, 6);

    // ... and change the detour whilst hooked
    hook.set_detour(|val| val - 5);
    assert_eq!(add5(5), 0);

    unsafe { hook.disable().unwrap() };

    assert_eq!(add5(1), 6);
}

Any type of function is supported, and extern is optional.