1
//!
2
//! A list of terms, where T is the type of the elements in the list.
3
//!
4
#![forbid(unsafe_code)]
5

            
6
use std::fmt;
7
use std::marker::PhantomData;
8

            
9
use delegate::delegate;
10
use itertools::Itertools;
11
use merc_utilities::MercError;
12

            
13
use crate::ATerm;
14
use crate::ATermArgs;
15
use crate::ATermIndex;
16
use crate::ATermRef;
17
use crate::SymbolRef;
18
use crate::Term;
19
use crate::TermIterator;
20
use crate::storage::THREAD_TERM_POOL;
21

            
22
/// Returns true iff the term is a list term.
23
1377932
pub fn is_list_term<'a, 'b>(t: &'b impl Term<'a, 'b>) -> bool {
24
1377932
    THREAD_TERM_POOL.with_borrow(|tp| *tp.list_symbol() == t.get_head_symbol())
25
1377932
}
26

            
27
/// Returns true iff the term is an empty list.
28
1387917
pub fn is_empty_list_term<'a, 'b>(t: &'b impl Term<'a, 'b>) -> bool {
29
1387917
    THREAD_TERM_POOL.with_borrow(|tp| *tp.empty_list_symbol() == t.get_head_symbol())
30
1387917
}
31

            
32
/// Represents a list of ATerms of type T.
33
///
34
/// # Details
35
///
36
/// Internally, uses two standard function symbols `cons` and `[]` to represent
37
/// lists. The `cons` function symbol has arity 2, where the first argument is
38
/// the head of the list and the second argument is the tail of the list. The
39
/// `[]` function symbol has arity 0 and represents the empty list.
40
pub struct ATermList<T> {
41
    term: ATerm,
42
    _marker: PhantomData<T>,
43
}
44

            
45
// TODO: This should use the trait Term<'a, 'b>
46
impl<T: From<ATerm>> ATermList<T> {
47
    /// Obtain the head, i.e. the first element, of the list.
48
2628
    pub fn head(&self) -> T {
49
2628
        self.term.arg(0).protect().into()
50
2628
    }
51

            
52
    /// Converts the list into a vector.
53
1182
    pub fn to_vec(&self) -> Vec<T> {
54
1182
        self.iter().collect()
55
1182
    }
56
}
57

            
58
impl<T> ATermList<T> {
59
    /// Constructs a new list from an iterator that is consumed.
60
501
    pub fn from_double_iter(iter: impl DoubleEndedIterator<Item = T>) -> Self
61
501
    where
62
501
        T: Into<ATerm>,
63
    {
64
501
        let mut list = Self::empty();
65
503
        for item in iter.rev() {
66
203
            list = list.cons(item);
67
203
        }
68
501
        list
69
501
    }
70

            
71
    /// Constructs a new list from an iterator that is consumed.
72
    pub fn try_from_double_iter(iter: impl DoubleEndedIterator<Item = Result<T, MercError>>) -> Result<Self, MercError>
73
    where
74
        T: Into<ATerm>,
75
    {
76
        let mut list = Self::empty();
77
        for item in iter.rev() {
78
            list = list.cons(item?);
79
        }
80
        Ok(list)
81
    }
82

            
83
    /// Constructs a new list with the given item as the head and the current list as the tail.
84
203
    pub fn cons(&self, item: T) -> Self
85
203
    where
86
203
        T: Into<ATerm>,
87
    {
88
        ATermList {
89
203
            term: THREAD_TERM_POOL.with_borrow(|tp| {
90
203
                ATerm::with_args(tp.list_symbol(), &[item.into().copy(), self.term.copy()]).protect()
91
203
            }),
92
203
            _marker: PhantomData,
93
        }
94
203
    }
95

            
96
    /// Constructs the empty list.
97
901
    pub fn empty() -> Self {
98
        ATermList {
99
901
            term: THREAD_TERM_POOL.with_borrow(|tp| ATerm::constant(tp.empty_list_symbol())),
100
901
            _marker: PhantomData,
101
        }
102
901
    }
103

            
104
    /// Returns true iff the list is empty.
105
5091
    pub fn is_empty(&self) -> bool {
106
5091
        is_empty_list_term(&self.term)
107
5091
    }
108

            
109
    /// Obtain the tail, i.e. the remainder, of the list.
110
2631
    pub fn tail(&self) -> ATermList<T> {
111
2631
        self.term.arg(1).into()
112
2631
    }
113

            
114
    /// Returns an iterator over all elements in the list.
115
2465
    pub fn iter(&self) -> ATermListIter<T> {
116
2465
        ATermListIter { current: self.clone() }
117
2465
    }
118
}
119

            
120
impl<'a, 'b, T> Term<'a, 'b> for ATermList<T>
121
where
122
    'b: 'a,
