use std::iter::{Chain, Once, once};
use std::{slice, vec};
use crate::{Lex, Parse, ParseStream, Spanned, Token, TokenParseError, TokenStream};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)]
pub struct PunctPair<L, P = Token![,], R = L> {
pub left: L,
pub punctuation: P,
pub right: R,
}
impl<L, P, R> PunctPair<L, P, R> {
pub fn new(left: L, punctuation: P, right: R) -> Self {
Self {
left,
punctuation,
right,
}
}
pub fn into_parts(self) -> (L, P, R) {
(self.left, self.punctuation, self.right)
}
}
impl<L: Parse, P: Parse, R: Parse> Parse for PunctPair<L, P, R> {
fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
Ok(Self::new(
L::parse(input)?,
P::parse(input)?,
R::parse(input)?,
))
}
}
impl<L: Lex, P: Lex, R: Lex> Lex for PunctPair<L, P, R> {
fn to_tokens(&self, output: &mut TokenStream) {
self.left.to_tokens(output);
self.punctuation.to_tokens(output);
self.right.to_tokens(output);
}
}
#[macro_export]
macro_rules! punc {
(value $value:expr) => {
$crate::Punctuated::from_single($value)
};
(pairs $first:expr; $($punctuation:expr => $next:expr),+ $(,)?) => {{
let mut values = $crate::Punctuated::from_single($first);
$(values.push($punctuation, $next);)+
values
}};
($value:ty) => {
$crate::Punctuated<$value>
};
}
#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
pub struct Punctuated<S, P = Token![,]> {
first: S,
rest: Vec<(P, S)>,
}
impl<S, P> Punctuated<S, P> {
pub fn new(first: S, rest: Vec<(P, S)>) -> Self {
Self { first, rest }
}
pub fn from_single(value: S) -> Self {
Self::new(value, Vec::new())
}
pub fn from_pair(pair: PunctPair<S, P>) -> Self {
let (left, punctuation, right) = pair.into_parts();
Self::new(left, vec![(punctuation, right)])
}
pub fn first(&self) -> &S {
&self.first
}
pub fn first_mut(&mut self) -> &mut S {
&mut self.first
}
pub fn rest(&self) -> &[(P, S)] {
&self.rest
}
pub fn rest_mut(&mut self) -> &mut [(P, S)] {
&mut self.rest
}
pub fn into_parts(self) -> (S, Vec<(P, S)>) {
(self.first, self.rest)
}
pub fn len(&self) -> usize {
self.rest.len() + 1
}
pub const fn is_empty(&self) -> bool {
false
}
pub fn token_len(&self) -> usize {
self.rest.len() * 2 + 1
}
pub fn iter(&self) -> Values<'_, S, P> {
once(&self.first).chain(
self.rest
.iter()
.map(rest_value_ref::<S, P> as fn(&(P, S)) -> &S),
)
}
pub fn iter_mut(&mut self) -> ValuesMut<'_, S, P> {
once(&mut self.first).chain(
self.rest
.iter_mut()
.map(rest_value_mut::<S, P> as fn(&mut (P, S)) -> &mut S),
)
}
pub fn push(&mut self, punctuation: P, value: S) {
self.rest.push((punctuation, value));
}
}
impl<S: Lex, P: Lex> Lex for Punctuated<S, P> {
fn to_tokens(&self, output: &mut TokenStream) {
self.first.to_tokens(output);
for (punctuation, value) in &self.rest {
punctuation.to_tokens(output);
value.to_tokens(output);
}
}
}
impl<S, P> Parse for Punctuated<S, P>
where
S: Parse,
P: Parse + Token,
{
fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
let first = S::parse(input)?;
let mut values = Self::from_single(first);
while input.peek().is_some_and(P::matches_token_tree) {
let punctuation = P::parse(input)?;
values.push(punctuation, S::parse(input)?);
}
Ok(values)
}
}
pub type Values<'a, S, P> =
Chain<Once<&'a S>, std::iter::Map<slice::Iter<'a, (P, S)>, fn(&(P, S)) -> &S>>;
pub type ValuesMut<'a, S, P> =
Chain<Once<&'a mut S>, std::iter::Map<slice::IterMut<'a, (P, S)>, fn(&mut (P, S)) -> &mut S>>;
pub type IntoValues<S, P> = Chain<Once<S>, std::iter::Map<vec::IntoIter<(P, S)>, fn((P, S)) -> S>>;
impl<S, P> IntoIterator for Punctuated<S, P> {
type Item = S;
type IntoIter = IntoValues<S, P>;
fn into_iter(self) -> Self::IntoIter {
once(self.first).chain(
self.rest
.into_iter()
.map(rest_value::<S, P> as fn((P, S)) -> S),
)
}
}
impl<'a, S, P> IntoIterator for &'a Punctuated<S, P> {
type Item = &'a S;
type IntoIter = Values<'a, S, P>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, S, P> IntoIterator for &'a mut Punctuated<S, P> {
type Item = &'a mut S;
type IntoIter = ValuesMut<'a, S, P>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
fn rest_value<S, P>((_, value): (P, S)) -> S {
value
}
fn rest_value_ref<S, P>((_, value): &(P, S)) -> &S {
value
}
fn rest_value_mut<S, P>((_, value): &mut (P, S)) -> &mut S {
value
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Span;
#[test]
fn a_sequence_is_nonempty_and_retains_separator_spans() {
let comma_span = Span::new(1, 2);
let values = Punctuated::new(
Token),
vec, Token))],
);
assert_eq!(values.len(), 2);
assert_eq!(values.token_len(), 3);
assert_eq!(values.rest()[0].0.span().bounds(), comma_span.bounds());
assert_eq!(values.to_m2(), "+,+");
}
}