1
use std::fmt::Debug;
2
use std::hash::Hash;
3
use std::mem::transmute;
4
use std::ops::Deref;
5
use std::ops::DerefMut;
6
use std::pin::Pin;
7
use std::sync::Arc;
8

            
9
use mcrl2_sys::atermpp::ffi;
10
use utilities::PhantomUnsend;
11

            
12
use crate::aterm::ATermRef;
13
use crate::aterm::BfTermPool;
14
use crate::aterm::THREAD_TERM_POOL;
15

            
16
use super::BfTermPoolThreadWrite;
17

            
18
#[cfg(debug_assertions)]
19
use std::cell::RefCell;
20

            
21
/// A container of objects, typically either terms or objects containing terms,
22
/// that are of trait Markable. These store ATermRef<'static> that are protected
23
/// during garbage collection by being in the container itself.
24
pub struct Protected<C> {
25
    container: Arc<BfTermPool<C>>,
26
    root: usize,
27

            
28
    // Protected is not Send because it uses thread-local state for its protection
29
    // mechanism.
30
    _unsend: PhantomUnsend,
31
}
32

            
33
impl<C: Markable + Send + 'static> Protected<C> {
34
    /// Creates a new Protected container from a given container.
35
2614589
    pub fn new(container: C) -> Protected<C> {
36
2614589
        let shared = Arc::new(BfTermPool::new(container));
37
2614589

            
38
2614589
        let root = THREAD_TERM_POOL.with_borrow_mut(|tp| tp.protect_container(shared.clone()));
39
2614589

            
40
2614589
        Protected {
41
2614589
            container: shared,
42
2614589
            root,
43
2614589
            _unsend: Default::default(),
44
2614589
        }
45
2614589
    }
46

            
47
    /// Provides mutable access to the underlying container. Use [Protector::protect] of
48
    /// the resulting guard to be able to insert terms into the container.
49
    /// Otherwise the borrow checker will note that the [ATermRef] do not
50
    /// outlive the guard, see [Protector].
51
301522288
    pub fn write(&mut self) -> Protector<'_, C> {
52
301522288
        // The lifetime of ATermRef can be derived from self since it is protected by self, so transmute 'static into 'a.
53
301522288
        unsafe { Protector::new(self.container.write_exclusive()) }
54
301522288
    }
55

            
56
    /// Provides immutable access to the underlying container.
57
246258259
    pub fn read(&self) -> &C {
58
246258259
        // The lifetime of ATermRef can be derived from self since it is protected by self, so transmute 'static into 'a.
59
246258259
        unsafe { self.container.get() }
60
246258259
    }
61
}
62

            
63
impl<C: Default + Markable + Send + 'static> Default for Protected<C> {
64
1289504
    fn default() -> Self {
65
1289504
        Protected::new(Default::default())
66
1289504
    }
67
}
68

            
69
impl<C: Clone + Markable + Send + 'static> Clone for Protected<C> {
70
    fn clone(&self) -> Self {
71
        Protected::new(self.container.read().clone())
72
    }
73
}
74

            
75
impl<C: Hash + Markable> Hash for Protected<C> {
76
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
77
        self.container.read().hash(state)
78
    }
79
}
80

            
81
impl<C: PartialEq + Markable> PartialEq for Protected<C> {
82
1
    fn eq(&self, other: &Self) -> bool {
83
1
        self.container.read().eq(&other.container.read())
84
1
    }
85
}
86

            
87
impl<C: PartialOrd + Markable> PartialOrd for Protected<C> {
88
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
89
        let c: &C = &other.container.read();
90
        self.container.read().partial_cmp(c)
91
    }
92
}
93

            
94
impl<C: Debug + Markable> Debug for Protected<C> {
95
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96
        let c: &C = &self.container.read();
97
        write!(f, "{:?}", c)
98
    }
99
}
100

            
101
impl<C: Eq + PartialEq + Markable> Eq for Protected<C> {}
102
impl<C: Ord + PartialEq + PartialOrd + Markable> Ord for Protected<C> {
103
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
104
        let c: &C = &other.container.read();
105
        self.container.read().partial_cmp(c).unwrap()
106
    }
