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

            
11
use delegate::delegate;
12

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
119
635343171
        self.shared().arguments()[index].borrow().copy()
120
635343171
    }
121

            
122
57830693
    fn arguments(&self) -> ATermArgs<'a> {
123
57830693
        ATermArgs::new(self.copy())
124
57830693
    }
125

            
126
3341213741
    fn copy(&self) -> ATermRef<'a> {
127
3341213741
        unsafe { ATermRef::from_index(self.shared()) }
128
3341213741
    }
129

            
130
11850495728
    fn get_head_symbol(&'b self) -> SymbolRef<'a> {
131
11850495728
        unsafe { std::mem::transmute::<SymbolRef<'b>, SymbolRef<'a>>(self.shared().symbol().copy()) }
132
11850495728
    }
133

            
134
55040
    fn iter(&self) -> TermIterator<'a> {
135
55040
        TermIterator::new(self.copy())
136
55040
    }
137

            
138
203850976
    fn index(&self) -> usize {
139
203850976
        self.shared.index()
140
203850976
    }
141

            
142
17690928788
    fn shared(&self) -> &ATermIndex {
143
17690928788
        &self.shared
144
17690928788
    }
145
}
146

            
147
impl Markable for ATermRef<'_> {
148
124219927
    fn mark(&self, marker: &mut Marker) {
149
124219927
        marker.mark(self);
150
124219927
    }
151

            
152
13223640
    fn contains_term(&self, term: &ATermRef<'_>) -> bool {
153
13223640
        term == self
154
13223640
    }
155

            
156
    fn contains_symbol(&self, symbol: &SymbolRef<'_>) -> bool {
157
        self.get_head_symbol() == *symbol
158
    }
159

            
160
    fn len(&self) -> usize {
161
        1
162
    }
163
}
164

            
165
impl fmt::Display for ATermRef<'_> {
166
104000
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167
104000
        write!(f, "{self:?}")
168
104000
    }
169
}
170

            
171
impl fmt::Debug for ATermRef<'_> {
172
1878854
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173
1878854
        if is_int_term(self) {
174
            write!(f, "{}", Into::<ATermIntRef>::into(self.copy()))?;
175
1878854
        } else if is_list_term(self) || is_empty_list_term(self) {
176
            write!(f, "{}", Into::<ATermList<ATerm>>::into(self.copy()))?;
177
1878854
        } else if self.arguments().is_empty() {
178
855771
            write!(f, "{}", self.get_head_symbol().name())?;
179
        } else {
180
            // Format the term with its head symbol and arguments, avoiding trailing comma
181
1023083
            write!(f, "{:?}(", self.get_head_symbol())?;
182

            
183
1023083
            let mut args = self.arguments().peekable();
184
2571457
            while let Some(arg) = args.next() {
185
1548374
                write!(f, "{arg:?}")?;
186
1548374
                if args.peek().is_some() {
187
525291
                    write!(f, ", ")?;
188
1023083
                }
189
            }
190

            
191
1023083
            write!(f, ")")?;
192
        }
193

            
194
1878854
        Ok(())
195
1878854
    }
196
}
197

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

            
217
    /// The root of the term in the protection set
218
    root: ProtectionIndex,
219

            
220
    // ATerm is not Send because it uses thread-local state for its protection
221
    // mechanism. However, it can be Sync since terms are immutable, and unlike
222
    // `Rc` cloning results in a local protected copy.
223
    _marker: PhantomUnsend,
224
}
225

            
226
impl ATerm {
227
    /// Creates a new term with the given symbol and arguments.
228
1392390
    pub fn with_args<'a, 'b, S: Symb<'a, 'b>, T: Term<'a, 'b>>(
229
1392390
        symbol: &'b S,
230
1392390
        args: &'b [T],
231
1392390
    ) -> Return<ATermRef<'static>> {
232
1392390
        THREAD_TERM_POOL.with_borrow(|tp| tp.create_term(symbol, args))
233
1392390
    }
234

            
235
    /// Creates a new term with the given symbol and an iterator over the arguments.
