use crate::{
node::{Node, TokenItem, Tokens},
private::Sealed,
tokenizer::{Position, TokenReference},
util,
visitors::{Visit, VisitMut, Visitor, VisitorMut},
};
use derive_more::Display as DeriveDisplay;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::{fmt::Display, iter::FromIterator};
#[derive(Clone, Debug, DeriveDisplay, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display(bound(T: Display))]
#[display("{}", util::join_vec(pairs))]
pub struct Punctuated<T> {
pairs: Vec<Pair<T>>,
}
impl<T> Punctuated<T> {
pub fn new() -> Self {
Self { pairs: Vec::new() }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn len(&self) -> usize {
self.pairs.len()
}
pub fn iter(&self) -> Iter<'_, T> {
self.into_iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
self.into_iter()
}
pub fn into_pairs(self) -> impl Iterator<Item = Pair<T>> {
self.pairs.into_iter()
}
pub fn first(&self) -> Option<&Pair<T>> {
self.pairs.first()
}
pub fn last(&self) -> Option<&Pair<T>> {
self.pairs.last()
}
pub fn pairs(&self) -> impl Iterator<Item = &Pair<T>> {
self.pairs.iter()
}
pub fn pairs_mut(&mut self) -> impl Iterator<Item = &mut Pair<T>> {
self.pairs.iter_mut()
}
pub fn pop(&mut self) -> Option<Pair<T>> {
self.pairs.pop()
}
pub fn push(&mut self, pair: Pair<T>) {
self.pairs.push(pair);
}
pub fn push_punctuated(&mut self, value: T, punctuation: TokenReference) {
let last_pair = self.pairs.pop().expect(
"push_punctuated adds the punctuation onto the last element, but there are no elements",
);
if last_pair.punctuation().is_some() {
self.pairs.push(last_pair);
panic!("push_punctuated adds the punctuation onto the last element, but the last element already has punctuation");
}
self.pairs
.push(Pair::Punctuated(last_pair.into_value(), punctuation));
self.pairs.push(Pair::new(value, None));
}
}
impl<T> Default for Punctuated<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Sealed for Punctuated<T> {}
impl<T: Node> Node for Punctuated<T> {
fn start_position(&self) -> Option<Position> {
self.pairs.first()?.start_position()
}
fn end_position(&self) -> Option<Position> {
self.pairs.last()?.end_position()
}
fn similar(&self, other: &Self) -> bool {
self.into_iter()
.collect::<Vec<_>>()
.similar(&other.into_iter().collect::<Vec<_>>())
}
fn tokens(&self) -> Tokens<'_> {
self.pairs.tokens()
}
}
impl<T: Visit> Visit for Punctuated<T> {
fn visit<V: Visitor>(&self, visitor: &mut V) {
self.pairs.visit(visitor);
}
}
impl<T: VisitMut> VisitMut for Punctuated<T> {
fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
Punctuated {
pairs: self.pairs.visit_mut(visitor),
}
}
}
impl<T> std::iter::Extend<Pair<T>> for Punctuated<T> {
fn extend<I: IntoIterator<Item = Pair<T>>>(&mut self, iter: I) {
self.pairs.extend(iter);
}
}
impl<T> IntoIterator for Punctuated<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
inner: self.pairs.into_iter(),
}
}
}
impl<T> FromIterator<Pair<T>> for Punctuated<T> {
fn from_iter<I: IntoIterator<Item = Pair<T>>>(iter: I) -> Self {
Punctuated {
pairs: iter.into_iter().collect(),
}
}
}
impl<'a, T> IntoIterator for &'a Punctuated<T> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
Iter {
inner: self.pairs.iter(),
}
}
}
impl<'a, T> IntoIterator for &'a mut Punctuated<T> {
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
IterMut {
inner: self.pairs.iter_mut(),
}
}
}
pub struct IntoIter<T> {
inner: std::vec::IntoIter<Pair<T>>,
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
Some(self.inner.next()?.into_value())
}
}
pub struct Iter<'a, T> {
inner: std::slice::Iter<'a, Pair<T>>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
Some(self.inner.next()?.value())
}
}
pub struct IterMut<'a, T> {
inner: std::slice::IterMut<'a, Pair<T>>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
Some(self.inner.next()?.value_mut())
}
}
#[derive(Clone, Debug, DeriveDisplay, PartialEq, Eq)]
#[display(bound(T: Display))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum Pair<T> {
#[display("{_0}")]
End(T),
#[display("{_0}{_1}")]
Punctuated(T, TokenReference),
}
impl<T> Pair<T> {
pub fn new(value: T, punctuation: Option<TokenReference>) -> Self {
match punctuation {
None => Pair::End(value),
Some(punctuation) => Pair::Punctuated(value, punctuation),
}
}
pub fn into_tuple(self) -> (T, Option<TokenReference>) {
match self {
Pair::End(value) => (value, None),
Pair::Punctuated(value, punctuation) => (value, Some(punctuation)),
}
}
pub fn into_value(self) -> T {
self.into_tuple().0
}
pub fn value(&self) -> &T {
match self {
Pair::End(value) => value,
Pair::Punctuated(value, _) => value,
}
}
pub fn value_mut(&mut self) -> &mut T {
match self {
Pair::End(value) => value,
Pair::Punctuated(value, _) => value,
}
}
pub fn punctuation(&self) -> Option<&TokenReference> {
match self {
Pair::End(_) => None,
Pair::Punctuated(_, punctuation) => Some(punctuation),
}
}
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Pair<U> {
match self {
Pair::End(value) => Pair::End(f(value)),
Pair::Punctuated(value, punctuated) => Pair::Punctuated(f(value), punctuated),
}
}
}
impl<T> Sealed for Pair<T> {}
impl<T: Node> Node for Pair<T> {
fn start_position(&self) -> Option<Position> {
self.value().start_position()
}
fn end_position(&self) -> Option<Position> {
self.punctuation()
.and_then(Node::end_position)
.or_else(|| self.value().end_position())
}
fn similar(&self, other: &Self) -> bool {
self.value().similar(other.value())
}
fn tokens(&self) -> Tokens<'_> {
match self {
Pair::Punctuated(node, separator) => {
let mut items = node.tokens().items;
items.push(TokenItem::TokenReference(separator));
Tokens { items }
}
Pair::End(node) => node.tokens(),
}
}
}
impl<T: Visit> Visit for Pair<T> {
fn visit<V: Visitor>(&self, visitor: &mut V) {
match self {
Pair::End(value) => value.visit(visitor),
Pair::Punctuated(value, punctuation) => {
value.visit(visitor);
punctuation.visit(visitor);
}
}
}
}
impl<T: VisitMut> VisitMut for Pair<T> {
fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
match self {
Pair::End(value) => Pair::End(value.visit_mut(visitor)),
Pair::Punctuated(value, punctuation) => {
Pair::Punctuated(value.visit_mut(visitor), punctuation.visit_mut(visitor))
}
}
}
}