macro_loop 0.4.3

A macro for writing repetitive Rust code using loops, conditionals, and bindings
Documentation
use std::mem::take;

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

use super::*;

pub struct NameStream {
    segs: Vec<NameStreamSegment>,
}

enum NameStreamSegment {
    TokenStream(TokenStream),
    Group(NameStreamGroup),
    Fragment(Frag),
}

struct NameStreamGroup {
    span: Span,
    delim: Delimiter,
    stream: Box<NameStream>,
}

impl Parse for NameStream {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let mut output = Self { segs: Vec::new() };

        let mut tokenstream = TokenStream::new();

        while !input.is_empty() {
            if input.peek(Token![@]) {
                let _ = input.parse::<Token![@]>().unwrap();

                output
                    .segs
                    .push(NameStreamSegment::TokenStream(take(&mut tokenstream)));

                let fragment = input.parse::<Frag>()?;

                output.segs.push(NameStreamSegment::Fragment(fragment));
            } else if input.peek(Brace) || input.peek(Paren) || input.peek(Bracket) {
                let group = input.parse::<Group>().unwrap();

                output
                    .segs
                    .push(NameStreamSegment::TokenStream(take(&mut tokenstream)));

                output.segs.push(NameStreamSegment::Group(NameStreamGroup {
                    span: group.span(),
                    delim: group.delimiter(),
                    stream: Box::new(NameStream::parse.parse2(group.stream())?),
                }));
            } else {
                tokenstream.append(input.parse::<TokenTree>()?);
            }
        }

        output
            .segs
            .push(NameStreamSegment::TokenStream(take(&mut tokenstream)));

        Ok(output)
    }
}

impl NameStream {
    pub fn resolve(&self, namespace: &Namespace) -> syn::Result<TokenStream> {
        let mut output = TokenStream::new();

        let mut namespace = namespace.fork();

        for seg in &self.segs {
            match seg {
                NameStreamSegment::TokenStream(stream) => stream.to_tokens(&mut output),

                NameStreamSegment::Group(group) => {
                    let mut token = Group::new(group.delim, group.stream.resolve(&namespace)?);
                    token.set_span(group.span);

                    output.append(token);
                }

                NameStreamSegment::Fragment(frag) => frag.apply(&mut namespace, &mut output)?,
            }

            namespace.flush();
        }

        Ok(output)
    }
}