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

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

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

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

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

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

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

            
65
    /// Constructs a new list with the given item as the head and the current list as the tail.
66
203
    pub fn cons(&self, item: T) -> Self
67
203
    where
68
203
        T: Into<ATerm>,
69
    {
70
        ATermList {
71
203
            term: THREAD_TERM_POOL.with_borrow(|tp| {
72
203
                ATerm::with_args(tp.list_symbol(), &[item.into().copy(), self.term.copy()]).protect()
73
203
            }),
74
203
            _marker: PhantomData,
75
        }
76
203
    }
77

            
78
    /// Constructs the empty list.
79
901
    pub fn empty() -> Self {
80
        ATermList {
81
901
            term: THREAD_TERM_POOL.with_borrow(|tp| ATerm::constant(tp.empty_list_symbol())),
82
901
            _marker: PhantomData,
83
        }
84
901
    }
85

            
86
    /// Returns true iff the list is empty.
87
849
    pub fn is_empty(&self) -> bool {
88
849
        is_empty_list_term(&self.term)
89
849
    }
90

            
91
    /// Obtain the tail, i.e. the remainder, of the list.
92
525
    pub fn tail(&self) -> ATermList<T> {
93
525
        self.term.arg(1).into()
94
525
    }
95

            
96
    /// Returns an iterator over all elements in the list.
97
329
    pub fn iter(&self) -> ATermListIter<T> {
98
329
        ATermListIter { current: self.clone() }
99
329
    }
100
}
101

            
102
impl<'a, 'b, T> Term<'a, 'b> for ATermList<T>
103
where
104
    'b: 'a,
105
{
106
    delegate! {
107
        to self.term {
108
            fn protect(&self) -> ATerm;
109
            fn arg(&'b self, index: usize) -> ATermRef<'a>;
110
            fn arguments(&'b self) -> ATermArgs<'a>;
111
700
            fn copy(&'b self) -> ATermRef<'a>;
112
            fn get_head_symbol(&'b self) -> SymbolRef<'a>;
113
            fn iter(&'b self) -> TermIterator<'a>;
114
            fn index(&self) -> usize;
115
            fn shared(&self) -> &ATermIndex;
116
            fn annotation(&self) -> Option<usize>;
117
        }
118
    }
119
}
120

            
121
impl<T> Clone for ATermList<T> {
122
329
    fn clone(&self) -> Self {
123
329
        ATermList {
124
329
            term: self.term.clone(),
125
329
            _marker: PhantomData,
126
329
        }
127
329
    }
128
}
129

            
130
impl<T> From<ATermList<T>> for ATerm {
131
200
    fn from(value: ATermList<T>) -> Self {
132
200
        value.term
133
200
    }
134
}
135

            
136
impl<T: From<ATerm>> Iterator for ATermListIter<T> {
137
    type Item = T;
138

            
139
848
    fn next(&mut self) -> Option<Self::Item> {
140
848
        if self.current.is_empty() {
141
329
            None
142
        } else {
143
519
            let head = self.current.head();
144
519
            self.current = self.current.tail();
145
519
            Some(head)
146
        }
147
848
    }
148
}
149

            
150
impl<T> From<ATerm> for ATermList<T> {
151
1
    fn from(value: ATerm) -> Self {
152
1
        debug_assert!(
153
1
            is_list_term(&value) || is_empty_list_term(&value),
154
            "Can only convert a aterm_list"
155
        );
156
1
        ATermList::<T> {
157
1
            term: value,
158
1
            _marker: PhantomData,
159
1
        }
160
1
    }
161
}
162

            
163
impl<'a, T> From<ATermRef<'a>> for ATermList<T> {
164
844
    fn from(value: ATermRef<'a>) -> Self {
165
844
        debug_assert!(
166
844
            is_list_term(&value) || is_empty_list_term(&value),
167
            "Can only convert a aterm_list"
168
        );
169
844
        ATermList::<T> {
170
844
            term: value.protect(),
171
844
            _marker: PhantomData,
172
844
        }
173
844
    }
174
}
175

            
176
impl<T: From<ATerm>> IntoIterator for ATermList<T> {
177
    type IntoIter = ATermListIter<T>;
178
    type Item = T;
179

            
180
320
    fn into_iter(self) -> Self::IntoIter {
181
320
        self.iter()
182
320
    }
183
}
184

            
185
impl<T: From<ATerm>> IntoIterator for &ATermList<T> {
186
    type IntoIter = ATermListIter<T>;
187
    type Item = T;
188

            
189
    fn into_iter(self) -> Self::IntoIter {
190
        self.iter()
191
    }
192
}
193

            
194
impl<T: From<ATerm> + fmt::Display> fmt::Display for ATermList<T> {
195
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196
        write!(f, "[{}]", self.iter().format(","))
197
    }
198
}
199

            
200
/// The iterator over the elements of an [ATermList].
201
pub struct ATermListIter<T> {
202
    current: ATermList<T>,
203
}
204

            
205
#[cfg(test)]
206
mod tests {
207

            
208
    #[test]
209
1
    fn test_list_term() {
210
        use super::*;
211
        use crate::ATermInt;
212

            
213
1
        let list = ATermList::from_double_iter(vec![ATermInt::new(1), ATermInt::new(2), ATermInt::new(3)].into_iter());
214
1
        assert_eq!(list.head().value(), 1);
215
1
        assert_eq!(list.tail().head().value(), 2);
216
1
        assert_eq!(list.tail().tail().head().value(), 3);
217
1
        assert!(list.tail().tail().tail().is_empty());
218
1
    }
219
}