visa-rs-proc 0.7.0

procedural macros used in visa-rs
Documentation
use proc_macro2::{Delimiter, TokenStream as TokenStream2, TokenTree};
use quote::ToTokens;
use syn::{
    parse::{Parse, ParseStream},
    Path, Result, Token,
};

use crate::{Body, OneLayer};

pub struct Macros {
    inner: Vec<NestedMacros>,
}

impl Parse for Macros {
    fn parse(input: ParseStream) -> Result<Self> {
        let mut inner = Vec::new();
        while !input.is_empty() {
            inner.push(input.parse()?);
        }
        Ok(Self { inner })
    }
}

impl ToTokens for Macros {
    fn to_tokens(&self, tokens: &mut TokenStream2) {
        self.inner.iter().for_each(|x| x.to_tokens(tokens))
    }
}

pub struct NestedMacros {
    pub(crate) macs: Vec<Path>,
    pub(crate) exc: Token![!],
    pub(crate) body: Body,
}

impl Parse for NestedMacros {
    fn parse(input: ParseStream) -> Result<Self> {
        let mac: Path = input.call(Path::parse_mod_style)?;
        let exc = input.parse::<Token![!]>()?;
        let mut body: Body = input.parse()?;
        let mut macs = vec![mac];
        while let Ok(s) = syn::parse2::<OneLayer>(body.content.clone()) {
            body = s.body;
            macs.push(s.mac);
        }
        Ok(Self { macs, exc, body })
    }
}

impl ToTokens for NestedMacros {
    fn to_tokens(&self, tokens: &mut TokenStream2) {
        let Self { macs, exc, body } = self;
        let body = body
            .content
            .clone()
            .into_iter()
            .map(subst_token_tree)
            .collect();
        let mut ret = body;
        for mac in macs.iter().rev() {
            let mut m = mac.to_token_stream();
            exc.to_tokens(&mut m);
            proc_macro2::Group::new(Delimiter::Brace, ret).to_tokens(&mut m);
            ret = m;
        }
        ret.to_tokens(tokens)
    }
}

fn subst_token_tree(t: TokenTree) -> TokenStream2 {
    let mut stream = TokenStream2::new();
    if let TokenTree::Ident(id) = t {
        crate::subst_ident(id).to_tokens(&mut stream);
        return stream;
    } else if let TokenTree::Group(ref g) = t {
        let content = g.stream();
        let content: TokenStream2 = content.into_iter().map(subst_token_tree).collect();
        proc_macro2::Group::new(g.delimiter(), content).to_tokens(&mut stream);
        return stream;
    }
    t.to_tokens(&mut stream);
    stream
}