123
{
124
    delegate! {
125
        to self.term {
126
            fn protect(&self) -> ATerm;
127
            fn arg(&'b self, index: usize) -> ATermRef<'a>;
128
            fn arguments(&'b self) -> ATermArgs<'a>;
129
700
            fn copy(&'b self) -> ATermRef<'a>;
130
            fn get_head_symbol(&'b self) -> SymbolRef<'a>;
131
            fn iter(&'b self) -> TermIterator<'a>;
132
            fn index(&self) -> usize;
133
            fn shared(&self) -> &ATermIndex;
134
            fn annotation(&self) -> Option<usize>;
135
        }
136
    }
137
}
138

            
139
impl<T> Clone for ATermList<T> {
140
2465
    fn clone(&self) -> Self {
141
2465
        ATermList {
142
2465
            term: self.term.clone(),
143
2465
            _marker: PhantomData,
144
2465
        }
145
2465
    }
146
}
147

            
148
impl<T> From<ATermList<T>> for ATerm {
149
200
    fn from(value: ATermList<T>) -> Self {
150
200
        value.term
151
200
    }
152
}
153

            
154
impl<T: From<ATerm>> Iterator for ATermListIter<T> {
155
    type Item = T;
156

            
157
5090
    fn next(&mut self) -> Option<Self::Item> {
158
5090
        if self.current.is_empty() {
159
2465
            None
160
        } else {
161
2625
            let head = self.current.head();
162
2625
            self.current = self.current.tail();
163
2625
            Some(head)
164
        }
165
5090
    }
166
}
167

            
168
impl<T> From<ATerm> for ATermList<T> {
169
77
    fn from(value: ATerm) -> Self {
170
77
        debug_assert!(
171
77
            is_list_term(&value) || is_empty_list_term(&value),
172
            "Can only convert an aterm_list"
173
        );
174
77
        ATermList::<T> {
175
77
            term: value,
176
77
            _marker: PhantomData,
177
77
        }
178
77
    }
179
}
180

            
181
impl<'a, T> From<ATermRef<'a>> for ATermList<T> {
182
5093
    fn from(value: ATermRef<'a>) -> Self {
183
5093
        debug_assert!(
184
5093
            is_list_term(&value) || is_empty_list_term(&value),
185
            "Can only convert an aterm_list"
186
        );
187
5093
        ATermList::<T> {
188
5093
            term: value.protect(),
189
5093
            _marker: PhantomData,
190
5093
        }
191
5093
    }
192
}
193

            
194
impl<T: From<ATerm>> IntoIterator for ATermList<T> {
195
    type IntoIter = ATermListIter<T>;
196
    type Item = T;
197

            
198
1283
    fn into_iter(self) -> Self::IntoIter {
199
1283
        self.iter()
200
1283
    }
201
}
202

            
203
impl<T: From<ATerm>> IntoIterator for &ATermList<T> {
204
    type IntoIter = ATermListIter<T>;
205
    type Item = T;
206

            
207
    fn into_iter(self) -> Self::IntoIter {
208
        self.iter()
209
    }
210
}
211

            
212
impl<T: From<ATerm> + fmt::Display> fmt::Display for ATermList<T> {
213
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214
        write!(f, "[{}]", self.iter().format(","))
215
    }
216
}
217

            
218
/// The iterator over the elements of an [ATermList].
219
pub struct ATermListIter<T> {
220
    current: ATermList<T>,
221
}
222

            
223
#[cfg(test)]
224
mod tests {
225

            
226
    #[test]
227
1
    fn test_list_term() {
228
        use super::*;
229
        use crate::ATermInt;
230

            
231
1
        let list = ATermList::from_double_iter(vec![ATermInt::new(1), ATermInt::new(2), ATermInt::new(3)].into_iter());
232
1
        assert_eq!(list.head().value(), 1);
233
1
        assert_eq!(list.tail().head().value(), 2);
234
1
        assert_eq!(list.tail().tail().head().value(), 3);
235
1
        assert!(list.tail().tail().tail().is_empty());
236
1
    }
237
}