#![feature(default_free_fn)]
#![feature(extend_one)]
#![feature(let_chains)]
#![feature(assert_matches)]
extern crate core;
extern crate proc_macro;
use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, TokenStream, TokenTree};
use std::default::default;
fn is_skip(iter: &mut std::iter::Peekable<impl Iterator<Item = TokenTree>>) -> bool {
let unwrap_group = |tt: &TokenTree| match tt {
TokenTree::Group(group) => Some((group.delimiter(), group.stream())),
_ => None,
};
const TERLY: &str = "Does not terminate earlier than expected";
if let Some((delimiter, stream)) = unwrap_group(iter.peek().expect(TERLY)) && delimiter == Delimiter::Bracket{
iter.next();
stream.to_string() == "skip_auto_unwrap"
} else {
false
}
}
fn unwrap_inner(input: TokenStream) -> TokenStream {
let mut out: TokenStream = default();
let mut iter = input.into_iter().peekable();
let mut ignore = false;
while let Some(token) = iter.next() {
match token {
TokenTree::Group(ref group) => {
if ignore {
if group.delimiter() == Delimiter::Brace {
ignore = false;
}
out.extend_one(token);
} else {
out.extend_one(TokenTree::Group(Group::new(
group.delimiter(),
unwrap_inner(group.stream()),
)))
}
}
TokenTree::Punct(ref punct) => match punct.as_char() {
'?' if !ignore => out.extend([
TokenTree::Punct(Punct::new('.', Spacing::Alone)),
TokenTree::Ident(Ident::new("unwrap", punct.span())),
TokenTree::Group(Group::new(Delimiter::Parenthesis, default())),
]),
'#' => {
if is_skip(&mut iter) {
ignore = true;
} else {
out.extend_one(token);
}
}
_ => out.extend_one(token),
},
other => out.extend_one(other),
}
}
out
}
#[proc_macro_attribute]
pub fn auto_unwrap(_args: TokenStream, input: TokenStream) -> TokenStream {
let mut args = input.into_iter().collect::<Vec<_>>();
let mut out = TokenStream::new();
out.extend(args.drain(..args.len() - 1));
assert!(args.len() == 1);
let token = args.into_iter().next().unwrap();
match token {
TokenTree::Group(group) if group.delimiter() == Delimiter::Brace => {
out.extend_one(TokenTree::Group(Group::new(
Delimiter::Brace,
unwrap_inner(group.stream()),
)));
}
_ => panic!("No/Invalid function body(???)"),
}
out
}