use std::iter::FusedIterator;
use std::slice::Iter;
use crate::path::NormalizedPath;
use crate::value::VariantValue;
#[derive(Debug, Default, Eq, PartialEq, Clone)]
pub struct NodeList<'a, T: VariantValue>(Vec<&'a T>);
impl<'a, T: VariantValue> NodeList<'a, T> {
pub fn new(nodes: Vec<&'a T>) -> Self {
Self(nodes)
}
pub fn at_most_one(&self) -> Result<Option<&'a T>, AtMostOneError> {
if self.0.len() > 1 {
Err(AtMostOneError(self.0.len()))
} else {
Ok(self.0.first().copied())
}
}
pub fn exactly_one(&self) -> Result<&'a T, ExactlyOneError> {
if self.0.len() > 1 {
Err(ExactlyOneError::MoreThanOne(self.0.len()))
} else {
match self.0.first() {
Some(node) => Ok(*node),
None => Err(ExactlyOneError::Empty),
}
}
}
pub fn all(self) -> Vec<&'a T> {
self.0
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> Iter<'_, &T> {
self.0.iter()
}
pub fn first(&self) -> Option<&'a T> {
self.0.first().copied()
}
pub fn last(&self) -> Option<&'a T> {
self.0.last().copied()
}
pub fn get(&self, index: usize) -> Option<&'a T> {
self.0.get(index).copied()
}
}
impl<'a, T: VariantValue> IntoIterator for NodeList<'a, T> {
type Item = &'a T;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[derive(Debug, Clone)]
pub struct LocatedNode<'a, T: VariantValue> {
loc: NormalizedPath<'a>,
node: &'a T,
}
impl<T: VariantValue> PartialEq for LocatedNode<'_, T> {
fn eq(&self, other: &Self) -> bool {
self.loc == other.loc
}
}
impl<T: VariantValue> Eq for LocatedNode<'_, T> {}
impl<'a, T: VariantValue> LocatedNode<'a, T> {
pub(crate) fn new(loc: NormalizedPath<'a>, node: &'a T) -> Self {
Self { loc, node }
}
pub fn location(&self) -> &NormalizedPath<'a> {
&self.loc
}
pub fn into_location(self) -> NormalizedPath<'a> {
self.loc
}
pub fn node(&self) -> &'a T {
self.node
}
}
#[derive(Debug, Default, Eq, PartialEq, Clone)]
pub struct LocatedNodeList<'a, T: VariantValue>(Vec<LocatedNode<'a, T>>);
impl<'a, T: VariantValue> LocatedNodeList<'a, T> {
pub fn new(nodes: Vec<LocatedNode<'a, T>>) -> Self {
Self(nodes)
}
pub fn at_most_one(mut self) -> Result<Option<LocatedNode<'a, T>>, AtMostOneError> {
if self.0.len() > 1 {
Err(AtMostOneError(self.0.len()))
} else {
Ok(self.0.pop())
}
}
pub fn exactly_one(mut self) -> Result<LocatedNode<'a, T>, ExactlyOneError> {
if self.0.is_empty() {
Err(ExactlyOneError::Empty)
} else if self.0.len() > 1 {
Err(ExactlyOneError::MoreThanOne(self.0.len()))
} else {
Ok(self.0.pop().unwrap())
}
}
pub fn all(self) -> Vec<LocatedNode<'a, T>> {
self.0
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> Iter<'_, LocatedNode<'a, T>> {
self.0.iter()
}
pub fn locations(&self) -> Locations<'_, T> {
Locations { inner: self.iter() }
}
pub fn nodes(&self) -> Nodes<'_, T> {
Nodes { inner: self.iter() }
}
pub fn dedup(mut self) -> Self {
self.dedup_in_place();
self
}
pub fn dedup_in_place(&mut self) {
self.0.sort_unstable_by(|l, r| l.loc.cmp(&r.loc));
self.0.dedup();
}
pub fn first(&self) -> Option<&LocatedNode<'a, T>> {
self.0.first()
}
pub fn last(&self) -> Option<&LocatedNode<'a, T>> {
self.0.last()
}
pub fn get(&self, index: usize) -> Option<&LocatedNode<'a, T>> {
self.0.get(index)
}
}
impl<'a, T: VariantValue> IntoIterator for LocatedNodeList<'a, T> {
type Item = LocatedNode<'a, T>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[derive(Debug)]
pub struct Locations<'a, T: VariantValue> {
inner: Iter<'a, LocatedNode<'a, T>>,
}
impl<'a, T: VariantValue> Iterator for Locations<'a, T> {
type Item = &'a NormalizedPath<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|l| l.location())
}
}
impl<T: VariantValue> DoubleEndedIterator for Locations<'_, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back().map(|l| l.location())
}
}
impl<T: VariantValue> ExactSizeIterator for Locations<'_, T> {
fn len(&self) -> usize {
self.inner.len()
}
}
impl<T: VariantValue> FusedIterator for Locations<'_, T> {}
#[derive(Debug)]
pub struct Nodes<'a, T: VariantValue> {
inner: Iter<'a, LocatedNode<'a, T>>,
}
impl<'a, T: VariantValue> Iterator for Nodes<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|l| l.node())
}
}
impl<T: VariantValue> DoubleEndedIterator for Nodes<'_, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back().map(|l| l.node())
}
}
impl<T: VariantValue> ExactSizeIterator for Nodes<'_, T> {
fn len(&self) -> usize {
self.inner.len()
}
}
impl<T: VariantValue> FusedIterator for Nodes<'_, T> {}
#[derive(Debug, thiserror::Error)]
#[error("nodelist expected to contain at most one entry, but instead contains {0} entries")]
pub struct AtMostOneError(pub usize);
#[derive(Debug, thiserror::Error)]
pub enum ExactlyOneError {
#[error("nodelist expected to contain one entry, but is empty")]
Empty,
#[error("nodelist expected to contain one entry, but instead contains {0} entries")]
MoreThanOne(usize),
}
impl ExactlyOneError {
pub fn is_empty(&self) -> bool {
matches!(self, Self::Empty)
}
pub fn is_more_than_one(&self) -> bool {
matches!(self, Self::MoreThanOne(_))
}
pub fn as_more_than_one(&self) -> Option<usize> {
match self {
ExactlyOneError::Empty => None,
ExactlyOneError::MoreThanOne(u) => Some(*u),
}
}
}