use proc_macro::TokenStream;
#[doc(hidden)]
use quote::quote;
#[doc(hidden)]
use syn::{
parse::Parse, parse::ParseStream, parse_macro_input, Expr, Ident, LitInt, LitStr,
Result, Token,
};
struct DynamicTupleParams(Expr, LitInt);
struct SmartSplitParams(Ident, LitStr, LitInt);
impl Parse for DynamicTupleParams {
fn parse(input: ParseStream) -> Result<Self> {
let value = input.parse()?;
input.parse::<Token![,]>()?;
let count = input.parse()?;
Ok(DynamicTupleParams(value, count))
}
}
impl Parse for SmartSplitParams {
fn parse(input: ParseStream) -> Result<Self> {
let text = input.parse()?;
input.parse::<Token![,]>()?;
let sep = input.parse()?;
input.parse::<Token![,]>()?;
let count = input.parse()?;
Ok(SmartSplitParams(text, sep, count))
}
}
#[proc_macro]
pub fn dynamic_tuple(input: TokenStream) -> TokenStream {
let DynamicTupleParams(value, count) = parse_macro_input!(input as DynamicTupleParams);
let value_ts = quote! { #value }.to_string();
let count = count
.base10_parse::<usize>()
.expect("Invalid count of arguments");
let tuple_elements = std::iter::repeat(value_ts)
.take(count)
.collect::<Vec<_>>()
.join(", ");
let tuple_string = format!("({})", tuple_elements);
tuple_string.parse().unwrap()
}
#[proc_macro]
pub fn unpack_split(input: TokenStream) -> TokenStream {
let SmartSplitParams(text, sep, count) = parse_macro_input!(input as SmartSplitParams);
let len = count.base10_parse::<usize>().unwrap();
let indices = 0..len;
let tuple_elems = indices.map(|_| quote! {tuple_elements.next().unwrap()});
let output = quote! {
{
let mut tuple_elements = #text.split(#sep);
(#( #tuple_elems, )*)
}
};
output.into()
}
struct LetStatement {
vars: Vec<proc_macro2::TokenStream>,
astrix: usize,
expr: Ident,
}
impl Parse for LetStatement {
fn parse(input: ParseStream) -> Result<Self> {
let mut vars = Vec::new();
let mut count: usize = 0;
let mut astrix: usize = 0;
loop {
if input.peek(Token![*]) {
input.parse::<Token![*]>()?; astrix = count;
}
let is_mut = input.peek(Token![mut]);
if is_mut {
input.parse::<Token![mut]>()?; }
let var: Ident = input.parse()?;
if is_mut {
vars.push(quote!(mut #var));
} else {
vars.push(quote!(#var));
}
if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
} else {
break;
}
count += 1;
}
input.parse::<Token![=]>()?;
let expr: Ident = input.parse()?;
Ok(LetStatement { vars, astrix, expr })
}
}
#[proc_macro]
pub fn let_unpack(input: TokenStream) -> TokenStream {
let LetStatement { vars, astrix, expr} = parse_macro_input!(input as LetStatement);
let mut values = Vec::new();
let arguments_number = vars.len();
for index in 0..arguments_number {
if index < astrix {
values.push(quote! {#expr[#index]});
} else if index == astrix {
values.push(
quote! {&#expr[#index..#expr.len() - #arguments_number + #index + 1].to_vec()}
);
} else {
values.push(quote! {#expr[#expr.len() - #arguments_number + #index]});
}
}
TokenStream::from(quote! {
#( let #vars = #values; )*;
drop(#expr);
})
}