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 }
}
pub fn next(&self) -> Next<'a> {
if let Some(pair) = self.tail.as_pair_ptr() {
Next::Pair(pair)
} else if self.tail.is_nil() {
Next::Nil
} else {
Next::Dot(self.tail.clone())
}
}
#[inline]
pub const fn car(&self) -> &Value<'a> {
&self.head
}
#[inline]
pub const fn cdr(&self) -> &Value<'a> {
&self.tail
}
#[inline]
pub fn caar(&self) -> Option<Value<'a>> {
self.car().as_pair().map(|pair| pair.car().clone())
}
#[inline]
pub fn cadr(&self) -> Option<Value<'a>> {
self.cdr().as_pair().map(|pair| pair.car().clone())
}
pub fn cdar(&self) -> Option<Value<'a>> {
self.car().as_pair().map(|pair| pair.cdr().clone())
}
pub fn cddr(&self) -> Option<Value<'a>> {
self.cdr().as_pair().map(|pair| pair.cdr().clone())
}
pub fn caaar(&self) -> Option<Value<'a>> {
self.caar()
.and_then(|value| value.as_pair().map(|pair| pair.car().clone()))
}
pub fn caadr(&self) -> Option<Value<'a>> {
self.cadr()
.and_then(|value| value.as_pair().map(|pair| pair.car().clone()))
}
pub fn cadar(&self) -> Option<Value<'a>> {
self.cdar()
.and_then(|value| value.as_pair().map(|pair| pair.car().clone()))
}
pub fn caddr(&self) -> Option<Value<'a>> {
self.cddr()
.and_then(|value| value.as_pair().map(|pair| pair.car().clone()))
}
pub fn cdaar(&self) -> Option<Value<'a>> {
self.caar()
.and_then(|value| value.as_pair().map(|pair| pair.cdr().clone()))
}
pub fn cdadr(&self) -> Option<Value<'a>> {
self.cadr()
.and_then(|value| value.as_pair().map(|pair| pair.cdr().clone()))
}
pub fn cddar(&self) -> Option<Value<'a>> {
self.cdar()
.and_then(|value| value.as_pair().map(|pair| pair.cdr().clone()))
}
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
}
pub fn is_list(&self) -> bool {
let mut seen = HashSet::new();
let mut tail = &self.tail;
seen.insert(self as *const Pair<'_> as usize);
while let Some(pair) = tail.as_pair() {
let pair_ptr = pair as *const Pair<'_> as usize;
if seen.contains(&pair_ptr) {
return false;
} else {
seen.insert(pair_ptr);
}
tail = &pair.tail;
}
tail.is_nil()
}
pub fn len(&self) -> usize {
let mut len = 1;
let mut seen = HashSet::new();
let mut tail = &self.tail;
seen.insert(self as *const Pair<'_> as usize);
while let Some(pair) = tail.as_pair() {
let pair_ptr = pair as *const Pair<'_> as usize;
if seen.contains(&pair_ptr) {
return len;
} else {
seen.insert(pair_ptr);
}
len += 1;
tail = &pair.tail;
}
len
}
#[inline]
pub 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 = self as *const _ as *const u8;
let rhs = other as *const _ as *const u8;
if !std::ptr::eq(lhs, rhs) {
self.head == other.head && self.tail == other.tail
} else {
true
}
}
}