use std::{borrow::Borrow, str::FromStr};
use proc_macro2::{TokenTree, Ident, Span, Group, TokenStream, Delimiter};
use crate::{FromMacro, Error, StreamExtract, EndOfStream, CommaExtractor, PunctOf, abort, All, Either, EitherStream};
#[derive(Debug)]
pub struct Spanned<T: FromMacro>(pub Span, pub T);
impl<T> Default for Spanned<T> where T: FromMacro + Default{
fn default() -> Self {
Spanned(Span::call_site(), T::default())
}
}
impl<T> FromMacro for Spanned<T> where T: FromMacro{
fn from_one(tt: TokenTree) -> Result<Self, Error> {
Ok(Self(tt.span(), T::from_one(tt)?))
}
fn from_many(tokens: proc_macro2::TokenStream) -> Result<Self, Error> {
Ok(Self(Span::call_site(), T::from_many(tokens)?))
}
}
pub struct ParenthesisizedGroup(pub Group);
pub struct BracketedGroup(pub Group);
pub struct CurlyBracedGroup(pub Group);
macro_rules! impl_groups {
($($name: ident, $delim: ident, $lit: literal);*) => {
$(impl FromMacro for $name {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
match tt {
TokenTree::Group(group) => {
if group.delimiter() == proc_macro2::Delimiter::$delim {
Ok(Self(group))
} else {
abort!(group.span(), ExpectTokenTree($lit, TokenTree::Group(group)))
}
},
tt => abort!(tt.span(), ExpectTokenTree("TokenTree::Group", tt))
}
}
fn peek(tt: &TokenTree) -> bool {
match tt {
TokenTree::Group(group) if group.delimiter() ==proc_macro2::Delimiter::$delim => {
true
},
_ => false,
}
}
})*
};
}
impl_groups!(
ParenthesisizedGroup, Parenthesis, "()";
BracketedGroup, Bracket, "[]";
CurlyBracedGroup, Brace, "{}"
);
pub struct Parenthesisized<T>(pub T);
pub struct Bracketed<T>(pub T);
pub struct CurlyBraced<T>(pub T);
macro_rules! impl_group_extract {
($($name: ident, $delim: ident, $lit: literal);*) => {
$(impl<T: FromMacro> FromMacro for $name<T> {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
match tt {
TokenTree::Group(group) => {
if group.delimiter() == proc_macro2::Delimiter::$delim {
let All(item) = group.stream().into_iter().extract()?;
Ok(Self(item))
} else {
abort!(group.span(), ExpectTokenTree($lit, TokenTree::Group(group)))
}
},
tt => abort!(tt.span(), ExpectTokenTree("TokenTree::Group", tt))
}
}
fn peek(tt: &TokenTree) -> bool {
match tt {
TokenTree::Group(group) if group.delimiter() ==proc_macro2::Delimiter::$delim => {
true
},
_ => false,
}
}
})*
};
}
impl_group_extract!(
Parenthesisized, Parenthesis, "(..)";
Bracketed, Bracket, "[..]";
CurlyBraced, Brace, "{..}"
);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NotParenthesisized<T>(pub T);
pub struct NotBracketed<T>(pub T);
pub struct NotCurlyBraced<T>(pub T);
macro_rules! impl_not_group_extract {
($($name: ident, $delim: ident, $lit: literal);*) => {
$(impl<T: FromMacro> FromMacro for $name<T> {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
match tt {
TokenTree::Group(group)
if group.delimiter() == proc_macro2::Delimiter::$delim => {
abort!(group.span(), ExpectTokenTree($lit, TokenTree::Group(group)))
},
tt => Ok(Self(T::from_one(tt)?))
}
}
fn peek(tt: &TokenTree) -> bool {
match tt {
TokenTree::Group(group) if group.delimiter() == proc_macro2::Delimiter::$delim => {
false
},
_ => true,
}
}
})*
};
}
impl_not_group_extract!(
NotParenthesisized, Parenthesis, "anything but (..)";
NotBracketed, Bracket, "anything but [..]";
NotCurlyBraced, Brace, "anything but {..}"
);
#[derive(Debug, Default, Hash, PartialEq, Eq)]
pub struct IdentString(pub String);
impl From<Ident> for IdentString {
fn from(ident: Ident) -> Self {
Self(ident.to_string())
}
}
impl Borrow<str> for IdentString {
fn borrow(&self) -> &str {
self.0.as_str()
}
}
impl FromMacro for IdentString {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
match tt {
TokenTree::Ident(ident) => {
Ok(Self(ident.to_string()))
},
tt => abort!(tt.span(), ExpectTokenTree("TokenTree::Ident", tt))
}
}
}
#[derive(Debug, Default, Hash, PartialEq, Eq)]
pub struct StringTokens<T: FromMacro>(pub T);
impl<T: FromMacro> FromMacro for StringTokens<T> {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
let span = tt.span();
let s = String::from_one(tt)?;
let stream = match TokenStream::from_str(&s) {
Ok(ts) => ts,
Err(e) => abort!(span, LexError(e))
};
let All(result) = stream.into_iter().extract()?;
Ok(Self(result))
}
}
#[derive(Debug, Default, Hash, PartialEq, Eq)]
pub struct Stringify(pub String);
impl FromMacro for Stringify {
const PREFER_MANY: bool = true;
fn from_one(tt: TokenTree) -> Result<Self, Error> {
Ok(Self(tt.to_string()))
}
fn from_many(tokens: TokenStream) -> Result<Self, Error> {
Ok(Self(tokens.to_string()))
}
}
pub(crate) struct NotPunct<const P: char>(pub Option<proc_macro2::TokenTree>);
impl<const P: char> FromMacro for NotPunct<P> {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
match &tt {
TokenTree::Punct(p) if p.as_char() == P => {
Ok(Self(None))
}
_ => Ok(Self(Some(tt)))
}
}
}
pub struct TupleStructExtractor(pub Ident, pub Group);
impl FromMacro for TupleStructExtractor {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
abort!(tt.span(), ExpectMany)
}
fn from_many(tokens: proc_macro2::TokenStream) -> Result<Self, Error> {
let mut iter = tokens.into_iter();
let ident = iter.extract()?;
let ParenthesisizedGroup(group) = iter.extract()?;
iter.extract::<EndOfStream>()?;
Ok(TupleStructExtractor(ident, group))
}
}
pub struct NamedStructExtractor(pub Ident, pub Group);
impl FromMacro for NamedStructExtractor {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
abort!(tt.span(), ExpectMany)
}
fn from_many(tokens: proc_macro2::TokenStream) -> Result<Self, Error> {
let mut iter = tokens.into_iter();
let ident = iter.extract()?;
let CurlyBracedGroup(group) = iter.extract()?;
iter.extract::<EndOfStream>()?;
Ok(NamedStructExtractor(ident, group))
}
}
pub struct StructExtractor(pub Ident, pub Group);
impl FromMacro for StructExtractor {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
abort!(tt.span(), ExpectMany)
}
fn from_many(tokens: proc_macro2::TokenStream) -> Result<Self, Error> {
let mut iter = tokens.into_iter();
let ident = iter.extract()?;
let group = match iter.extract()? {
Either::A(ParenthesisizedGroup(g)) => g,
Either::B(CurlyBracedGroup(g)) => g,
};
iter.extract::<EndOfStream>()?;
Ok(StructExtractor(ident, group))
}
}
#[derive(Debug, Default)]
pub struct Field<A: FromMacro, B: FromMacro>(pub A, pub B);
impl<A: FromMacro, B: FromMacro> FromMacro for Field<A, B> {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
abort!(tt.span(), ExpectMany)
}
fn from_many(tokens: TokenStream) -> Result<Self, Error> {
let mut iter = tokens.into_iter();
let name = iter.extract()?;
iter.extract::<PunctOf<':'>>()?;
let CommaExtractor(rem) = iter.extract()?;
Ok(Self(name, rem))
}
}
pub struct Meta(pub Ident, pub EitherStream);
impl FromMacro for Meta {
fn from_one(tt: TokenTree) -> Result<Self, Error> {
let ident = Ident::from_one(tt)?;
Ok(Self(
ident,
EitherStream::One(TokenTree::Ident(Ident::new("true", Span::call_site())))
))
}
fn from_many(tokens: TokenStream) -> Result<Self, Error> {
let mut iter = tokens.into_iter();
let name: Ident = iter.extract()?;
match iter.next() {
Some(TokenTree::Punct(p)) if p.as_char() == '=' => {
let tt = iter.extract()?;
let EndOfStream = iter.extract()?;
Ok(Self(name, EitherStream::One(tt)))
},
Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => {
Ok(Self(name, EitherStream::Many(g.stream())))
}
None => Ok(Self(
name,
EitherStream::One(TokenTree::Ident(Ident::new("true", Span::call_site())))
)),
Some(tt) => {
abort!(tt.span(), ExpectValidMeta)
}
}
}
}