1
use std::cmp::Ordering;
2
use std::collections::VecDeque;
3
use std::fmt;
4
use std::hash::Hash;
5
use std::hash::Hasher;
6
use std::marker::PhantomData;
7
use std::sync::Arc;
8
use std::sync::Mutex;
9

            
10
use delegate::delegate;
11

            
12
use merc_sharedmutex::RecursiveLockReadGuard;
13
use merc_unsafety::ProtectionIndex;
14
use merc_unsafety::ProtectionSet;
15
use merc_unsafety::StablePointer;
16
use merc_utilities::MercError;
17
use merc_utilities::PhantomUnsend;
18

            
19
use crate::ATermIntRef;
20
use crate::ATermList;
21
use crate::Markable;
22
use crate::Symb;
23
use crate::SymbolRef;
24
use crate::Transmutable;
25
use crate::is_empty_list_term;
26
use crate::is_int_term;
27
use crate::is_list_term;
28
use crate::storage::GlobalTermPool;
29
use crate::storage::Marker;
30
use crate::storage::SharedTerm;
31
use crate::storage::THREAD_TERM_POOL;
32

            
33
/// The ATerm trait represents a first-order term in the ATerm library.
34
/// It provides methods to manipulate and access the term's properties.
35
///  
36
/// # Details
37
///
38
/// This trait is rather complicated with two lifetimes, but this is used
39
/// to support both the [ATerm], which has no lifetimes, and [ATermRef<'a>]
40
/// whose lifetime is bound by `'a`. Because now we can require that `'b: 'a`
41
/// for the implementation of [Term<'a, 'b>] for [ATerm], we can safely return
42
/// [ATermRef<'a>] from methods of [Term<'a, 'b>]. Further explanation can be
43
/// found on the website.
44
pub trait Term<'a, 'b> {
45
    /// Protects the term from garbage collection, returning an owned [ATerm].
46
    fn protect(&self) -> ATerm;
47

            
48
    /// Returns the indexed argument of the term as an [ATermRef].
49
    fn arg(&'b self, index: usize) -> ATermRef<'a>;
50

            
51
    /// Returns the list of arguments as an [ATermArgs] collection.
52
    fn arguments(&'b self) -> ATermArgs<'a>;
53

            
54
    /// Makes a copy of the term, returning an [ATermRef] with the same lifetime as itself.
55
    fn copy(&'b self) -> ATermRef<'a>;
56

            
57
    /// Returns the head symbol of the term as a [SymbolRef].
58
    fn get_head_symbol(&'b self) -> SymbolRef<'a>;
59

            
60
    /// Returns a [TermIterator] over all arguments of the term in pre-order traversal.
61
    fn iter(&'b self) -> TermIterator<'a>;
62

            
63
    /// Returns a unique index of the term in the term pool.
64
    fn index(&self) -> usize;
65

            
66
    /// Returns the [ATermIndex] of the term in the term pool.
67
    fn shared(&self) -> &ATermIndex;
68
}
69

            
70
/// Type alias for [ATerm] indices, representing a stable pointer to a [SharedTerm] in the term pool.
71
pub type ATermIndex = StablePointer<SharedTerm>;
72

            
73
/// This represents a lifetime bound reference to an existing [ATerm].
74
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
75
pub struct ATermRef<'a> {
76
    shared: ATermIndex,
77
    marker: PhantomData<&'a ()>,
78
}
79

            
80
// /// Check that the ATermRef is the same size as a usize.
81
// #[cfg(not(debug_assertions))]
82
// const _: () = assert!(std::mem::size_of::<ATermRef>() == std::mem::size_of::<usize>());
83

            
84
// /// Since we have NonZero we can use a niche value optimisation for option.
85
// #[cfg(not(debug_assertions))]
86
// const _: () = assert!(std::mem::size_of::<Option<ATermRef>>() == std::mem::size_of::<usize>());
87

            
88
/// These are safe because terms are immutable. Garbage collection is
89
/// always performed with exclusive access, and reference terms have no thread-local state.
90
unsafe impl Send for ATermRef<'_> {}
91
unsafe impl Sync for ATermRef<'_> {}
92

            
93
impl ATermRef<'_> {
94
    /// Creates a new term reference from the given [ATermIndex].
95
    ///
96
    /// # Safety
97
    ///
98
    /// This function is unsafe because it does not check if the index is valid for the given lifetime.
99
6183116155
    pub unsafe fn from_index(shared: &ATermIndex) -> Self {
100
6183116155
        ATermRef {
101
6183116155
            // SAFETY: the caller guarantees the index remains valid for the
102
6183116155
            // lifetime of the returned reference.
103
6183116155
            shared: unsafe { shared.copy() },
104
6183116155
            marker: PhantomData,
105
6183116155
        }
106
6183116155
    }
107
}
108

            
109
impl<'a, 'b> Term<'a, 'b> for ATermRef<'a> {
110
813921460
    fn protect(&self) -> ATerm {
111
813921460
        THREAD_TERM_POOL.with(|tp| tp.protect(&self.copy()))
112
813921460
    }
113

            
114
910818231
    fn arg(&self, index: usize) -> ATermRef<'a> {
115
910818231
        debug_assert!(
116
910818231
            index < self.get_head_symbol().arity(),
117
            "arg({index}) is not defined for term {self:?}"
118
        );
119

            
120
        // Safety: self is ATermRef<'a>, so the GC keeps all its arguments
121
        // protected for 'a. We copy the stable pointer rather than borrowing
122
        // through the short-lived slice reference.
123
910818231
        unsafe { ATermRef::from_index(self.shared().deref().arguments()[index].shared()) }
124
910818231
    }
125

            
126
83203808
    fn arguments(&self) -> ATermArgs<'a> {
127
83203808
        ATermArgs::new(self.copy())
128
83203808
    }
129

            
130
3883960587
    fn copy(&self) -> ATermRef<'a> {
131
3883960587
        unsafe { ATermRef::from_index(self.shared()) }
132
3883960587
    }
