use std::slice;
use crate::{SourceCodeSpan, SourceSpan, lex::Token};
#[derive(Debug, Clone, PartialEq)]
pub struct Punctuated<'de, T> {
pub(crate) inner: Vec<(T, Option<Token<'de>>)>,
}
impl<'de, T> Punctuated<'de, T> {
pub fn new() -> Self {
Punctuated { inner: Vec::new() }
}
pub fn first(&self) -> Option<&T> {
self.inner.first().map(|(v, _)| v)
}
pub fn push_value(&mut self, value: T) {
self.inner.push((value, None));
}
pub fn push_pair(&mut self, value: T, punct: Token<'de>) {
self.inner.push((value, Some(punct)));
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.inner.iter().map(|(v, _)| v)
}
pub fn pairs(&self) -> slice::Iter<'_, (T, Option<Token<'de>>)> {
self.inner.iter()
}
pub fn trailing_punct(&self) -> bool {
self.inner.last().is_some_and(|(_, p)| p.is_some())
}
pub fn into_values(self) -> Vec<T> {
self.inner.into_iter().map(|(v, _)| v).collect()
}
}
impl<'de, T: SourceCodeSpan<'de>> SourceCodeSpan<'de> for Punctuated<'de, T> {
fn span(&self) -> Option<SourceSpan<'de>> {
let mut span: Option<SourceSpan<'de>> = None;
for punctuate in &self.inner {
let punctuate_span = punctuate.0.span().or(punctuate.1.map(|t| t.src_span()));
if let Some(span) = span {
if let Some(inner_span) = punctuate_span {
span.extend(inner_span);
}
} else {
span = punctuate_span;
}
}
span
}
}
impl<'de, T> Default for Punctuated<'de, T> {
fn default() -> Self {
Self::new()
}
}