107
}
108

            
109
impl<C> Drop for Protected<C> {
110
2614589
    fn drop(&mut self) {
111
2614589
        THREAD_TERM_POOL.with_borrow_mut(|tp| {
112
2614589
            tp.drop_container(self.root);
113
2614589
        });
114
2614589
    }
115
}
116

            
117
/// A type for the todo queue.
118
pub type Todo<'a> = Pin<&'a mut ffi::term_mark_stack>;
119

            
120
/// This trait should be used on all objects and containers related to storing unprotected terms.
121
pub trait Markable {
122
    /// Marks all the ATermRefs to prevent them from being garbage collected.
123
    fn mark(&self, todo: Todo);
124

            
125
    /// Should return true iff the given term is contained in the object. Used for runtime checks.
126
    fn contains_term(&self, term: &ATermRef<'_>) -> bool;
127

            
128
    /// Returns the number of terms in the instance, used to delay garbage collection.
129
    fn len(&self) -> usize;
130

            
131
    /// Returns true iff the container is empty.
132
    fn is_empty(&self) -> bool {
133
        self.len() == 0
134
    }
135
}
136

            
137
impl Markable for ATermRef<'_> {
138
    fn mark(&self, todo: Pin<&mut ffi::term_mark_stack>) {
139
        if !self.is_default() {
140
            unsafe {
141
                ffi::aterm_mark_address(self.get(), todo);
142
            }
143
        }
144
    }
145

            
146
9125020
    fn contains_term(&self, term: &ATermRef<'_>) -> bool {
147
9125020
        term == self
148
9125020
    }
149

            
150
    fn len(&self) -> usize {
151
        1
152
    }
153
}
154

            
155
impl<T: Markable> Markable for Vec<T> {
156
    fn mark(&self, mut todo: Pin<&mut ffi::term_mark_stack>) {
157
        for value in self {
158
            value.mark(todo.as_mut());
159
        }
160
    }
161

            
162
232072632
    fn contains_term(&self, term: &ATermRef<'_>) -> bool {
163
19777555228
        self.iter().any(|v| v.contains_term(term))
164
232072632
    }
165

            
166
    fn len(&self) -> usize {
167
        self.len()
168
    }
169
}
170

            
171
impl<T: Markable + ?Sized> Markable for BfTermPool<T> {
172
    fn mark(&self, mut todo: Pin<&mut ffi::term_mark_stack>) {
173
        unsafe {
174
            self.get().mark(todo.as_mut());
175
        }
176
    }
177

            
178
    fn contains_term(&self, term: &ATermRef<'_>) -> bool {
179
        self.read().contains_term(term)
180
    }
181

            
182
    fn len(&self) -> usize {
183
        self.read().len()
184
    }
185
}
186

            
187
/// This is a helper struct used by TermContainer to protected terms that are
188
/// inserted into the container before the guard is dropped.
189
///
190
/// The reason is that the ATermRef derive their lifetime from the
191
/// TermContainer. However, when inserting terms with shorter lifetimes we know
192
/// that their lifetime is extended by being in the container. This is enforced
193
/// by runtime checks during debug for containers that implement IntoIterator.
194
pub struct Protector<'a, C: Markable> {
195
    reference: BfTermPoolThreadWrite<'a, C>,
196

            
197
    #[cfg(debug_assertions)]
198
    protected: RefCell<Vec<ATermRef<'static>>>,
199
}
200

            
201
impl<'a, C: Markable> Protector<'a, C> {
202
301522288
    fn new(reference: BfTermPoolThreadWrite<'a, C>) -> Protector<'a, C> {
203
301522288
        #[cfg(debug_assertions)]
204
301522288
        return Protector {
205
301522288
            reference,
206
301522288
            protected: RefCell::new(vec![]),
207
301522288
        };
208
301522288

            
209
301522288
        #[cfg(not(debug_assertions))]
210
301522288
        return Protector { reference };
211
301522288
    }
212

            
213
232072632
    pub fn protect(&self, term: &ATermRef<'_>) -> ATermRef<'static> {
214
232072632
        unsafe {
215
232072632
            // Store terms that are marked as protected to check if they are
216
232072632
            // actually in the container when the protection is dropped.
217
232072632
            #[cfg(debug_assertions)]
218
232072632
            self.protected
219
232072632
                .borrow_mut()
220
232072632
                .push(transmute::<ATermRef<'_>, ATermRef<'static>>(term.copy()));
221
232072632

            
222
232072632
            transmute(term.copy())
223
232072632
        }
224
232072632
    }
225
}
226

            
227
impl<C: Markable> Deref for Protector<'_, C> {
228
    type Target = C;
229

            
230
211243987
    fn deref(&self) -> &Self::Target {
231
211243987
        &self.reference
232
211243987
    }
233
}
234

            
235
impl<C: Markable> DerefMut for Protector<'_, C> {
236
445278991
    fn deref_mut(&mut self) -> &mut Self::Target {
237
445278991
        &mut self.reference
238
445278991
    }
239
}
240

            
241
impl<C: Markable> Drop for Protector<'_, C> {
242
301522288
    fn drop(&mut self) {
243
        #[cfg(debug_assertions)]
244
        {
245
301522288
            for term in self.protected.borrow().iter() {
246
232072632
                debug_assert!(
247
232072632
                    self.reference.contains_term(term),
248
                    "Term was protected but not actually inserted"
249
                );
250
            }
251
        }
252
301522288
    }
253
}
254

            
255
#[cfg(test)]
256
mod tests {
257
    use super::*;
258

            
259
    use crate::aterm::TermPool;
260

            
261
    #[test]
262
1
    fn test_aterm_container() {
263
1
        let mut tp = TermPool::new();
264
1
        let t = tp.from_string("f(g(a),b)").unwrap();
265
1

            
266
1
        // First test the trait for a standard container.
267
1
        let mut container = Protected::<Vec<ATermRef>>::new(vec![]);
268

            
269
1001
        for _ in 0..1000 {
270
1000
            let mut write = container.write();
271
1000
            let u = write.protect(&t);
272
1000
            write.push(u);
273
1000
        }
274
1
    }
275
}