lexpr/
cons.rs

1//! List "cons cell" data type and accompanying iterator types.
2use std::fmt;
3
4use crate::Value;
5
6/// A Lisp "cons cell".
7///
8/// A cons cell is similiar to a two-element tuple in Rust. Its fields
9/// are traditionally called `car` and `cdr`, for obscure historical
10/// reasons. Both the `car` and the `cdr` field can hold any `Value`,
11/// including other cons cells.
12///
13/// This data type is used to represent singly-linked lists, by
14/// forming a chain of cons cells where the list element is kept in
15/// the `car` field, and the `cdr` field either points to the next
16/// cons cell, or terminates the list with any other value. Usually,
17/// that terminator value is `Value::Null`, also referred to as the
18/// empty list. If any other terminating value is used, the resulting
19/// linked list is referred to as "dotted", or "improper" list.
20///
21/// The `Cons` data type provides some utility function for the
22/// singly-linked list use case, such as iterating through the list or
23/// converting the list to a vector. To account for the possibility of
24/// dotted lists, the iterators and vector conversion functions have
25/// slightly unusual types.
26///
27/// The most natural way to traverse a singly linked list is probably by using
28/// the `list_iter` method.
29#[derive(PartialEq, Clone)]
30pub struct Cons {
31    inner: Box<(Value, Value)>,
32}
33
34impl fmt::Debug for Cons {
35    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
36        write!(fmt, "({:?} . {:?})", self.car(), self.cdr())
37    }
38}
39
40impl Cons {
41    /// Constructs a new cons cell from two values.
42    pub fn new<T, U>(car: T, cdr: U) -> Self
43    where
44        T: Into<Value>,
45        U: Into<Value>,
46    {
47        Cons {
48            inner: Box::new((car.into(), cdr.into())),
49        }
50    }
51
52    /// Returns a reference to the value in the `car` field.
53    pub fn car(&self) -> &Value {
54        &self.inner.0
55    }
56
57    /// Returns a mutable reference to the value in the `car` field.
58    pub fn car_mut(&mut self) -> &mut Value {
59        &mut self.inner.0
60    }
61
62    /// Sets the `car` field.
63    pub fn set_car(&mut self, car: impl Into<Value>) {
64        self.inner.0 = car.into()
65    }
66
67    /// Returns a reference to the value in the `cdr` field.
68    pub fn cdr(&self) -> &Value {
69        &self.inner.1
70    }
71
72    /// Returns a mutable reference to the value in the `cdr` field.
73    pub fn cdr_mut(&mut self) -> &mut Value {
74        &mut self.inner.1
75    }
76
77    /// Sets the `cdr` field.
78    pub fn set_cdr(&mut self, cdr: impl Into<Value>) {
79        self.inner.1 = cdr.into()
80    }
81
82    /// Returns references to the values in the `car` and `cdr` fields.
83    ///
84    /// ```
85    /// # use lexpr::{Cons, Value};
86    /// let cell = Cons::new(1, 2);
87    /// assert_eq!(cell.as_pair(), (&Value::from(1), &Value::from(2)));
88    /// ```
89    pub fn as_pair(&self) -> (&Value, &Value) {
90        (&self.inner.0, &self.inner.1)
91    }
92
93    /// Converts `self` into a pair of values without cloning.
94    ///
95    /// ```
96    /// # use lexpr::Cons;
97    /// let cell = Cons::new("a", 42);
98    /// assert_eq!(cell.car(), "a");
99    /// assert_eq!(cell.cdr(), 42);
100    /// let (car, cdr) = cell.into_pair();
101    /// assert_eq!(car, "a");
102    /// assert_eq!(cdr, 42);
103    /// ```
104    pub fn into_pair(self) -> (Value, Value) {
105        (self.inner.0, self.inner.1)
106    }
107
108    /// Obtains an iterator yielding references to all the cons cells in this
109    /// linked list.
110    ///
111    /// ```
112    /// # use lexpr::{Cons, Value};
113    /// for cell in Cons::new(1, Cons::new(2, Value::Null)).iter() {
114    ///    println!("list element: {}", cell.car());
115    /// }
116    /// ```
117    pub fn iter(&self) -> Iter<'_> {
118        Iter { cursor: Some(self) }
119    }
120
121    /// Converts `self` into a vector without cloning the elements.
122    ///
123    /// Returns the accumulated items of the list and the `cdr` of the last list
124    /// element. For proper lists, this will always be `Value::Null`.
125    ///
126    /// ```
127    /// # use lexpr::{Cons, Value};
128    /// let list = Cons::new(1, Cons::new(2, Cons::new(3, Value::Null)));
129    /// assert_eq!(list.into_vec(), (vec![Value::from(1), Value::from(2), Value::from(3)], Value::Null));
130    /// ```
131    pub fn into_vec(self) -> (Vec<Value>, Value) {
132        let mut vec = Vec::new();
133        for (item, rest) in self.into_iter() {
134            vec.push(item);
135            if let Some(rest) = rest {
136                return (vec, rest);
137            }
138        }
139        unreachable!()
140    }
141
142    /// Retrieves a vector, cloning the values.
143    ///
144    /// Returns the accumulated items of the list and the `cdr` of the last list
145    /// element. For proper lists, this will always be `Value::Null`.
146    ///
147    /// ```
148    /// # use lexpr::{Cons, Value};
149    /// let list = Cons::new(1, Cons::new(2, Cons::new(3, Value::Null)));
150    /// assert_eq!(list.to_vec(), (vec![Value::from(1), Value::from(2), Value::from(3)], Value::Null));
151    /// ```
152    pub fn to_vec(&self) -> (Vec<Value>, Value) {
153        let mut vec = Vec::new();
154        for pair in self.iter() {
155            vec.push(pair.car().clone());
156            if !pair.cdr().is_cons() {
157                return (vec, pair.cdr().clone());
158            }
159        }
160        unreachable!()
161    }
162
163    /// Retrieves a vector, taking references to the values.
164    ///
165    /// Returns the accumulated items of the list and the `cdr` of the last list
166    /// element. For proper lists, this will always be `Value::Null`.
167    ///
168    /// ```
169    /// # use lexpr::{Cons, Value};
170    /// let list = Cons::new(1, Cons::new(2, Cons::new(3, Value::Null)));
171    /// assert_eq!(list.to_ref_vec(), (vec![&Value::from(1), &Value::from(2), &Value::from(3)], &Value::Null));
172    /// ```
173    pub fn to_ref_vec(&self) -> (Vec<&Value>, &Value) {
174        let mut vec = Vec::new();
175        for pair in self.iter() {
176            vec.push(pair.car());
177            if !pair.cdr().is_cons() {
178                return (vec, pair.cdr());
179            }
180        }
181        unreachable!()
182    }
183
184    /// Returns an iterator that returns each element (`car` field) of a singly-linked list.
185    ///
186    /// The iterator returns `None` if a terminating value is encountered. For a
187    /// dotted list, the iterator is not yet exhausted at that point, and
188    /// produces the non-`Null` terminating value next.
189    pub fn list_iter(&self) -> ListIter<'_> {
190        ListIter::cons(self)
191    }
192}
193
194impl IntoIterator for Cons {
195    type Item = (Value, Option<Value>);
196    type IntoIter = IntoIter;
197
198    /// Obtains an iterator yielding the contents of the elements of this linked
199    /// list.
200    ///
201    /// The returned iterator transfers ownership of the values contained in the
202    /// list to the consumer of the iterator. For each cons cell but the last,
203    /// the iterator yields a pair containing the value in the cell's `car`
204    /// field and `None`. For the last cell, the yielded pair will contain the
205    /// value of `car` and `Some(cdr)`.
206    //
207    /// ```
208    /// # use lexpr::{Cons, Value};
209    /// let vec: Vec<_> = Cons::new(1, Cons::new(2, 3)).into_iter().collect();
210    /// assert_eq!(vec, vec![(Value::from(1), None), (Value::from(2), Some(Value::from(3)))]);
211    /// ```
212    fn into_iter(self) -> IntoIter {
213        IntoIter { cursor: Some(self) }
214    }
215}
216
217impl<'a> IntoIterator for &'a Cons {
218    type Item = &'a Cons;
219    type IntoIter = Iter<'a>;
220
221    fn into_iter(self) -> Iter<'a> {
222        self.iter()
223    }
224}
225
226/// An iterator over a chain of cons cells.
227///
228/// This is returned by the [`Cons::iter`] method.
229pub struct Iter<'a> {
230    cursor: Option<&'a Cons>,
231}
232
233impl<'a> Iter<'a> {
234    /// Returns the current cons cell, without advancing the iterator.
235    pub fn peek(&self) -> Option<&Cons> {
236        self.cursor
237    }
238}
239
240impl<'a> Iterator for Iter<'a> {
241    type Item = &'a Cons;
242
243    fn next(&mut self) -> Option<Self::Item> {
244        match self.cursor {
245            Some(pair) => {
246                match pair.cdr() {
247                    Value::Cons(pair) => self.cursor = Some(pair),
248                    _ => self.cursor = None,
249                }
250                Some(pair)
251            }
252            None => None,
253        }
254    }
255}
256
257/// An iterator consuming a chain of cons cells.
258///
259/// This is returned by the [`Cons::into_iter`] method.
260///
261/// [`Cons::into_iter`]: struct.Cons.html#method.into_iter
262pub struct IntoIter {
263    cursor: Option<Cons>,
264}
265
266impl IntoIter {
267    /// Returns the current cons cell, without advancing the iterator.
268    pub fn peek(&self) -> Option<&Cons> {
269        self.cursor.as_ref()
270    }
271
272    /// Returns a mutable reference to the current cons cell, without advancing
273    /// the iterator.
274    pub fn peek_mut(&mut self) -> Option<&mut Cons> {
275        self.cursor.as_mut()
276    }
277}
278
279impl Iterator for IntoIter {
280    type Item = (Value, Option<Value>);
281
282    fn next(&mut self) -> Option<Self::Item> {
283        match self.cursor.take() {
284            Some(cell) => {
285                let (car, cdr) = cell.into_pair();
286                match cdr {
287                    Value::Cons(cell) => {
288                        self.cursor = Some(cell);
289                        Some((car, None))
290                    }
291                    _ => {
292                        self.cursor = None;
293                        Some((car, Some(cdr)))
294                    }
295                }
296            }
297            None => None,
298        }
299    }
300}
301
302/// An iterator yielding the `car` field of a chain of cons cells.
303///
304/// # Improper lists
305///
306/// Since in Lisp, lists can be "improper", i.e., terminated by a value other than `Null`, this
307/// iterator type takes advantage of the fact that Rust's iterators can produce multiple sequences
308/// of values, each terminated by `None`. For an improper list, the terminating value is produced
309/// after the sequence of elements, as a singleton element, again followed by `None`.
310///
311/// For example, while the list `(1 2 3)` will produce the three expected `Some` values, followed by
312/// `None`, the list `(1 2 . 3)` will produce `Some` values for `1` and `2`, then a `None`, followed
313/// by a some value for `3`, and then the final `None`.
314#[derive(Debug, Clone)]
315pub struct ListIter<'a>(ListCursor<'a>);
316
317#[derive(Debug, Clone)]
318enum ListCursor<'a> {
319    Cons(&'a Cons),
320    Dot(&'a Value),
321    Rest(&'a Value),
322    Exhausted,
323}
324
325impl<'a> ListIter<'a> {
326    /// Returns true when the iterator is completely exhausted.
327    ///
328    /// For an improper list, true will only be returned after the terminating value has been
329    /// consumed.
330    pub fn is_empty(&self) -> bool {
331        matches!(&self.0, ListCursor::Exhausted)
332    }
333
334    /// Returns a peek at the value that would be returned by a call to `next`.
335    ///
336    /// For improper lists, this implies that after the last regular element, `None` will be
337    /// returned, while `is_empty` still returns false at that point.
338    pub fn peek(&self) -> Option<&Value> {
339        match &self.0 {
340            ListCursor::Cons(cell) => Some(cell.car()),
341            ListCursor::Dot(_) => None,
342            ListCursor::Rest(value) => Some(value),
343            ListCursor::Exhausted => None,
344        }
345    }
346
347    pub(crate) fn empty() -> Self {
348        ListIter(ListCursor::Exhausted)
349    }
350
351    pub(crate) fn cons(cell: &'a Cons) -> Self {
352        ListIter(ListCursor::Cons(cell))
353    }
354}
355
356impl<'a> Iterator for ListIter<'a> {
357    type Item = &'a Value;
358
359    fn next(&mut self) -> Option<Self::Item> {
360        match self.0 {
361            ListCursor::Cons(cell) => {
362                let car = cell.car();
363                match cell.cdr() {
364                    Value::Cons(next) => {
365                        self.0 = ListCursor::Cons(next);
366                    }
367                    Value::Null => {
368                        self.0 = ListCursor::Exhausted;
369                    }
370                    cdr => {
371                        self.0 = ListCursor::Dot(cdr);
372                    }
373                }
374                Some(car)
375            }
376            ListCursor::Dot(value) => {
377                self.0 = ListCursor::Rest(value);
378                None
379            }
380            ListCursor::Rest(value) => {
381                self.0 = ListCursor::Exhausted;
382                Some(value)
383            }
384            ListCursor::Exhausted => None,
385        }
386    }
387}