133

            
134
17021550462
    fn get_head_symbol(&'b self) -> SymbolRef<'a> {
135
17021550462
        unsafe { std::mem::transmute::<SymbolRef<'b>, SymbolRef<'a>>(self.shared().deref().symbol().copy()) }
136
17021550462
    }
137

            
138
79695
    fn iter(&self) -> TermIterator<'a> {
139
79695
        TermIterator::new(self.copy())
140
79695
    }
141

            
142
293050567
    fn index(&self) -> usize {
143
        // SAFETY: `self` is an `ATermRef<'a>`, so the GC keeps the term alive
144
        // for `'a` and the pointee is valid to read.
145
293050567
        unsafe { self.shared.deref() }.index()
146
293050567
    }
147

            
148
25333812777
    fn shared(&self) -> &ATermIndex {
149
25333812777
        &self.shared
150
25333812777
    }
151
}
152

            
153
impl Markable for ATermRef<'_> {
154
108239034
    fn mark(&self, marker: &mut Marker) {
155
108239034
        marker.mark(self);
156
108239034
    }
157

            
158
20890580
    fn contains_term(&self, term: &ATermRef<'_>) -> bool {
159
20890580
        term == self
160
20890580
    }
161

            
162
    fn contains_symbol(&self, symbol: &SymbolRef<'_>) -> bool {
163
        self.get_head_symbol() == *symbol
164
    }
165

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

            
171
impl fmt::Display for ATermRef<'_> {
172
104000
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173
104000
        write!(f, "{self:?}")
174
104000
    }
175
}
176

            
177
impl fmt::Debug for ATermRef<'_> {
178
2766077
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179
2766077
        if is_int_term(self) {
180
            write!(f, "{}", Into::<ATermIntRef>::into(self.copy()))?;
181
2766077
        } else if is_list_term(self) || is_empty_list_term(self) {
182
            write!(f, "{}", Into::<ATermList<ATerm>>::into(self.copy()))?;
183
2766077
        } else if self.arguments().is_empty() {
184
1299719
            write!(f, "{}", self.get_head_symbol().name())?;
185
        } else {
186
            // Format the term with its head symbol and arguments, avoiding trailing comma
187
1466358
            write!(f, "{:?}(", self.get_head_symbol())?;
188

            
189
1466358
            let mut args = self.arguments().peekable();
190
3681131
            while let Some(arg) = args.next() {
191
2214773
                write!(f, "{arg:?}")?;
192
2214773
                if args.peek().is_some() {
193
748415
                    write!(f, ", ")?;
194
1466358
                }
195
            }
196

            
197
1466358
            write!(f, ")")?;
198
        }
