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
62
63
64
65
66
67
68
69
70
71
72
73
74
use std;
use std::os::raw::c_void;
use std::collections::HashSet;
use borrow::LoanError;

pub unsafe trait Pointer {
    unsafe fn as_ptr(&self) -> *const c_void;
    unsafe fn as_mut(&mut self) -> *mut c_void;
}

unsafe impl<T> Pointer for *mut T {
    unsafe fn as_ptr(&self) -> *const c_void {
        *self as *const c_void
    }

    unsafe fn as_mut(&mut self) -> *mut c_void {
        *self as *mut c_void
    }
}
unsafe impl<'a, T> Pointer for &'a mut T {
    unsafe fn as_ptr(&self) -> *const c_void {
        let r: &T = &**self;
        std::mem::transmute(r)
    }

    unsafe fn as_mut(&mut self) -> *mut c_void {
        let r: &mut T = &mut **self;
        std::mem::transmute(r)
    }
}

pub struct Ledger {
    immutable_loans: HashSet<*const c_void>,
    mutable_loans: HashSet<*const c_void>
}

impl Ledger {
    pub fn new() -> Self {
        Ledger {
            immutable_loans: HashSet::new(),
            mutable_loans: HashSet::new()
        }
    }

    pub fn try_borrow<T>(&mut self, p: *const T) -> Result<(), LoanError> {
        let p = p as *const c_void;
        if self.mutable_loans.contains(&p) {
            return Err(LoanError::Mutating(p));
        }
        self.immutable_loans.insert(p);
        Ok(())
    }

    pub fn settle<T>(&mut self, p: *const T) {
        let p = p as *const c_void;
        self.immutable_loans.remove(&p);
    }

    pub fn try_borrow_mut<T>(&mut self, p: *mut T) -> Result<(), LoanError> {
        let p = p as *const c_void;
        if self.mutable_loans.contains(&p) {
            return Err(LoanError::Mutating(p));
        } else if self.immutable_loans.contains(&p) {
            return Err(LoanError::Frozen(p));
        }
        self.mutable_loans.insert(p);
        Ok(())
    }

    pub fn settle_mut<T>(&mut self, p: *mut T) {
        let p = p as *const c_void;
        self.mutable_loans.remove(&p);
    }
}