use std::collections::HashSet;
use crate::mem::{Pointer, Root, ToRoot, Trace};
use super::Value;
#[derive(Clone, Debug, PartialEq)]
pub enum Next<'a> {
Pair(Pointer<'a, Pair<'a>>),
Dot(Value<'a>),
Nil,
}
#[derive(Debug)]
pub struct Pair<'a> {
head: Value<'a>,
tail: Value<'a>,
}
impl<'a> Pair<'a> {
pub(crate) fn new(mut head: Value<'a>, mut tail: Value<'a>) -> Self {
head.unlock();
tail.unlock();
Self { head, tail }
}
#[must_use]
pub fn next(&self) -> Next<'a> {
self.tail.as_pair_ptr().map_or_else(
|| {
if self.tail.is_nil() {
Next::Nil
} else {
Next::Dot(self.tail.clone())
}
},
Next::Pair,
)
}
#[must_use]
#[inline]
pub const fn car(&self) -> &Value<'a> {
&self.head
}
#[must_use]
#[inline]
pub const fn cdr(&self) -> &Value<'a> {
&self.tail
}
#[must_use]
#[inline]
pub fn caar(&self) -> Option<Value<'a>> {
self.car().as_pair().map(|pair| pair.car().clone())
}
#[must_use]
#[inline]
pub fn cadr(&self) -> Option<Value<'a>> {
self.cdr().as_pair().map(|pair| pair.car().clone())
}
#[must_use]
pub fn cdar(&self) -> Option<Value<'a>> {
self.car().as_pair().map(|pair| pair.cdr().clone())
}
#[must_use]
pub fn cddr(&self) -> Option<Value<'a>> {
self.cdr().as_pair().map(|pair| pair.cdr().clone())
}
#[must_use]
pub fn caaar(&self) -> Option<Value<'a>> {
self.caar()
.and_then(|value| value.as_pair().map(|pair| pair.car().clone()))
}
#[must_use]
pub fn caadr(&self) -> Option<Value<'a>> {
self.cadr()
.and_then(|value| value.as_pair().map(|pair| pair.car().clone()))
}
#[must_use]
pub fn cadar(&self) -> Option<Value<'a>> {
self.cdar()
.and_then(|value| value.as_pair().map(|pair| pair.car().clone()))
}
#[must_use]
pub fn caddr(&self) -> Option<Value<'a>> {
self.cddr()
.and_then(|value| value.as_pair().map(|pair| pair.car().clone()))
}
#[must_use]
pub fn cdaar(&self) -> Option<Value<'a>> {
self.caar()
.and_then(|value| value.as_pair().map(|pair| pair.cdr().clone()))
}
#[must_use]
pub fn cdadr(&self) -> Option<Value<'a>> {
self.cadr()
.and_then(|value| value.as_pair().map(|pair| pair.cdr().clone()))
}
#[must_use]
pub fn cddar(&self) -> Option<Value<'a>> {
self.cdar()
.and_then(|value| value.as_pair().map(|pair| pair.cdr().clone()))
}
#[must_use]
pub fn cdddr(&self) -> Option<Value<'a>> {
self.cddr()
.and_then(|value| value.as_pair().map(|pair| pair.cdr().clone()))
}
#[inline]
pub fn set_car(&mut self, mut value: Value<'a>) -> Value<'a> {
value.unlock();
let mut old_value = std::mem::replace(&mut self.head, value);
old_value.lock();
old_value
}
#[inline]
pub fn set_cdr(&mut self, mut value: Value<'a>) -> Value<'a> {
value.unlock();
let mut old_value = std::mem::replace(&mut self.tail, value);
old_value.lock();
old_value
}
#[must_use]
pub fn is_list(&self) -> bool {
let mut seen = HashSet::new();
let mut tail = &self.tail;
seen.insert(std::ptr::from_ref::<Pair<'_>>(self) as usize);
while let Some(pair) = tail.as_pair() {
let pair_ptr = std::ptr::from_ref::<Pair<'_>>(pair) as usize;
if seen.contains(&pair_ptr) {
return false;
}
seen.insert(pair_ptr);
tail = &pair.tail;
}
tail.is_nil()
}
#[must_use]
pub fn len(&self) -> usize {
let mut len = 1;
let mut seen = HashSet::new();
let mut tail = &self.tail;
seen.insert(std::ptr::from_ref::<Pair<'_>>(self) as usize);
while let Some(pair) = tail.as_pair() {
let pair_ptr = std::ptr::from_ref::<Pair<'_>>(pair) as usize;
if seen.contains(&pair_ptr) {
return len;
}
seen.insert(pair_ptr);
len += 1;
tail = &pair.tail;
}
len
}
#[must_use]
#[inline]
pub const fn is_empty(&self) -> bool {
false
}
}
impl<'a> Trace<'a> for Pair<'a> {
fn trace(&self, traced: &mut Vec<Root<'a>>) {
if let Some(root) = self.head.to_root() {
traced.push(root);
}
if let Some(root) = self.tail.to_root() {
traced.push(root);
}
}
}
impl<'a> PartialEq for Pair<'a> {
#[inline]
fn eq(&self, other: &Self) -> bool {
let lhs = std::ptr::from_ref::<Self>(self).cast::<u8>();
let rhs = std::ptr::from_ref::<Self>(other).cast::<u8>();
if std::ptr::eq(lhs, rhs) {
true
} else {
self.head == other.head && self.tail == other.tail
}
}
}