use crate::node_data::{NodesDataLend, NodesDataLendGat};
use super::*;
macro_rules! link {
($accessor:expr, $index:expr) => {
$accessor.nodes.expect_node_link($index)
};
}
mod formatting;
mod iter;
pub use iter::*;
mod validate_error {
#[derive(thiserror::Error, Debug)]
pub enum OpaqueError<Index: core::fmt::Debug> {
#[error("`map_link` returned `None` for element at {0:?}")]
LinkNone(Index),
#[error(
"element {0:?} says the next element is {1:?}, but \
element {1:?} says the previous element is {2:?}"
)]
LinkInconsistent(Index, Index, Index),
}
}
impl<Index> Head<Index> {
#[inline]
pub fn read<Nodes>(&self, nodes: Nodes) -> ListAccessor<'_, Nodes, Index>
where
Nodes: NodesLink<Index>,
{
ListAccessor { head: self, nodes }
}
#[inline]
pub fn read_ref<'pool, Pool, MapLink, Element>(
&self,
pool: &'pool Pool,
map_link: MapLink,
) -> ListAccessor<'_, NodesWithMapLink<'pool, Pool, MapLink>, Index>
where
Pool: ?Sized + core::ops::Index<Index, Output = Element>,
MapLink: Fn(&'pool Element) -> &'pool Option<Link<Index>>,
Element: 'pool,
Index: 'pool + Clone,
{
self.read(NodesWithMapLink { pool, map_link })
}
}
#[derive(Debug)]
pub struct ListAccessor<'head, Nodes, Index> {
head: &'head Head<Index>,
nodes: Nodes,
}
impl<'head, Nodes, Index> Clone for ListAccessor<'head, Nodes, Index>
where
Nodes: Clone,
{
#[inline]
fn clone(&self) -> Self {
ListAccessor {
head: self.head,
nodes: self.nodes.clone(),
}
}
}
impl<'head, Nodes, Index> Copy for ListAccessor<'head, Nodes, Index> where Nodes: Copy {}
impl<'head, Nodes, Index> ListAccessor<'head, Nodes, Index>
where
Nodes: NodesLink<Index>,
Index: PartialEq + Clone,
{
#[inline]
pub fn nodes(&self) -> &Nodes {
&self.nodes
}
#[inline]
pub fn nodes_mut(&mut self) -> &mut Nodes {
&mut self.nodes
}
#[inline]
pub fn head(&self) -> &'head Head<Index> {
self.head
}
#[inline]
pub fn is_empty(&self) -> bool {
self.head.is_empty()
}
#[inline]
pub fn front_index(&self) -> Option<Index> {
self.head.first.clone()
}
#[inline]
pub fn back_index(&self) -> Option<Index> {
self.head.first.clone().map(|p| link!(self, p).prev.clone())
}
#[doc(alias = "first")]
#[inline]
pub fn front(&self) -> Option<<Nodes as NodesDataLendGat<'_, Index>>::Data>
where
Nodes: NodesDataLend<Index>,
{
self.front_index().map(|p| self.nodes.node_data_lend(p))
}
#[doc(alias = "last")]
#[inline]
pub fn back(&self) -> Option<<Nodes as NodesDataLendGat<'_, Index>>::Data>
where
Nodes: NodesDataLend<Index>,
{
self.back_index().map(|p| self.nodes.node_data_lend(p))
}
#[inline]
pub fn next_index(&self, i: Index) -> Option<Index> {
Some(link!(self, i).next.clone()).filter(|i| *i != *self.head.first.as_ref().unwrap())
}
#[inline]
pub fn prev_index(&self, i: Index) -> Option<Index> {
(i != *self.head.first.as_ref().unwrap()).then(|| link!(self, i).prev.clone())
}
#[track_caller]
pub fn validate(&self) -> Result<(), validate_error::OpaqueError<Index>>
where
Index: core::fmt::Debug,
{
use validate_error::OpaqueError as Error;
let Some(first) = &self.head.first else {
return Ok(());
};
let mut current = first.clone();
loop {
let link = self
.nodes
.node_link(current.clone())
.ok_or_else(|| Error::LinkNone(current.clone()))?;
let next_link = self
.nodes
.node_link(link.next.clone())
.ok_or_else(|| Error::LinkNone(link.next.clone()))?;
if current != next_link.prev {
return Err(Error::LinkInconsistent(
current,
link.next.clone(),
next_link.prev.clone(),
));
}
if link.next == *first {
break;
} else {
current = link.next.clone();
}
}
Ok(())
}
}