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}