#![doc = include_str!("../README.md")]
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, ToTokens};
use syn::{
braced,
buffer::Cursor,
parse::{ParseBuffer, ParseStream, Parser},
punctuated::Punctuated,
Index, LitStr, RangeLimits, Result, Token,
};
use crate::{custom_ident::CustomIdMap, format::handle_formatted};
mod custom_ident;
mod format;
#[proc_macro]
pub fn impl_variadics(tokens: TokenStream) -> TokenStream {
let parser =
|input: ParseStream| Punctuated::<_, Token![;]>::parse_terminated_with(input, impl_one);
let ts = match parser.parse(tokens) {
Ok(i) => i.into_iter(),
Err(e) => return e.into_compile_error().into(),
};
quote! {
#(#ts)*
}
.into()
}
fn impl_one(input: ParseStream) -> Result<TokenStream2> {
let start = if input.peek(Token![..]) || input.peek(Token![..=]) {
0
} else {
input.parse::<Index>()?.index
};
let end = {
let range_limits = input.parse::<RangeLimits>()?;
let end = input.parse::<Index>()?.index;
match range_limits {
RangeLimits::Closed(_) => end + 1,
RangeLimits::HalfOpen(_) => end,
}
};
let mut custom_ids = CustomIdMap::new();
while input.peek(LitStr) {
custom_ids.parse(input.parse::<LitStr>()?)?;
}
input.parse::<Token![=>]>()?;
let content;
braced!(content in input);
let mut output = TokenStream2::new();
for len in start..end {
handle_formatted(&content.fork(), len, &custom_ids)?.to_tokens(&mut output);
}
discard_parse_buffer(content);
Ok(output)
}
fn discard_parse_buffer(buffer: ParseBuffer) {
let _ = buffer.step(|_| Ok(((), Cursor::empty())));
}