199

            
200
2766077
        Ok(())
201
2766077
    }
202
}
203

            
204
/// The protected version of [ATermRef], mostly derived from it.
205
///
206
/// # Safety
207
///
208
/// Note that terms use thread-local state for their protection mechanism, so
209
/// [ATerm] is not [Send]. Moreover, this means that terms cannot be stored in
210
/// thread-local storage themselves, or at least must be destroyed before the
211
/// thread exists, because the order in which thread-local destructors are
212
/// called is undefined. For this purpose one can use `ManuallyDrop` to simply
213
/// never drop thread local terms, since exiting the thread will clean up the
214
/// protection sets anyway.
215
///
216
/// We do not mark term access as unsafe, since that would make their use
217
/// cumbersome. An alternative would be to require
218
/// THREAD_TERM_POOL.with(|tp| ...) around every access, but that would
219
/// be very verbose.
220
pub struct ATerm {
221
    term: ATermRef<'static>,
222

            
223
    /// The root of the term in the protection set
224
    root: ProtectionIndex,
225

            
226
    // ATerm is not Send because it uses thread-local state for its protection
227
    // mechanism. However, it can be Sync since terms are immutable, and unlike
228
    // `Rc` cloning results in a local protected copy.
229
    _marker: PhantomUnsend,
230
}
231

            
232
impl ATerm {
233
    /// Creates a new term with the given symbol and arguments.
234
1634998
    pub fn with_args<'a, 'b, S: Symb<'a, 'b>, T: Term<'a, 'b>>(
235
1634998
        symbol: &'b S,
236
1634998
        args: &'b [T],
237
1634998
    ) -> Return<ATermRef<'static>> {
238
1634998
        THREAD_TERM_POOL.with(|tp| tp.create_term(symbol, args))
239
1634998
    }
240

            
241
    /// Creates a new term with the given symbol and an iterator over the arguments.
242
173485
    pub fn with_iter<'a, 'b, 'c, 'd, S, I, T>(symbol: &'b S, iter: I) -> ATerm
243
173485
    where
244
173485
        S: Symb<'a, 'b>,
245
173485
        I: IntoIterator<Item = T>,
246
173485
        T: Term<'c, 'd>,
247
    {
248
173485
        THREAD_TERM_POOL.with(|tp| tp.create_term_iter(symbol, iter))
249
173485
    }
250

            
251
    /// Creates a new term with the given symbol and an iterator over the arguments.
252
211056
    pub fn try_with_iter<'a, 'b, 'c, 'd, S, I, T>(symbol: &'b S, iter: I) -> Result<ATerm, MercError>
253
211056
    where
254
211056
        S: Symb<'a, 'b>,
255
211056
        I: IntoIterator<Item = Result<T, MercError>>,
256
211056
        T: Term<'c, 'd>,
257
    {
258
211056
        THREAD_TERM_POOL.with(|tp| tp.try_create_term_iter(symbol, iter))
259
211056
    }
260

            
261
    /// Creates a new term with the given symbol and a head term, along with a list of arguments.
262
12836231
    pub fn with_iter_head<'a, 'b, 'c, 'd, 'e, 'f, I, S, T, H>(symbol: &'b S, head: &'d H, iter: I) -> ATerm
263
12836231
    where
264
12836231
        S: Symb<'a, 'b>,
265
12836231
        H: Term<'c, 'd>,
266
12836231
        I: IntoIterator<Item = T>,
267
12836231
        T: Term<'e, 'f>,
268
    {
269
12836231
        THREAD_TERM_POOL.with(|tp| tp.create_term_iter_head(symbol, head, iter))
270
12836231
    }
271

            
272
    /// Creates a new constant term (arity 0) for the given symbol.
273
4846521
    pub fn constant<'a, 'b, S: Symb<'a, 'b>>(symbol: &'b S) -> ATerm {
274
4846521
        THREAD_TERM_POOL.with(|tp| tp.create_constant(symbol))
275
4846521
    }
276

            
277
    /// Constructs a term from the given string.
278
11433
    pub fn from_string(text: &str) -> Result<ATerm, MercError> {
279
11433
        THREAD_TERM_POOL.with(|tp| tp.from_string(text))
280
11433
    }
281

            
282
    /// Returns the term as a borrowed [ATermRef].
283
1000
    pub fn get(&self) -> ATermRef<'_> {
284
1000
        self.term.copy()
285
1000
    }
286

            
287
    /// Returns the root of the term
288
932307449
    pub fn root(&self) -> ProtectionIndex {
289
932307449
        self.root
290
932307449
    }
291

            
292
    /// Replace this term by the given term in place.
293
    pub fn replace<'a, 'b, T>(&mut self, value: Return<T>)
294
    where
295
        T: Term<'a, 'b>,
296
        'b: 'a,
297
    {
298
        // Replace the current term in the protection set by the value.
299
        // SAFETY: `value` still holds the recursive read guard, so no garbage
300
        // collection can run before `tp.replace` registers this index under
301
        // `self.root`; from then on the protection set keeps the term alive
302
        // until this `ATerm` unprotects it.
303
        let index = unsafe { value.shared().copy() };
304
        THREAD_TERM_POOL.with(|tp| tp.replace(value.guard, self.root, unsafe { index.copy() }));
305

            
306
        // Set the term itself.
307
        self.term = unsafe { ATermRef::from_index(&index) };
308
    }
309

            
310
    /// Creates a new term from the given reference and protection set root
311
    /// entry.
312
932307443
    pub(crate) fn from_index(term: &ATermIndex, root: ProtectionIndex) -> ATerm {
313
        unsafe {
314
932307443
            ATerm {
315
932307443
                term: ATermRef::from_index(term),
316
932307443
                root,
317
932307443
                _marker: PhantomData,
318
932307443
            }
319
        }
320
932307443
    }
321
}
322

            
323
impl<'a, 'b> Term<'a, 'b> for ATerm
324
where
325
    'b: 'a,
