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

            
27
/// Returns true iff the term is an empty list.
28
1560261
pub fn is_empty_list_term<'a, 'b, T: Term<'a, 'b>>(t: &'b T) -> bool {
29
1560261
    THREAD_TERM_POOL.with_borrow(|tp| *tp.empty_list_symbol() == t.get_head_symbol())
30
1560261
}
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<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
5091
    pub fn is_empty(&self) -> bool {
108
5091
        is_empty_list_term(&self.term)
109
5091
    }
110

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

            
116
    /// Returns an iterator over all elements in the list.
117
2465
    pub fn iter(&self) -> ATermListIter<T> {
118
2465
        ATermListIter { current: self.clone() }
119
2465
    }
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
            fn annotation(&self) -> Option<usize>;
137
        }
138
    }
139
}
140

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

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

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

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

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

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

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

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

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

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

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

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

            
225
#[cfg(test)]
226
mod tests {
227

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

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