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 [ATermList] list term.
23
1912545
pub fn is_list_term<'a, 'b, T: Term<'a, 'b>>(t: &'b T) -> bool {
24
1912545
    THREAD_TERM_POOL.with_borrow(|tp| *tp.list_symbol() == t.get_head_symbol())
25
1912545
}
26

            
27
/// Returns true iff the term is an empty [ATermList].
28
1929912
pub fn is_empty_list_term<'a, 'b, T: Term<'a, 'b>>(t: &'b T) -> bool {
29
1929912
    THREAD_TERM_POOL.with_borrow(|tp| *tp.empty_list_symbol() == t.get_head_symbol())
30
1929912
}
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
8386
    pub fn head(&self) -> T {
49
8386
        self.term.arg(0).protect().into()
50
8386
    }
51

            
52
    /// Converts the list into a vector.
53
3560
    pub fn to_vec(&self) -> Vec<T> {
54
3560
        self.iter().collect()
55
3560
    }
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<I>(iter: I) -> Self
61
501
    where
62
501
        T: Into<ATerm>,
63
501
        I: DoubleEndedIterator<Item = T>,
64
    {
65
501
        let mut list = Self::empty();
66
503
        for item in iter.rev() {
67
203
            list = list.cons(item);
68
203
        }
69
501
        list
70
501
    }
71

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

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

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

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

            
111
    /// Obtain the tail, i.e. the remainder, of the list as a new [ATermList].
112
8389
    pub fn tail(&self) -> ATermList<T> {
113
8389
        self.term.arg(1).into()
114
8389
    }
115

            
116
    /// Returns an [ATermListIter] over all elements in the list.
117
7227
    pub fn iter(&self) -> ATermListIter<T> {
118
7227
        ATermListIter { current: self.clone() }
119
7227
    }
120
}
121

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

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

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

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

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

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

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

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

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

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

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

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

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

            
224
#[cfg(test)]
225
mod tests {
226
    use crate::ATermInt;
227
    use crate::ATermList;
228

            
229
    #[test]
230
1
    fn test_list_term() {
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
}