326
{
327
    delegate! {
328
        to self.term {
329
3
            fn protect(&self) -> ATerm;
330
81101243
            fn arg(&self, index: usize) -> ATermRef<'a>;
331
2330759
            fn arguments(&self) -> ATermArgs<'a>;
332
1009163027
            fn copy(&self) -> ATermRef<'a>;
333
1362329403
            fn get_head_symbol(&self) -> SymbolRef<'a>;
334
10393
            fn iter(&self) -> TermIterator<'a>;
335
2044694
            fn index(&self) -> usize;
336
7479635
            fn shared(&self) -> &ATermIndex;
337
        }
338
    }
339
}
340

            
341
impl Markable for ATerm {
342
    fn mark(&self, marker: &mut Marker) {
343
        marker.mark(&self.term);
344
    }
345

            
346
    fn contains_term(&self, term: &ATermRef<'_>) -> bool {
347
        *term == self.term
348
    }
349

            
350
    fn contains_symbol(&self, symbol: &SymbolRef<'_>) -> bool {
351
        self.get_head_symbol() == *symbol
352
    }
353

            
354
    fn len(&self) -> usize {
355
        1
356
    }
357
}
358

            
359
impl Drop for ATerm {
360
932307443
    fn drop(&mut self) {
361
932307443
        THREAD_TERM_POOL.with(|tp| tp.drop(self))
362
932307443
    }
363
}
364

            
365
impl Clone for ATerm {
366
732815517
    fn clone(&self) -> Self {
367
732815517
        self.copy().protect()
368
732815517
    }
369
}
370

            
371
impl fmt::Display for ATerm {
372
104000
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373
104000
        write!(f, "{}", self.copy())
374
104000
    }
375
}
376

            
377
impl fmt::Debug for ATerm {
378
447074
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
379
447074
        write!(f, "{:?}", self.copy())
380
447074
    }
381
}
382

            
383
impl Hash for ATerm {
384
79427827
    fn hash<H: Hasher>(&self, state: &mut H) {
385
79427827
        self.term.hash(state)
386
79427827
    }
387
}
388

            
389
impl PartialEq for ATerm {
390
640908179
    fn eq(&self, other: &Self) -> bool {
391
640908179
        self.term.eq(&other.term)
392
640908179
    }
393
}
394

            
395
impl PartialOrd for ATerm {
396
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
397
        Some(self.cmp(other))
398
    }
