1
#![forbid(unsafe_code)]
2

            
3
use std::fmt;
4
use std::marker::PhantomData;
5

            
6
use delegate::delegate;
7
use itertools::Itertools;
8
use merc_utilities::MercError;
9

            
10
use crate::ATerm;
11
use crate::ATermArgs;
12
use crate::ATermIndex;
13
use crate::ATermRef;
14
use crate::SymbolRef;
15
use crate::Term;
16
use crate::TermIterator;
17
use crate::storage::THREAD_TERM_POOL;
18

            
19
/// Returns true iff the term is a [ATermList] list term.
20
2819822
pub fn is_list_term<'a, 'b, T: Term<'a, 'b>>(t: &'b T) -> bool {
21
2819822
    THREAD_TERM_POOL.with(|tp| *tp.list_symbol() == t.get_head_symbol())
22
2819822
}
23

            
24
/// Returns true iff the term is an empty [ATermList].
25
2847522
pub fn is_empty_list_term<'a, 'b, T: Term<'a, 'b>>(t: &'b T) -> bool {
26
2847522
    THREAD_TERM_POOL.with(|tp| *tp.empty_list_symbol() == t.get_head_symbol())
27
2847522
}
28

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

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

            
49
    /// Converts the list into a vector.
50
4901
    pub fn to_vec(&self) -> Vec<T> {
51
4901
        self.iter().collect()
52
4901
    }
53
}
54

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

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

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

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

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

            
107
    /// Obtain the tail, i.e. the remainder, of the list as a new [ATermList].
108
11313
    pub fn tail(&self) -> ATermList<T> {
109
11313
        self.term.arg(1).into()
110
11313
    }
111

            
112
    /// Returns an [ATermListIter] over all elements in the list.
113
9910
    pub fn iter(&self) -> ATermListIter<T> {
114
9910
        ATermListIter { current: self.clone() }
115
9910
    }
116
}
117

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

            
136
impl<T> Clone for ATermList<T> {
137
9910
    fn clone(&self) -> Self {
138
9910
        ATermList {
139
9910
            term: self.term.clone(),
140
9910
            _marker: PhantomData,
141
9910
        }
142
9910
    }
143
}
144

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

            
151
impl<T: From<ATerm>> Iterator for ATermListIter<T> {
152
    type Item = T;
153

            
154
21217
    fn next(&mut self) -> Option<Self::Item> {
155
21217
        if self.current.is_empty() {
156
9910
            None
157
        } else {
158
11307
            let head = self.current.head();
159
11307
            self.current = self.current.tail();
160
11307
            Some(head)
161
        }
162
21217
    }
163
}
164

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

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

            
191
impl<T: From<ATerm>> IntoIterator for ATermList<T> {
192
    type IntoIter = ATermListIter<T>;
193
    type Item = T;
194

            
195
5009
    fn into_iter(self) -> Self::IntoIter {
196
5009
        self.iter()
197
5009
    }
198
}
199

            
200
impl<T: From<ATerm>> IntoIterator for &ATermList<T> {
201
    type IntoIter = ATermListIter<T>;
202
    type Item = T;
203

            
204
    fn into_iter(self) -> Self::IntoIter {
205
        self.iter()
206
    }
207
}
208

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

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

            
220
#[cfg(test)]
221
mod tests {
222
    use crate::ATermInt;
223
    use crate::ATermList;
224

            
225
    #[test]
226
1
    fn test_list_term() {
227
1
        let list = ATermList::from_double_iter(vec![ATermInt::new(1), ATermInt::new(2), ATermInt::new(3)].into_iter());
228
1
        assert_eq!(list.head().value(), 1);
229
1
        assert_eq!(list.tail().head().value(), 2);
230
1
        assert_eq!(list.tail().tail().head().value(), 3);
231
1
        assert!(list.tail().tail().tail().is_empty());
232
1
    }
233
}