use crate::Value;
#[derive(thiserror::Error, Debug, PartialEq, Eq)]
pub enum ListError {
#[error("Expected a cons cell")]
NotCons,
#[error("Improper list")]
ImproperList,
#[error("Failed to allocate Lisp root")]
AllocationFailed,
}
pub struct ListIter<'a, 'rt> {
start: Option<&'a Value<'rt>>,
tail: Option<Value<'rt>>,
}
impl<'a, 'rt> ListIter<'a, 'rt> {
pub(crate) fn new(list: &'a Value<'rt>) -> Self {
Self {
start: Some(list),
tail: None,
}
}
}
impl<'a, 'rt> Iterator for ListIter<'a, 'rt> {
type Item = Result<Value<'rt>, ListError>;
fn next(&mut self) -> Option<Self::Item> {
let current = match self.tail.as_ref() {
Some(tail) => tail,
None => self.start.take()?,
};
if current.is_nil() {
self.tail = None;
return None;
}
if !current.is_cons() {
self.tail = None;
return Some(Err(ListError::ImproperList));
}
let result = (|| {
let head = current.car()?;
let tail = current.cdr()?;
Ok((head, tail))
})();
match result {
Ok((head, tail)) => {
self.tail = Some(tail);
Some(Ok(head))
}
Err(error) => {
self.tail = None;
Some(Err(error))
}
}
}
}