399
}
400

            
401
impl Ord for ATerm {
402
372506206
    fn cmp(&self, other: &Self) -> Ordering {
403
372506206
        self.term.cmp(&other.term)
404
372506206
    }
405
}
406

            
407
impl Eq for ATerm {}
408

            
409
/// A sendable variant of an `ATerm`.
410
///
411
/// # Details
412
///
413
/// Keeps track of an internal reference to the protection set it was protected from to ensure proper cleanup.
414
pub struct ATermSend {
415
    term: ATermRef<'static>,
416

            
417
    /// The root of the term in the protection set
418
    root: ProtectionIndex,
419

            
420
    /// A shared reference to the protection set that this term was created in.
421
    protection_set: Arc<Mutex<ProtectionSet<ATermIndex>>>,
422
}
423

            
424
unsafe impl Send for ATermSend {}
425
unsafe impl Sync for ATermSend {}
426

            
427
impl ATermSend {
428
    /// Takes ownership of an `ATerm` and makes it send.
429
200025
    pub fn from(term: ATerm) -> Self {
430
        // We need to insert the term into the protection set of the current
431
        // thread, and keep track of the root index to properly unprotect it on
432
        // drop.
433
200025
        let protection_set = THREAD_TERM_POOL.with(|tp| tp.send_term_protection_set().clone());
434
200025
        let term_ref: ATermRef<'static> = unsafe { ATermRef::from_index(&term.term.shared) };
435
        // SAFETY: `term` keeps the index alive during this call, and inserting
436
        // the copy into the send-term protection set makes it a GC root until
437
        // the `ATermSend` is dropped.
438
200025
        let root = protection_set
439
200025
            .lock()
440
200025
            .expect("Lock poisoned!")
441
200025
            .protect(unsafe { term.shared().copy() });
442

            
443
200025
        Self {
444
200025
            term: term_ref,
445
200025
            root,
446
200025
            protection_set,
447
200025
        }
448
200025
    }
449
}
450

            
451
impl Drop for ATermSend {
452
200025
    fn drop(&mut self) {
453
200025
        let mut guard = match self.protection_set.lock() {
454
200025
            Ok(guard) => guard,
455
            Err(poisoned) => poisoned.into_inner(),
456
        };
457
        // SAFETY: `self.root` was protected when this `ATermSend` was created and
458
        // `Drop` runs exactly once, so the root is unprotected exactly once.
459
200025
        unsafe {
460
200025
            guard.unprotect(self.root);
461
200025
        }
462
200025
    }
463
}
464

            
465
impl<'a, 'b> Term<'a, 'b> for ATermSend
466
where
467
    'b: 'a,
468
{
469
    delegate! {
470
        to self.term {
471
1
            fn protect(&self) -> ATerm;
472
            fn arg(&self, index: usize) -> ATermRef<'a>;
473
            fn arguments(&self) -> ATermArgs<'a>;
474
            fn copy(&self) -> ATermRef<'a>;
475
2
            fn get_head_symbol(&self) -> SymbolRef<'a>;
476
            fn iter(&self) -> TermIterator<'a>;
477
            fn index(&self) -> usize;
478
            fn shared(&self) -> &ATermIndex;
479
        }
480
    }
481
}
482

            
483
/// This is a wrapper around a term that indicates it is being returned from a
484
/// function.
485
///
486
/// The resulting term can have a lifetime tied to the thread-local term pool.
487
pub struct Return<T> {
488
    term: T,
489
    guard: RecursiveLockReadGuard<'static, GlobalTermPool>,
490
}
491

            
492
impl<T> Return<T> {
493
    /// Creates a new return value wrapping the given term.
494
5862402
    pub fn new(guard: RecursiveLockReadGuard<'static, GlobalTermPool>, term: T) -> Self {
495
5862402
        Return { term, guard }
496
5862402
    }
497

            
498
    /// Casts the inner term to another type, while keeping the same guard.
499
    pub fn cast<U>(self) -> Return<U>
500
    where
501
        T: Into<U>,
502
    {
503
        Return {
504
            term: self.term.into(),
505
            guard: self.guard,
506
        }
507
    }
508
}
509

            
510
impl<T: Transmutable> Return<T> {
511
    /// Maps the inner term to another type, while keeping the same guard.
512
    pub fn inner(&self) -> &T::Target<'_> {
513
        // SAFETY: The returned lifetime is bound to the borrow of `self` by the signature.
514
        unsafe { self.term.transmute_lifetime() }
515
    }
