1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use std::cell::Cell;
use std::mem;

thread_local!( static HOOK_LOCK: Cell< i32 > = Cell::new( 0 ) );

struct HookLockGuard( i32 );

impl HookLockGuard {
    #[inline]
    fn increment() -> HookLockGuard {
        HookLockGuard( HOOK_LOCK.with( |cell| {
            let previous = cell.get();
            cell.set( previous + 1 );
            previous
        }))
    }

    #[inline]
    fn zero() -> HookLockGuard {
        HookLockGuard( HOOK_LOCK.with( |cell| {
            let previous = cell.get();
            cell.set( 0 );
            previous
        }))
    }
}

impl Drop for HookLockGuard {
    #[inline]
    fn drop( &mut self ) {
        HOOK_LOCK.with( |cell| cell.set( self.0 ) );
    }
}

#[inline]
pub fn disable_hooks< R, F: FnOnce() -> R >( callback: F ) -> R {
    let lock = HookLockGuard::increment();
    let result = callback();
    mem::drop( lock );

    result
}

#[inline]
pub fn enable_hooks< R, F: FnOnce() -> R >( callback: F ) -> R {
    let lock = HookLockGuard::zero();
    let result = callback();
    mem::drop( lock );

    result
}

#[inline]
pub fn are_hooks_enabled() -> bool {
    HOOK_LOCK.with( |cell| cell.get() <= 0 )
}

#[inline]
pub fn are_hooks_disabled() -> bool {
    !are_hooks_enabled()
}