236
34070
    pub fn with_iter<'a, 'b, 'c, 'd, S, I, T>(symbol: &'b S, iter: I) -> ATerm
237
34070
    where
238
34070
        S: Symb<'a, 'b>,
239
34070
        I: IntoIterator<Item = T>,
240
34070
        T: Term<'c, 'd>,
241
    {
242
34070
        THREAD_TERM_POOL.with_borrow(|tp| tp.create_term_iter(symbol, iter))
243
34070
    }
244

            
245
    /// Creates a new term with the given symbol and an iterator over the arguments.
246
210217
    pub fn try_with_iter<'a, 'b, 'c, 'd, S, I, T>(symbol: &'b S, iter: I) -> Result<ATerm, MercError>
247
210217
    where
248
210217
        S: Symb<'a, 'b>,
249
210217
        I: IntoIterator<Item = Result<T, MercError>>,
250
210217
        T: Term<'c, 'd>,
251
    {
252
210217
        THREAD_TERM_POOL.with_borrow(|tp| tp.try_create_term_iter(symbol, iter))
253
210217
    }
254

            
255
    /// Creates a new term with the given symbol and a head term, along with a list of arguments.
256
4359807
    pub fn with_iter_head<'a, 'b, 'c, 'd, 'e, 'f, I, S, T, H>(symbol: &'b S, head: &'d H, iter: I) -> ATerm
257
4359807
    where
258
4359807
        S: Symb<'a, 'b>,
259
4359807
        H: Term<'c, 'd>,
260
4359807
        I: IntoIterator<Item = T>,
261
4359807
        T: Term<'e, 'f>,
262
    {
263
4359807
        THREAD_TERM_POOL.with_borrow(|tp| tp.create_term_iter_head(symbol, head, iter))
264
4359807
    }
265

            
266
    /// Creates a new constant term (arity 0) for the given [SymbolRef].
267
3445931
    pub fn constant(symbol: &SymbolRef<'_>) -> ATerm {
268
3445931
        THREAD_TERM_POOL.with_borrow(|tp| tp.create_constant(symbol))
269
3445931
    }
270

            
271
    /// Constructs a term from the given string.
272
6082
    pub fn from_string(text: &str) -> Result<ATerm, MercError> {
273
6082
        THREAD_TERM_POOL.with_borrow(|tp| tp.from_string(text))
274
6082
    }
275

            
276
    /// Returns the term as a borrowed [ATermRef].
277
1000
    pub fn get(&self) -> ATermRef<'_> {
278
1000
        self.term.copy()
279
1000
    }
280

            
281
    /// Returns the root of the term
282
649007447
    pub fn root(&self) -> ProtectionIndex {
283
649007447
        self.root
284
649007447
    }
285

            
286
    /// Replace this term by the given term in place.
287
    pub fn replace<'a, 'b, T>(&mut self, value: Return<T>)
288
    where
289
        T: Term<'a, 'b>,
290
        'b: 'a,
291
    {
292
        // Replace the current term in the protection set by the value.
293
        let index = value.shared().copy();
294
        THREAD_TERM_POOL.with_borrow(|tp| tp.replace(value.guard, self.root, index.copy()));
295

            
296
        // Set the term itself.
297
        self.term = unsafe { ATermRef::from_index(&index) };
298
    }
299

            
300
    /// Creates a new term from the given reference and protection set root
301
    /// entry.
302
649007441
    pub(crate) fn from_index(term: &ATermIndex, root: ProtectionIndex) -> ATerm {
303
        unsafe {
304
649007441
            ATerm {
305
649007441
                term: ATermRef::from_index(term),
306
649007441
                root,
307
649007441
                _marker: PhantomData,
308
649007441
            }
309
        }
310
649007441
    }
311
}
312

            
313
impl<'a, 'b> Term<'a, 'b> for ATerm
314
where
315
    'b: 'a,