516
}
517

            
518
impl<'a, 'b, T: Term<'a, 'b>> Term<'a, 'b> for Return<T>
519
where
520
    'b: 'a,
521
{
522
    delegate! {
523
        to self.term {
524
5448284
            fn protect(&self) -> ATerm;
525
            fn arg(&'b self, index: usize) -> ATermRef<'a>;
526
            fn arguments(&'b self) -> ATermArgs<'a>;
527
            fn copy(&'b self) -> ATermRef<'a>;
528
            fn get_head_symbol(&'b self) -> SymbolRef<'a>;
529
            fn iter(&'b self) -> TermIterator<'a>;
530
            fn index(&self) -> usize;
531
            fn shared(&self) -> &ATermIndex;
532
        }
533
    }
534
}
535

            
536
/// An iterator over the arguments of a term.
537
pub struct ATermArgs<'a> {
538
    term: Option<ATermRef<'a>>,
539
    arity: usize,
540
    index: usize,
541
}
542

            
543
impl<'a> ATermArgs<'a> {
544
    pub fn empty() -> ATermArgs<'static> {
545
        ATermArgs {
546
            term: None,
547
            arity: 0,
548
            index: 0,
549
        }
550
    }
551

            
552
83203808
    fn new(term: ATermRef<'a>) -> ATermArgs<'a> {
553
83203808
        let arity = term.get_head_symbol().arity();
554
83203808
        ATermArgs {
555
83203808
            term: Some(term),
556
83203808
            arity,
557
83203808
            index: 0,
558
83203808
        }
559
83203808
    }
560

            
561
2766077
    pub fn is_empty(&self) -> bool {
562
2766077
        self.arity == 0
563
2766077
    }
564
}
565

            
566
impl<'a> Iterator for ATermArgs<'a> {
567
    type Item = ATermRef<'a>;
568

            
569
225738623
    fn next(&mut self) -> Option<Self::Item> {
570
225738623
        if self.index < self.arity {
571
148902140
            let res = Some(self.term.as_ref().unwrap().arg(self.index));
572

            
573
148902140
            self.index += 1;
574
148902140
            res
575
        } else {
576
76836483
            None
577
        }
578
225738623
    }
579

            
580
104995667
    fn size_hint(&self) -> (usize, Option<usize>) {
581
        // Report the exact remaining length so adapters such as `Skip` and `Map` keep
582
        // satisfying the `ExactSizeIterator` invariant (upper bound == lower bound).
583
104995667
        let remaining = self.arity - self.index;
584
104995667
        (remaining, Some(remaining))
585
104995667
    }
586
}
587

            
588
impl DoubleEndedIterator for ATermArgs<'_> {
589
2276563
    fn next_back(&mut self) -> Option<Self::Item> {
590
2276563
        if self.index < self.arity {
591
1098434
            let res = Some(self.term.as_ref().unwrap().arg(self.arity - 1));
592

            
593
1098434
            self.arity -= 1;
594
1098434
            res
595
        } else {
596
1178129
            None
597
        }
598
2276563
    }
599
}
600

            
601
impl ExactSizeIterator for ATermArgs<'_> {
602
92
    fn len(&self) -> usize {
603
92
        self.arity - self.index
604
92
    }
605
}
606

            
607
/// An iterator over all subterms of the given [ATerm] in preorder traversal, i.e.,
608
/// for f(g(a), b) we visit f(g(a), b), g(a), a, b.
609
pub struct TermIterator<'a> {
610
    queue: VecDeque<ATermRef<'a>>,
611
}
612

            
613
impl TermIterator<'_> {
614
79695
    pub fn new(t: ATermRef) -> TermIterator {
615
79695
        TermIterator {
616
79695
            queue: VecDeque::from([t]),
617
79695
        }
618
79695
    }
619
}
620

            
621
impl<'a> Iterator for TermIterator<'a> {
622
    type Item = ATermRef<'a>;
623

            
624
1257824
    fn next(&mut self) -> Option<Self::Item> {
625
1257824
        match self.queue.pop_back() {
626
1178129
            Some(term) => {
627
                // Put subterms in the queue
628
1178129
                for argument in term.arguments().rev() {
629
1098434
                    self.queue.push_back(argument);
630
1098434
                }
631

            
632
1178129
                Some(term)
633
            }
634
79695
            None => None,
635
        }
636
1257824
    }
637
}
638

            
639
/// Blanket implementation allowing passing borrowed terms as references.
640
/// TODO: Why is this necessary.
641
impl<'a, 'b, T: Term<'a, 'b>> Term<'a, 'b> for &'b T {
642
    fn protect(&self) -> ATerm {
643
        (*self).protect()
644
    }
