use std::rc::Rc;
use std::sync::Arc;
use proc_macro2::{Literal, Span, TokenStream};
use quote::ToTokens;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::*;
use crate::__attr_parse_prelude::*;
use crate::ValueSyntax;
impl ParseOption for bool {
fn from_stream(input: ParseStream) -> Result<Self> {
input.parse_bool_attr()
}
}
impl<T: ParseOption, P: Parse> ParseOption for Punctuated<T, P> {
#[inline]
fn from_stream(input: ParseStream) -> Result<Self> {
if input.is_empty() {
return Ok(Self::new());
}
let parse_buf;
let parse_from: ParseStream = match ValueSyntax::from_stream(input) {
Some(ValueSyntax::Eq) => {
input.parse::<Token![=]>()?;
let outer;
parenthesized!(outer in input);
bracketed!(parse_buf in outer);
&parse_buf
}
Some(ValueSyntax::Paren) => {
parenthesized!(parse_buf in input);
&parse_buf
}
None => input,
};
Self::parse_terminated_with(parse_from, ParseOption::from_stream)
}
}
impl<T: FromExpr, P: Parse + Default> FromExpr for Punctuated<T, P> {
#[cfg_attr(not(feature = "full"), inline, allow(unused_variables))]
fn from_expr(expr: Expr) -> Result<Self> {
#[cfg(feature = "full")]
match expr {
Expr::Array(ExprArray { elems, .. }) | Expr::Tuple(ExprTuple { elems, .. }) => {
let it = elems.into_iter().map(T::from_expr);
it.collect::<Result<_>>()
}
expr => Err(Error::new_spanned(
expr,
"Can't parse this type as `Punctuated`",
)),
}
#[cfg(not(feature = "full"))]
Err(Error::new(
Span::call_site(),
"`full` feature required to parse `Punctuated`",
))
}
}
impl<T: ParseOption> ParseOption for Option<T> {
fn from_stream(input: ParseStream) -> Result<Self> {
Ok(Some(T::from_stream(input)?))
}
}
impl<T: FromExpr> FromExpr for Option<T> {
fn from_expr(expr: Expr) -> Result<Self> {
Ok(Some(T::from_expr(expr)?))
}
#[inline]
fn boolean() -> Option<Self> {
Some(T::boolean())
}
}
impl FromExpr for Expr {
#[inline]
fn from_expr(expr: Expr) -> Result<Self> {
Ok(expr)
}
}
impl FromExpr for TokenStream {
#[inline]
fn from_expr(expr: Expr) -> Result<Self> {
Ok(expr.into_token_stream())
}
}
impl FromExpr for Lit {
fn from_expr(expr: Expr) -> Result<Self> {
Ok(ExprLit::from_expr(expr)?.lit)
}
}
impl FromExpr for bool {
fn from_expr(expr: Expr) -> Result<Self> {
Ok(<LitBool>::from_expr(expr)?.value())
}
#[inline]
fn boolean() -> Option<Self> {
Some(true)
}
}
impl FromExpr for LitBool {
fn from_expr(expr: Expr) -> Result<Self> {
let lit = Lit::from_expr(expr)?;
if let Lit::Bool(lit) = lit {
Ok(lit)
} else {
Err(Error::new_spanned(lit, "Incompatible literal"))
}
}
fn boolean() -> Option<Self> {
Some(Self::new(true, Span::call_site()))
}
}
impl FromExpr for Path {
fn from_expr(expr: Expr) -> Result<Self> {
Ok(<ExprPath>::from_expr(expr)?.path)
}
}
/// For use within the macro. API subject to change at any time.
macro_rules! parse_impl {
(lit $([$base: ty, $lit: ty]),+) => {
$(
impl ParseOption for $base {
fn from_stream(input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
Ok(<$lit as ParseOption>::from_stream(input)?.value())
}
}
from_expr!(lit_direct_num_ok $base, value => $lit);
)+
};
(new [$($ty: ty),+]) => {
$(
impl<T: ParseOption> ParseOption for $ty {
fn from_stream(input: ParseStream) -> Result<Self> {
T::from_stream(input).map(<$ty>::new)
}
}
impl<T: FromExpr> FromExpr for $ty {
fn from_expr(expr: Expr) -> Result<Self> {
T::from_expr(expr).map(<$ty>::new)
}
}
)+
};
(parse [$($ty: ty),+]) => {
$(
impl ParseOption for $ty {
parse_impl!(parse);
}
)+
};
(parse if $feature: literal [$($ty: ty),+]) => {
$(
#[cfg(feature = $feature)]
impl ParseOption for $ty {
parse_impl!(parse);
}
)+
};
(parse) => {
fn from_stream(input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
ValueSyntax::from_stream(input).and_parse(input)
}
};
(lit_num [$lit: ty => $($base: ty),+]) => {
$(
impl ParseOption for $base {
fn from_stream(input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
<$lit as ParseOption>::from_stream(input)?.base10_parse()
}
}
from_expr!(lit_direct_num $base, base10_parse => $lit);
)+
};
}
macro_rules! from_expr {
(direct $([$ident: ident => $target: ident]),+) => {
$(
impl FromExpr for $target {
fn from_expr(expr: Expr) -> Result<Self> {
if let Expr::$ident(expr) = expr {
Ok(expr)
} else {
Err(Error::new_spanned(expr, "Incompatible expression"))
}
}
}
)+
};
(lit $([$ident: ident => $target: ident]),+) => {
$(
impl FromExpr for $target {
fn from_expr(expr: Expr) -> Result<Self> {
let lit = Lit::from_expr(expr)?;
if let Lit::$ident(lit) = lit {
Ok(lit)
} else {
Err(Error::new_spanned(lit, "Incompatible literal"))
}
}
}
)+
};
(lit_direct_num $base: ty, $fn: ident => $lit: ty) => {
impl FromExpr for $base {
fn from_expr(expr: Expr) -> ::syn::Result<Self> {
<$lit>::from_expr(expr)?.$fn()
}
}
};
(lit_direct_num_ok $base: ty, $fn: ident => $lit: ty) => {
impl FromExpr for $base {
fn from_expr(expr: Expr) -> ::syn::Result<Self> {
Ok(<$lit>::from_expr(expr)?.$fn())
}
}
};
(tokenise [$($ident: ident),+]) => {
$(
impl FromExpr for $ident {
fn from_expr(expr: Expr) -> Result<Self> {
parse2(expr.into_token_stream())
}
}
)+
};
}
from_expr!(tokenise [Lifetime, LifetimeParam, BoundLifetimes, TypeParamBound, TraitBound, TypeParam, GenericParam, WherePredicate]);
from_expr!(tokenise [Ident, Type, TypeArray, TypeFnPtr, TypeGroup, TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple, AngleBracketedGenericArguments, ConstParam, Abi, NamedArg, Meta, MetaList, MetaNameValue, Visibility]);
from_expr!(lit [Str => LitStr], [ByteStr => LitByteStr], [Byte => LitByte], [Char => LitChar], [Int => LitInt], [Float => LitFloat], [Verbatim => Literal]);
from_expr!(direct [Array => ExprArray], [Assign => ExprAssign], [Async => ExprAsync], [Await => ExprAwait], [Binary => ExprBinary], [Block => ExprBlock], [Break => ExprBreak], [Call => ExprCall], [Cast => ExprCast], [Closure => ExprClosure], [Const => ExprConst], [Continue => ExprContinue], [Field => ExprField], [ForLoop => ExprForLoop], [Group => ExprGroup], [If => ExprIf], [Infer => ExprInfer], [Index => ExprIndex], [Let => ExprLet], [Lit => ExprLit], [Loop => ExprLoop], [Macro => ExprMacro], [Match => ExprMatch], [MethodCall => ExprMethodCall], [Paren => ExprParen], [Path => ExprPath], [Range => ExprRange], [RawAddr => ExprRawAddr], [Reference => ExprReference], [Repeat => ExprRepeat], [Return => ExprReturn], [Struct => ExprStruct], [Try => ExprTry], [TryBlock => ExprTryBlock], [Tuple => ExprTuple], [Unary => ExprUnary], [Unsafe => ExprUnsafe], [While => ExprWhile], [Yield => ExprYield]);
parse_impl!(lit [String, LitStr], [char, LitChar]);
parse_impl!(lit_num [LitFloat => f32, f64]);
parse_impl!(lit_num [LitInt => u8, i8, u16, i16, u32, i32, u64, i64, usize, isize]);
parse_impl!(parse [Expr, AngleBracketedGenericArguments, ConstParam, Abi, NamedArg, Ident, Path, Meta, MetaList, MetaNameValue, Visibility]);
parse_impl!(parse [Lifetime, LifetimeParam, BoundLifetimes, TypeParamBound, TraitBound, TypeParam, GenericParam, WherePredicate]);
parse_impl!(parse [Lit, LitBool, LitByteStr, LitByte, LitStr, LitChar, LitInt, LitFloat, Literal]);
parse_impl!(parse [Type, TypeArray, TypeFnPtr, TypeGroup, TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple]);
parse_impl!(new [Box<T>, Rc<T>, Arc<T>]);
parse_impl!(parse if "full" [ExprArray, ExprAssign, ExprAsync, ExprAwait, ExprBinary, ExprBlock, ExprBreak, ExprCall, ExprCast, ExprClosure, ExprConst, ExprContinue, ExprField, ExprForLoop, ExprIf, ExprIndex, ExprInfer, ExprLet, ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprRawAddr, ExprReference, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprUnary, ExprUnsafe, ExprWhile, ExprYield]);