316
{
317
    delegate! {
318
        to self.term {
319
3
            fn protect(&self) -> ATerm;
320
54068945
            fn arg(&self, index: usize) -> ATermRef<'a>;
321
1758046
            fn arguments(&self) -> ATermArgs<'a>;
322
682848335
            fn copy(&self) -> ATermRef<'a>;
323
909454642
            fn get_head_symbol(&self) -> SymbolRef<'a>;
324
3440
            fn iter(&self) -> TermIterator<'a>;
325
1362284
            fn index(&self) -> usize;
326
5843964
            fn shared(&self) -> &ATermIndex;
327
        }
328
    }
329
}
330

            
331
impl Markable for ATerm {
332
    fn mark(&self, marker: &mut Marker) {
333
        marker.mark(&self.term);
334
    }
335

            
336
    fn contains_term(&self, term: &ATermRef<'_>) -> bool {
337
        *term == self.term
338
    }
339

            
340
    fn contains_symbol(&self, symbol: &SymbolRef<'_>) -> bool {
341
        self.get_head_symbol() == *symbol
342
    }
343

            
344
    fn len(&self) -> usize {
345
        1
346
    }
347
}
348

            
349
impl Drop for ATerm {
350
649007441
    fn drop(&mut self) {
351
649007441
        THREAD_TERM_POOL.with_borrow(|tp| tp.drop(self))
352
649007441
    }
353
}
354

            
355
impl Clone for ATerm {
356
509936507
    fn clone(&self) -> Self {
357
509936507
        self.copy().protect()
358
509936507
    }
359
}
360

            
361
impl<'a> Borrow<ATermRef<'a>> for ATerm {
362
    fn borrow(&self) -> &ATermRef<'a> {
363
        &self.term
364
    }
365
}
366

            
367
impl fmt::Display for ATerm {
368
104000
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369
104000
        write!(f, "{}", self.copy())
370
104000
    }
371
}
372

            
373
impl fmt::Debug for ATerm {
374
226480
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375
226480
        write!(f, "{:?}", self.copy())
376
226480
    }
377
}
378

            
379
impl Hash for ATerm {
380
27907502
    fn hash<H: Hasher>(&self, state: &mut H) {
381
27907502
        self.term.hash(state)
382
27907502
    }
383
}
384

            
385
impl PartialEq for ATerm {
386
445482583
    fn eq(&self, other: &Self) -> bool {
387
445482583
        self.term.eq(&other.term)
388
445482583
    }
389
}
390

            
391
impl PartialOrd for ATerm {
392
259134560
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
393
259134560
        Some(self.cmp(other))
394
259134560
    }
395
}
396

            
397
impl Ord for ATerm {
398
259134560
    fn cmp(&self, other: &Self) -> Ordering {
399
259134560
        self.term.cmp(&other.term)
400
259134560
    }
401
}
402

            
403
impl Eq for ATerm {}
404

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

            
413
    /// The root of the term in the protection set
414
    root: ProtectionIndex,
415

            
416
    /// A shared reference to the protection set that this term was created in.
417
    protection_set: Arc<Mutex<ProtectionSet<ATermIndex>>>,
418
}
419

            
420
unsafe impl Send for ATermSend {}
421
unsafe impl Sync for ATermSend {}
422

            
423
impl ATermSend {
424
    /// Takes ownership of an `ATerm` and makes it send.
425
200001
    pub fn from(term: ATerm) -> Self {
426
        // We need to insert the term into the protection set of the current
427
        // thread, and keep track of the root index to properly unprotect it on
428
        // drop.
429
200001
        let protection_set = THREAD_TERM_POOL.with_borrow(|tp| tp.send_term_protection_set().clone());
430
200001
        let term_ref: ATermRef<'static> = unsafe { ATermRef::from_index(&term.term.shared) };
431
200001
        let root = protection_set
432
200001
            .lock()
433
200001
            .expect("Lock poisoned!")
434
200001
            .protect(term.shared().copy());
435

            
436
200001
        Self {
437
200001
            term: term_ref,
438
200001
            root,
439
200001
            protection_set,
440
200001
        }
441
200001
    }
442
}
443

            
444
impl Drop for ATermSend {
445
200001
    fn drop(&mut self) {
446
200001
        let mut guard = match self.protection_set.lock() {
447
200001
            Ok(guard) => guard,
448
            Err(poisoned) => poisoned.into_inner(),
449
        };
450
200001
        guard.unprotect(self.root);
451
200001
    }
452
}
453

            
454
impl<'a, 'b> Term<'a, 'b> for ATermSend
455
where
456
    'b: 'a,