645

            
646
    fn arg(&self, index: usize) -> ATermRef<'a> {
647
        (*self).arg(index)
648
    }
649

            
650
    fn arguments(&self) -> ATermArgs<'a> {
651
        (*self).arguments()
652
    }
653

            
654
    fn copy(&self) -> ATermRef<'a> {
655
        (*self).copy()
656
    }
657

            
658
    fn get_head_symbol(&self) -> SymbolRef<'a> {
659
        (*self).get_head_symbol()
660
    }
661

            
662
    fn iter(&self) -> TermIterator<'a> {
663
        (*self).iter()
664
    }
665

            
666
    fn index(&self) -> usize {
667
        (*self).index()
668
    }
669

            
670
20594325
    fn shared(&self) -> &ATermIndex {
671
20594325
        (*self).shared()
672
20594325
    }
673
}
674

            
675
#[cfg(test)]
676
mod tests {
677
    use std::sync::Arc;
678

            
679
    use parking_lot::Mutex;
680

            
681
    use crate::ATerm;
682
    use crate::ATermSend;
683
    use crate::Symbol;
684
    use crate::Term;
685
    use crate::storage::THREAD_TERM_POOL;
686

            
687
    #[test]
688
1
    fn test_send_term_outlives_creating_thread() {
689
        // An ATermSend created on a thread must keep its term alive after that thread exits,
690
        // even across garbage collection. This pins the invariant relied upon when GC reclaims
691
        // the send-term protection set slots of exited threads: a slot must not be released while
692
        // a live ATermSend still references it.
693
1
        let symbol = Symbol::new("send_outlives", 0);
694
1
        let term = std::thread::spawn(|| ATermSend::from(ATerm::constant(&Symbol::new("send_outlives", 0))))
695
1
            .join()
696
1
            .unwrap();
697

            
698
        // The creating thread has exited; force collections from this thread.
699
1
        THREAD_TERM_POOL.with(|tp| {
700
1
            tp.force_collect_garbage();
701
1
            tp.force_collect_garbage();
702
1
        });
703

            
704
        // The term must still be alive and structurally intact.
705
1
        assert_eq!(term.get_head_symbol(), symbol.copy());
706
1
    }
707

            
708
    #[test]
709
    #[cfg_attr(miri, ignore)] // This test runs too slow under miri.
710
1
    fn test_send_terms() {
711
        // Run two threads that create and drop sendable terms, and check that the protection set is properly cleaned up.
712
1
        let symbol = Symbol::new("a", 0);
713
1
        let term = Arc::new(Mutex::new(ATermSend::from(ATerm::constant(&symbol))));
714

            
715
1
        let thread_a = {
716
1
            let term = term.clone();
717

            
718
1
            std::thread::spawn(move || {
719
1
                let symbol = Symbol::new("a", 0);
720

            
721
100000
                for _ in 0..100000 {
722
100000
                    *term.lock() = ATermSend::from(ATerm::constant(&symbol));
723
100000
                }
724
1
            })
725
        };
726

            
727
100000
        for _ in 0..100000 {
728
100000
            *term.lock() = ATermSend::from(ATerm::constant(&symbol));
729
100000
        }
730

            
731
1
        thread_a.join().unwrap();
732
1
    }
733
}