1
use std::borrow::Borrow;
2
use std::cell::RefCell;
3
use std::fmt::Debug;
4
use std::fmt::Formatter;
5
use std::fmt::{self};
6
use std::hash::Hash;
7
use std::hash::Hasher;
8
use std::marker::PhantomData;
9
use std::ops::Deref;
10
use std::rc::Rc;
11

            
12
use merc_collections::ProtectionIndex;
13
use merc_collections::ProtectionSet;
14
use merc_collections::SetIndex;
15

            
16
/// An alias for the ldd index type.
17
pub type LddIndex = SetIndex;
18

            
19
/// The shared protection set is used to keep track of the nodes that are reachable.
20
pub type SharedProtectionSet = Rc<RefCell<ProtectionSet<LddIndex>>>;
21

            
22
/// Every Ldd points to its root node in the Storage instance for maximal
23
/// sharing. These Ldd instances can only be created from the storage.
24
///
25
/// # Details
26
///
27
/// Note that the Ldd actually has a interior mutable reference to the protection set.
28
/// However, this has no influence on the PartialEq and Hash implementations. As such
29
/// we can use the Ldd as a key in hash maps and sets. Use the following clippy lint
30
/// to disable the warning about mutable key types:
31
///
32
/// #[allow(clippy::mutable_key_type)]
33
pub struct Ldd {
34
    ldd: LddRef<'static>,  // Reference in the node table.
35
    root: ProtectionIndex, // Index in the root set.
36
    protection_set: SharedProtectionSet,
37
}
38

            
39
impl Ldd {
40
    /// Creates a new Ldd instance. This should only be called from the storage.
41
18237119
    pub fn new(protection_set: &SharedProtectionSet, index: LddIndex) -> Ldd {
42
18237119
        let root = protection_set.borrow_mut().protect(index);
43
18237119
        Ldd {
44
18237119
            protection_set: Rc::clone(protection_set),
45
18237119
            ldd: LddRef::new(index),
46
18237119
            root,
47
18237119
        }
48
18237119
    }
49

            
50
    /// Returns the index of the Ldd.
51
378967196
    pub fn index(&self) -> LddIndex {
52
378967196
        self.ldd.index
53
378967196
    }
54
}
55

            
56
impl Deref for Ldd {
57
    type Target = LddRef<'static>;
58

            
59
18475053
    fn deref(&self) -> &Self::Target {
60
18475053
        &self.ldd
61
18475053
    }
62
}
63

            
64
impl<'a> Borrow<LddRef<'a>> for Ldd {
65
    fn borrow(&self) -> &LddRef<'a> {
66
        &self.ldd
67
    }
68
}
69

            
70
impl Clone for Ldd {
71
4886674
    fn clone(&self) -> Self {
72
4886674
        Ldd::new(&self.protection_set, self.index())
73
4886674
    }
74
}
75

            
76
impl Drop for Ldd {
77
18237119
    fn drop(&mut self) {
78
18237119
        self.protection_set.borrow_mut().unprotect(self.root);
79
18237119
    }
80
}
81

            
82
impl PartialEq for Ldd {
83
3410513
    fn eq(&self, other: &Self) -> bool {
84
3410513
        debug_assert!(
85
3410513
            Rc::ptr_eq(&self.protection_set, &other.protection_set),
86
            "Both LDDs should refer to the same storage."
87
        );
88
3410513
        self.index() == other.index()
89
3410513
    }
90
}
91

            
92
impl Debug for Ldd {
93
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
94
        write!(f, "index: {}", self.index())
95
    }
96
}
97

            
98
impl Hash for Ldd {
99
2246890
    fn hash<H: Hasher>(&self, state: &mut H) {
100
2246890
        self.index().hash(state);
101
2246890
    }
102
}
103

            
104
impl Eq for Ldd {}
105

            
106
/// The LddRef is a reference to an existing [Ldd] instance. This can be used to
107
/// avoid explicit protections that are performed when creating an [Ldd]
108
/// instance.
109
///
110
/// # Implementation notes
111
///
112
/// It is important to note that the lifetime carried by an LddRef is only used
113
/// to enforce lifetime constraints in several places, in a similar way as used
114
/// for mutex guards or iterators. The lifetime should *not* be used to derive
115
/// lifetimes of return values and instead these should be derived from `self`.
116
/// If this is implemented correctly in the internal implementation then the
117
/// LddRef can never be misused.
118
#[derive(Hash, PartialEq, Eq, Debug)]
119
pub struct LddRef<'a> {
120
    index: LddIndex, // Index in the node table.
121
    marker: PhantomData<&'a ()>,
122
}
123

            
124
impl<'a> LddRef<'a> {
125
    /// TODO: This function should only be called by Storage and [Ldd]
126
173283563
    pub fn new(index: LddIndex) -> LddRef<'a> {
127
173283563
        LddRef {
128
173283563
            index,
129
173283563
            marker: PhantomData,
130
173283563
        }
131
173283563
    }
132

            
133
    /// Returns the index of the LddRef in the node table.
134
212838856
    pub fn index(&self) -> LddIndex {
135
212838856
        self.index
136
212838856
    }
137

            
138
    /// Returns an LddRef with the same lifetime as itself.
139
    pub fn borrow(&self) -> LddRef<'_> {
140
        LddRef::new(self.index())
141
    }
142
}
143

            
144
impl PartialEq<Ldd> for LddRef<'_> {
145
360725282
    fn eq(&self, other: &Ldd) -> bool {
146
360725282
        self.index == other.index()
147
360725282
    }
148
}