repetitive 0.2.0

Macro for generating repetitive code
Documentation
use std::mem::take;

use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
use quote::{ToTokens, TokenStreamExt};
use syn::{
    Token,
    parse::ParseStream,
    token::{Brace, Bracket, Paren},
};

use super::*;

#[derive(Debug, Clone, Default)]
pub struct Tokens {
    segments: Vec<TokensSegment>,
}

#[derive(Debug, Clone)]
enum TokensSegment {
    TokenStream(TokenStream),
    Group(TokensGroup),
    Fragment(Fragment),
}

#[derive(Debug, Clone)]
struct TokensGroup {
    delimiter: Delimiter,
    tokens: Tokens,
}

impl ContextParse for Tokens {
    fn ctx_parse(input: ParseStream, ctx: &mut Context) -> Result<Self, Error>
    where
        Self: Sized,
    {
        let mut segments = Vec::new();

        while !input.is_empty() {
            let segment = TokensSegment::ctx_parse(input, ctx)?;
            segments.push(segment);
        }

        Ok(Self { segments })
    }
}
impl ContextParse for TokensSegment {
    fn ctx_parse(input: ParseStream, ctx: &mut Context) -> Result<Self, Error>
    where
        Self: Sized,
    {
        if let Some(group) = Option::<Group>::ctx_parse(input, ctx)? {
            let tokens = Tokens::ctx_parse.ctx_parse2(group.stream(), ctx)?;

            Ok(TokensSegment::Group(TokensGroup {
                delimiter: group.delimiter(),
                tokens,
            }))
        } else if input.peek(Token![@]) {
            let fragment = Fragment::ctx_parse(input, ctx)?;
            Ok(TokensSegment::Fragment(fragment))
        } else {
            let mut stream = TokenStream::new();

            while !input.is_empty()
                && !input.peek(Token![@])
                && !input.peek(Paren)
                && !input.peek(Brace)
                && !input.peek(Bracket)
            {
                stream.append(TokenTree::ctx_parse(input, ctx)?);
            }

            Ok(TokensSegment::TokenStream(stream))
        }
    }
}

impl Optimize for Tokens {
    fn optimize(&mut self, ctx: &mut Context) {
        let mut new_self = Self::default();

        for mut segment in self.segments.drain(..) {
            segment.optimize(ctx);

            if let Some(TokensSegment::TokenStream(last_segment)) = new_self.segments.last_mut()
                && let TokensSegment::TokenStream(segment) = segment
            {
                segment.to_tokens(last_segment);
            } else {
                new_self.segments.push(segment);
            }
        }

        *self = new_self;
    }
}
impl Optimize for TokensSegment {
    fn optimize(&mut self, ctx: &mut Context) {
        match self {
            TokensSegment::TokenStream(_) => {}

            TokensSegment::Group(group) => {
                group.tokens.optimize(ctx);

                if let [TokensSegment::TokenStream(_)] = group.tokens.segments.as_slice() {
                    let Some(TokensSegment::TokenStream(stream)) =
                        take(&mut group.tokens.segments).into_iter().nth(0)
                    else {
                        unreachable!("single token stream segment group");
                    };

                    let group = Group::new(group.delimiter, stream);
                    *self = TokensSegment::TokenStream(group.to_token_stream());
                }
            }

            TokensSegment::Fragment(frag) => {
                frag.optimize(ctx);
            }
        }
    }
}

impl Expand for Tokens {
    fn expand(&self, output: &mut TokenStream, ctx: &mut Context, namespace: &Namespace) {
        let mut namespace_fork = namespace.fork();

        for segment in &self.segments {
            match segment {
                TokensSegment::TokenStream(seg) => seg.expand(output, ctx, &namespace_fork),
                TokensSegment::Group(seg) => seg.expand(output, ctx, &namespace_fork),
                TokensSegment::Fragment(seg) => seg.expand_into(output, ctx, &mut namespace_fork),
            }
        }
    }
}
impl Expand for TokensGroup {
    fn expand(&self, output: &mut TokenStream, ctx: &mut Context, namespace: &Namespace) {
        let mut group_tokens = TokenStream::new();
        self.tokens.expand(&mut group_tokens, ctx, namespace);

        let group = Group::new(self.delimiter, group_tokens);
        group.to_tokens(output);
    }
}