457
{
458
    delegate! {
459
        to self.term {
460
            fn protect(&self) -> ATerm;
461
            fn arg(&self, index: usize) -> ATermRef<'a>;
462
            fn arguments(&self) -> ATermArgs<'a>;
463
            fn copy(&self) -> ATermRef<'a>;
464
            fn get_head_symbol(&self) -> SymbolRef<'a>;
465
            fn iter(&self) -> TermIterator<'a>;
466
            fn index(&self) -> usize;
467
            fn shared(&self) -> &ATermIndex;
468
        }
469
    }
470
}
471

            
472
/// This is a wrapper around a term that indicates it is being returned from a
473
/// function.
474
///
475
/// The resulting term can have a lifetime tied to the thread-local term pool.
476
pub struct Return<T> {
477
    term: T,
478
    guard: RecursiveLockReadGuard<'static, GlobalTermPool>,
479
}
480

            
481
impl<T> Return<T> {
482
    /// Creates a new return value wrapping the given term.
483
4378933
    pub fn new(guard: RecursiveLockReadGuard<'static, GlobalTermPool>, term: T) -> Self {
484
4378933
        Return { term, guard }
485
4378933
    }
486

            
487
    /// Casts the inner term to another type, while keeping the same guard.
488
    pub fn cast<U>(self) -> Return<U>
489
    where
490
        T: Into<U>,
491
    {
492
        Return {
493
            term: self.term.into(),
494
            guard: self.guard,
495
        }
496
    }
497
}
498

            
499
impl<T: Transmutable> Return<T> {
500
    /// Maps the inner term to another type, while keeping the same guard.
501
    pub fn inner(&self) -> &T::Target<'_> {
502
        self.term.transmute_lifetime()
503
    }
504
}
505

            
506
impl<'a, 'b, T: Term<'a, 'b>> Term<'a, 'b> for Return<T>
507
where
508
    'b: 'a,
509
{
510
    delegate! {
511
        to self.term {
512
3970281
            fn protect(&self) -> ATerm;
513
            fn arg(&'b self, index: usize) -> ATermRef<'a>;
514
            fn arguments(&'b self) -> ATermArgs<'a>;
515
            fn copy(&'b self) -> ATermRef<'a>;
516
            fn get_head_symbol(&'b self) -> SymbolRef<'a>;
517
            fn iter(&'b self) -> TermIterator<'a>;
518
            fn index(&self) -> usize;
519
            fn shared(&self) -> &ATermIndex;
520
        }
521
    }
522
}
523

            
524
/// An iterator over the arguments of a term.
525
pub struct ATermArgs<'a> {
526
    term: Option<ATermRef<'a>>,
527
    arity: usize,
528
    index: usize,
529
}
530

            
531
impl<'a> ATermArgs<'a> {
532
    pub fn empty() -> ATermArgs<'static> {
533
        ATermArgs {
534
            term: None,
535
            arity: 0,
536
            index: 0,
537
        }
538
    }
539

            
540
57830693
    fn new(term: ATermRef<'a>) -> ATermArgs<'a> {
541
57830693
        let arity = term.get_head_symbol().arity();
542
57830693
        ATermArgs {
543
57830693
            term: Some(term),
544
57830693
            arity,
545
57830693
            index: 0,
546
57830693
        }
547
57830693
    }
548

            
549
1878854
    pub fn is_empty(&self) -> bool {
550
1878854
        self.arity == 0
551
1878854
    }
552
}
553

            
554
impl<'a> Iterator for ATermArgs<'a> {
555
    type Item = ATermRef<'a>;
556

            
557
158817285
    fn next(&mut self) -> Option<Self::Item> {
558
158817285
        if self.index < self.arity {
559
105365878
            let res = Some(self.term.as_ref().unwrap().arg(self.index));
560

            
561
105365878
            self.index += 1;
562
105365878
            res
563
        } else {
564
53451407
            None
565
        }
566
158817285
    }
567
}
568

            
569
impl DoubleEndedIterator for ATermArgs<'_> {
570
1576256
    fn next_back(&mut self) -> Option<Self::Item> {
571
1576256
        if self.index < self.arity {
572
760608
            let res = Some(self.term.as_ref().unwrap().arg(self.arity - 1));
573

            
574
760608
            self.arity -= 1;
575
760608
            res
576
        } else {
577
815648
            None
578
        }
579
1576256
    }
580
}
581

            
582
impl ExactSizeIterator for ATermArgs<'_> {
583
73039488
    fn len(&self) -> usize {
584
73039488
        self.arity - self.index
585
73039488
    }
586
}
587

            
588
/// An iterator over all subterms of the given [ATerm] in preorder traversal, i.e.,
589
/// for f(g(a), b) we visit f(g(a), b), g(a), a, b.
590
pub struct TermIterator<'a> {
591
    queue: VecDeque<ATermRef<'a>>,
592
}
593

            
594
impl TermIterator<'_> {
595
55040
    pub fn new(t: ATermRef) -> TermIterator {
596
55040
        TermIterator {
597
55040
            queue: VecDeque::from([t]),
598
55040
        }
599
55040
    }
600
}
601

            
602
impl<'a> Iterator for TermIterator<'a> {
603
    type Item = ATermRef<'a>;
604

            
605
870688
    fn next(&mut self) -> Option<Self::Item> {
606
870688
        match self.queue.pop_back() {
607
815648
            Some(term) => {
608
                // Put subterms in the queue
609
815648
                for argument in term.arguments().rev() {
610
760608
                    self.queue.push_back(argument);
611
760608
                }
612

            
613
815648
                Some(term)
614
            }
615
55040
            None => None,
616
        }
617
870688
    }
618
}
619

            
620
/// Blanket implementation allowing passing borrowed terms as references.
621
/// TODO: Why is this necessary.
622
impl<'a, 'b, T: Term<'a, 'b>> Term<'a, 'b> for &'b T {
623
    fn protect(&self) -> ATerm {
624
        (*self).protect()
625
    }
626

            
627
    fn arg(&self, index: usize) -> ATermRef<'a> {
628
        (*self).arg(index)
629
    }
630

            
631
    fn arguments(&self) -> ATermArgs<'a> {
632
        (*self).arguments()
633
    }
634

            
635
    fn copy(&self) -> ATermRef<'a> {
636
        (*self).copy()
637
    }
638

            
639
    fn get_head_symbol(&self) -> SymbolRef<'a> {
640
        (*self).get_head_symbol()
641
    }
642

            
643
    fn iter(&self) -> TermIterator<'a> {
644
        (*self).iter()
645
    }
646

            
647
    fn index(&self) -> usize {
648
        (*self).index()
649
    }
650

            
651
7154128
    fn shared(&self) -> &ATermIndex {
652
7154128
        (*self).shared()
653
7154128
    }
654
}
655

            
656
#[cfg(test)]
657
mod tests {
658
    use std::sync::Arc;
659

            
660
    use parking_lot::Mutex;
661

            
662
    use crate::ATerm;
663
    use crate::ATermSend;
664
    use crate::Symbol;
665

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

            
673
1
        let thread_a = {
674
1
            let term = term.clone();
675
1
            let thread_a = std::thread::spawn(move || {
676
1
                let symbol = Symbol::new("a", 0);
677

            
678
100000
                for _ in 0..100000 {
679
100000
                    *term.lock() = ATermSend::from(ATerm::constant(&symbol));
680
100000
                }
681
1
            });
682

            
683
1
            thread_a
684
        };
685

            
686
100000
        for _ in 0..100000 {
687
100000
            *term.lock() = ATermSend::from(ATerm::constant(&symbol));
688
100000
        }
689

            
690
1
        thread_a.join().unwrap();
691
1
    }
692
}