#![deny(missing_docs)]
#![deny(missing_copy_implementations)]
#![deny(missing_debug_implementations)]
use std::{marker::PhantomData, ops::Deref};
use proc_macro2::Span;
use syn::{
parse::{Lookahead1, Parse, ParseStream},
spanned::Spanned,
token::{Paren, Token},
};
#[doc(hidden)]
pub mod private {
pub use std::{
concat, default::Default, format, mem::discriminant, option::Option, result::Result,
string::String, stringify, vec::Vec,
};
pub use bool;
pub use proc_macro2::Span;
pub use syn::{
custom_keyword, parenthesized,
parse::{Lookahead1, Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
token::{Comma, Eq, Paren},
Attribute, Error,
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! easy_void_tokens {
($($t:tt)*) => {};
}
#[doc(hidden)]
#[macro_export]
macro_rules! easy_replace_tokens {
($with:tt, $($t:tt)*) => {
$with
};
}
pub trait EasyToken: EasyPeek + Parse + Spanned {
fn display() -> &'static str;
}
#[macro_export]
macro_rules! easy_token {
($name:ident) => {
$crate::private::custom_keyword!($name);
impl $crate::EasyToken for $name {
#[inline]
fn display() -> &'static str {
$crate::private::concat!("`", $crate::private::stringify!($name), "`")
}
}
};
}
pub trait EasyPeek: Parse {
fn peek(lookahead1: &Lookahead1) -> bool;
fn peek_stream(stream: ParseStream) -> bool;
}
impl<T> EasyPeek for T
where
T: Token + Parse,
{
#[inline]
fn peek(lookahead1: &Lookahead1) -> bool {
lookahead1.peek(|v| -> T { match v {} })
}
#[inline]
fn peek_stream(stream: ParseStream) -> bool {
stream.peek(|v| -> T { match v {} })
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct EasyPeekHack<'a, T>(&'a PhantomData<T>);
impl<'a, T> Parse for EasyPeekHack<'a, T> {
fn parse(_: ParseStream) -> syn::Result<Self> {
panic!("This function must not be called");
}
}
impl<'a, T> EasyPeek for EasyPeekHack<'a, T>
where
T: EasyPeek,
{
fn peek(lookahead1: &Lookahead1) -> bool {
T::peek(lookahead1)
}
fn peek_stream(stream: ParseStream) -> bool {
T::peek_stream(stream)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EasyParenthesized<T>(pub T);
impl<T> Deref for EasyParenthesized<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> Spanned for EasyParenthesized<T>
where
T: Spanned,
{
fn span(&self) -> Span {
self.0.span()
}
}
impl<T> EasyPeek for EasyParenthesized<T>
where
T: Parse,
{
#[inline]
fn peek(lookahead1: &Lookahead1) -> bool {
lookahead1.peek(syn::token::Paren)
}
#[inline]
fn peek_stream(stream: ParseStream) -> bool {
stream.peek(syn::token::Paren)
}
}
impl<T> Parse for EasyParenthesized<T>
where
T: Parse,
{
#[inline]
fn parse(input: ParseStream) -> syn::Result<Self> {
let inner;
syn::parenthesized!(inner in input);
T::parse(&inner).map(EasyParenthesized)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EasyBraced<T>(pub T);
impl<T> Deref for EasyBraced<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> Spanned for EasyBraced<T>
where
T: Spanned,
{
fn span(&self) -> Span {
self.0.span()
}
}
impl<T> EasyPeek for EasyBraced<T>
where
T: Parse,
{
#[inline]
fn peek(lookahead1: &Lookahead1) -> bool {
lookahead1.peek(syn::token::Brace)
}
#[inline]
fn peek_stream(stream: ParseStream) -> bool {
stream.peek(syn::token::Brace)
}
}
impl<T> Parse for EasyBraced<T>
where
T: Parse,
{
#[inline]
fn parse(input: ParseStream) -> syn::Result<Self> {
let inner;
syn::braced!(inner in input);
T::parse(&inner).map(EasyBraced)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EasyBracketed<T>(pub T);
impl<T> Deref for EasyBracketed<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> Spanned for EasyBracketed<T>
where
T: Spanned,
{
fn span(&self) -> Span {
self.0.span()
}
}
impl<T> EasyPeek for EasyBracketed<T>
where
T: Parse,
{
#[inline]
fn peek(lookahead1: &Lookahead1) -> bool {
lookahead1.peek(syn::token::Bracket)
}
#[inline]
fn peek_stream(stream: ParseStream) -> bool {
stream.peek(syn::token::Bracket)
}
}
impl<T> Parse for EasyBracketed<T>
where
T: Parse,
{
#[inline]
fn parse(input: ParseStream) -> syn::Result<Self> {
let inner;
syn::bracketed!(inner in input);
T::parse(&inner).map(EasyBracketed)
}
}
#[derive(Clone, Debug)]
pub struct EasySeparated<T, P = syn::Token![,]> {
items: Vec<T>,
punctuation: PhantomData<P>,
}
impl<T, P> Deref for EasySeparated<T, P> {
type Target = [T];
fn deref(&self) -> &[T] {
&self.items
}
}
impl<T, P> Parse for EasySeparated<T, P>
where
T: Parse,
P: EasyPeek,
{
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut items = Vec::new();
let item = input.parse::<T>()?;
items.push(item);
while P::peek_stream(input) {
let _ = input.parse::<P>()?;
let item = input.parse::<T>()?;
items.push(item);
}
Ok(EasySeparated {
items,
punctuation: PhantomData,
})
}
}
impl<T, P> EasyPeek for EasySeparated<T, P>
where
T: EasyPeek,
P: EasyPeek,
{
fn peek(lookahead1: &Lookahead1) -> bool {
T::peek(lookahead1)
}
fn peek_stream(stream: ParseStream) -> bool {
T::peek_stream(stream)
}
}
#[derive(Clone, Debug)]
pub struct EasyTerminated<T, P = syn::Token![,]> {
items: Vec<T>,
punctuation: PhantomData<P>,
}
impl<T, P> Deref for EasyTerminated<T, P> {
type Target = [T];
fn deref(&self) -> &[T] {
&self.items
}
}
impl<T, P> Parse for EasyTerminated<T, P>
where
T: Parse,
P: EasyPeek,
{
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut items = Vec::new();
if input.is_empty() {
return Ok(EasyTerminated {
items,
punctuation: PhantomData,
});
}
let item = input.parse::<T>()?;
items.push(item);
loop {
if input.is_empty() {
break;
}
let _ = input.parse::<P>()?;
if input.is_empty() {
break;
}
let item = input.parse::<T>()?;
items.push(item);
}
Ok(EasyTerminated {
items,
punctuation: PhantomData,
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EasyMaybe<T> {
Nothing,
Just(T),
}
impl<T> Default for EasyMaybe<T> {
fn default() -> Self {
EasyMaybe::Nothing
}
}
impl<T> Parse for EasyMaybe<T>
where
T: EasyPeek,
{
fn parse(input: ParseStream) -> syn::Result<Self> {
if T::peek_stream(input) {
T::parse(input).map(EasyMaybe::Just)
} else {
Ok(EasyMaybe::Nothing)
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EasySubArgument<V, T> {
Value(V),
Tuple(T),
}
impl<V, T> Parse for EasySubArgument<V, T>
where
V: Parse,
T: Parse,
{
fn parse(stream: ParseStream) -> syn::Result<Self> {
let lookahead1 = stream.lookahead1();
if lookahead1.peek(syn::Token![=]) {
stream.parse::<syn::Token![=]>()?;
Ok(EasySubArgument::Value(stream.parse::<V>()?))
} else if lookahead1.peek(Paren) {
let content;
syn::parenthesized!(content in stream);
Ok(EasySubArgument::Tuple(content.parse::<T>()?))
} else {
Err(lookahead1.error())
}
}
}
impl<V, T> EasyPeek for EasySubArgument<V, T>
where
V: Parse,
T: Parse,
{
fn peek(lookahead1: &Lookahead1) -> bool {
lookahead1.peek(syn::Token![=]) || lookahead1.peek(Paren)
}
fn peek_stream(stream: ParseStream) -> bool {
stream.peek(syn::Token![=]) || stream.peek(Paren)
}
}
#[macro_export]
macro_rules! easy_parse {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident;
) => {
$(#[$meta])*
$vis struct $name;
impl $crate::private::Parse for $name {
fn parse(_input: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
$crate::private::Result::Ok($name)
}
}
};
(
$(#[$meta:meta])*
$vis:vis struct $name:ident ();
) => {
$(#[$meta])*
$vis struct $name ();
impl $crate::private::Parse for $name {
fn parse(_input: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
$crate::private::Result::Ok($name ())
}
}
};
(
$(#[$meta:meta])*
$vis:vis struct $name:ident {}
) => {
$(#[$meta])*
$vis struct $name {}
impl $crate::private::Parse for $name {
fn parse(_input: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
$crate::private::Result::Ok($name {})
}
}
};
(
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$(#[$hmeta:meta])* $hvis:vis $hname:ident : $htype:ty
$(, $(#[$fmeta:meta])* $fvis:vis $fname:ident : $ftype:ty)*
$(,)?
}
) => {
$(#[$meta])*
$vis struct $name {
$(#[$hmeta])* $hvis $hname: $htype,
$($(#[$fmeta])* $fvis $fname: $ftype,)*
}
impl $crate::private::Parse for $name {
fn parse(input: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
#![allow(unused_variables)]
let $hname = <$htype as $crate::private::Parse>::parse(input)?;
$(
let $fname = <$ftype as $crate::private::Parse>::parse(input)?;
)*
$crate::private::Result::Ok($name {
$hname,
$( $fname, )*
})
}
}
impl $crate::EasyPeek for $name
where
for<'a> $crate::EasyPeekHack<'a, $htype>: $crate::EasyPeek,
{
#[inline]
fn peek(lookahead1: &$crate::private::Lookahead1) -> $crate::private::bool {
<$crate::EasyPeekHack<'static, $htype> as $crate::EasyPeek>::peek(lookahead1)
}
#[inline]
fn peek_stream(stream: $crate::private::ParseStream) -> $crate::private::bool {
<$crate::EasyPeekHack<'static, $htype> as $crate::EasyPeek>::peek_stream(stream)
}
}
};
(
$(#[$meta:meta])*
$vis:vis struct $name:ident (
$(#[$hmeta:meta])* $hvis:vis $htype:ty
$(, $(#[$fmeta:meta])* $fvis:vis $ftype:ty)*
$(,)?
);
) => {
$(#[$meta])*
$vis struct $name (
$(#[$hmeta])* $hvis $htype,
$($(#[$fmeta])* $fvis $ftype,)*
);
impl $crate::private::Parse for $name {
fn parse(input: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
#![allow(unused_variables)]
$crate::private::Result::Ok($name (
<$htype as $crate::private::Parse>::parse(input)?,
$(
<$ftype as $crate::private::Parse>::parse(input)?,
)*
))
}
}
impl $crate::EasyPeek for $name
where
for<'a> $crate::EasyPeekHack<'a, $htype>: $crate::EasyPeek,
{
#[inline]
fn peek(lookahead1: &$crate::private::Lookahead1) -> $crate::private::bool {
<$crate::EasyPeekHack<'static, $htype> as $crate::EasyPeek>::peek(lookahead1)
}
#[inline]
fn peek_stream(stream: $crate::private::ParseStream) -> $crate::private::bool {
<$crate::EasyPeekHack<'static, $htype> as $crate::EasyPeek>::peek_stream(stream)
}
}
};
(
$(#[$meta:meta])*
$vis:vis enum $name:ident {
$(#[$vdmeta:meta])* ! $vdname:ident $( ( $($vdt:tt)* ) )? $( { $($vdr:tt)* } )?,
$($(#[$vmeta:meta])* $( ? $vsname:ident )? $( $vname:ident )? $( ( $($vt:tt)* ) )? $( { $($vr:tt)* } )?, )*
}
) => {
$(#[$meta])*
$vis enum $name {
$(#[$vdmeta])* $vdname $( ( $($vdt)* ) )? $( { $($vdr)* } )?,
$( $(#[$vmeta])* $( $vsname )? $( $vname )? $( ( $($vt)* ) )? $( { $($vr)* } )?, )*
}
impl $crate::private::Parse for $name {
#[inline]
fn parse(input: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
#![allow(unused_variables)]
let lookahead1 = input.lookahead1();
$(
$crate::easy_parse_enum_variant!{parse lookahead1 input $name $( $vname )? $( ( $($vt)* ) )? $( { $($vr)* } )?}
)*
$crate::easy_parse_enum_variant!{parse_default input $name $vdname $( ( $($vdt)* ) )? $( { $($vdr)* } )?}
}
}
};
(
$(#[$meta:meta])*
$vis:vis enum $name:ident {
$($(#[$vmeta:meta])* $( ? $vsname:ident )? $( $vname:ident )? $( ( $($vt:tt)* ) )? $( { $($vr:tt)* } )?, )*
}
) => {
$(#[$meta])*
$vis enum $name {
$( $(#[$vmeta])* $( $vsname )? $( $vname )? $( ( $($vt)* ) )? $( { $($vr)* } )? ),*
}
impl $crate::private::Parse for $name {
#[inline]
fn parse(input: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
#![allow(unused_variables)]
let lookahead1 = input.lookahead1();
$(
$crate::easy_parse_enum_variant!{parse lookahead1 input $name $( $vname )? $( ( $($vt)* ) )? $( { $($vr)* } )?}
)*
$crate::private::Result::Err(lookahead1.error())
}
}
impl $crate::EasyPeek for $name {
#[inline]
fn peek(lookahead1: &$crate::private::Lookahead1) -> $crate::private::bool {
$(
$crate::easy_parse_enum_variant!{peek lookahead1 $($vname)? $( ( $($vt)* ) )? $( { $($vr)* } )?}
)*
false
}
#[inline]
fn peek_stream(stream: $crate::private::ParseStream) -> $crate::private::bool {
$(
$crate::easy_parse_enum_variant!{peek_stream stream $($vname)? $( ( $($vt)* ) )? $( { $($vr)* } )?}
)*
false
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! easy_parse_enum_variant {
(parse $lookahead1:ident $stream:ident $name:ident $vname:ident ( $(#[$vpmeta:meta])* $vptype:ty $(, $(#[$vfmeta:meta])* $vftype:ty )* $(,)? )) => {
if <$vptype as $crate::EasyPeek>::peek(&$lookahead1) {
return $crate::private::Result::Ok($name::$vname(
<$vptype as $crate::private::Parse>::parse($stream)?,
$( <$vftype as $crate::private::Parse>::parse($stream)?, )*
));
}
};
(peek $lookahead1:ident $vname:ident ( $(#[$vpmeta:meta])* $vptype:ty $(, $(#[$vfmeta:meta])* $vftype:ty )* $(,)? )) => {
if <$vptype as $crate::EasyPeek>::peek($lookahead1) {
return true;
}
};
(peek_stream $stream:ident $vname:ident ( $(#[$vpmeta:meta])* $vptype:ty $(, $(#[$vfmeta:meta])* $vftype:ty )* $(,)? )) => {
if <$vptype as $crate::EasyPeek>::peek_stream($stream) {
return true;
}
};
(parse $lookahead1:ident $stream:ident $name:ident $vname:ident { $(#[$vpmeta:meta])* $vpname:ident : $vptype:ty $(, $(#[$vfmeta:meta])* $vfname:ident : $vftype:ty )* $(,)? }) => {
if <$vptype as $crate::EasyPeek>::peek(&$lookahead1) {
let $vpname = <$vptype as $crate::private::Parse>::parse($stream)?;
$( let $vfname = <$vftype as $crate::private::Parse>::parse($stream)?; )*
return $crate::private::Result::Ok($name :: $vname {
$vpname,
$($vfname,)*
})
}
};
(peek $lookahead1:ident $vname:ident { $(#[$vpmeta:meta])* $vpname:ident : $vptype:ty $(, $(#[$vfmeta:meta])* $vfname:ident : $vftype:ty )* $(,)? }) => {
if <$vptype as $crate::EasyPeek>::peek($lookahead1) {
return true;
}
};
(peek_stream $stream:ident $vname:ident { $(#[$vpmeta:meta])* $vpname:ident : $vptype:ty $(, $(#[$vfmeta:meta])* $vfname:ident : $vftype:ty )* $(,)? }) => {
if <$vptype as $crate::EasyPeek>::peek_stream($stream) {
return true;
}
};
(parse_default $stream:ident $name:ident $vname:ident) => {
$crate::private::Result::Ok( $name::$vname )
};
(parse_default $stream:ident $name:ident $vname:ident ( $( $(#[$vfmeta:meta])* $vftype:ty ),* $(,)? )) => {
$crate::private::Result::Ok( $name::$vname ( $( <$vftype as $crate::private::Parse>::parse($stream)?, )* ))
};
(parse_default $stream:ident $name:ident $vname:ident { $( $(#[$vfmeta:meta])* $vfname:ident : $vftype:ty),* $(,)? }) => {
$crate::private::Result::Ok( $name::$vname { $( $vfname: <$vftype as $crate::private::Parse>::parse($stream)?, )* })
};
}
pub trait EasyArgument: EasyPeek {
fn name_display() -> &'static str;
fn name_span(&self) -> Span;
}
impl<T> EasyArgument for T
where
T: EasyToken,
{
fn name_display() -> &'static str {
<T as EasyToken>::display()
}
fn name_span(&self) -> Span {
<T as Spanned>::span(self)
}
}
#[macro_export]
macro_rules! easy_argument {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$(#[$nmeta:meta])* $nvis:vis $nname:ident: $ntype:ty
$(, $(#[$fmeta:meta])* $fvis:vis $fname:ident: $ftype:ty)*
$(,)?
}
) => {
$crate::easy_parse!{
$(#[$meta])*
$vis struct $name {
$(#[$nmeta])* $nvis $nname: $ntype,
$($(#[$fmeta])* $fvis $fname: $ftype,)*
}
}
impl $crate::EasyArgument for $name {
fn name_display() -> &'static str {
<$ntype as $crate::EasyToken>::display()
}
fn name_span(&self) -> $crate::private::Span {
<$ntype as $crate::private::Spanned>::span(&self.$nname)
}
}
};
(
$(#[$meta:meta])*
$vis:vis struct $name:ident (
$(#[$nmeta:meta])* $nvis:vis $ntype:ty
$(, $(#[$fmeta:meta])* $fvis:vis $ftype:ty)*
$(,)?
);
) => {
$crate::easy_parse!{
$(#[$meta])*
$vis struct $name (
$(#[$nmeta])* $nvis $ntype,
$( $(#[$fmeta])* $fvis $ftype,)*
);
}
impl $crate::EasyArgument for $name {
fn name_display() -> &'static str {
<$ntype as $crate::EasyToken>::display()
}
fn name_span(&self) -> $crate::private::Span {
<$ntype as $crate::private::Spanned>::span(&self.0)
}
}
};
}
#[macro_export]
macro_rules! easy_argument_tuple {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$(#[$nmeta:meta])* $nvis:vis $nname:ident: $ntype:ty
$(, $(#[$fmeta:meta])* $fvis:vis $fname:ident: $ftype:ty)*
$(,)?
}
) => {
$(#[$meta])*
$vis struct $name {
$(#[$nmeta])* $nvis $nname: $ntype,
$($(#[$fmeta])* $fvis $fname: $ftype,)*
}
impl $crate::EasyPeek for $name {
fn peek(lookahead1: &$crate::private::Lookahead1) -> $crate::private::bool {
<$ntype as $crate::EasyPeek>::peek(lookahead1)
}
fn peek_stream(stream: $crate::private::ParseStream) -> $crate::private::bool {
<$ntype as $crate::EasyPeek>::peek_stream(stream)
}
}
impl $crate::private::Parse for $name {
fn parse(stream: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
let $nname = stream.parse::<$ntype>()?;
$(let mut $fname = $crate::private::Option::None;)*
if stream.peek($crate::private::Paren) {
let content;
$crate::private::parenthesized!(content in stream);
loop {
if content.is_empty() {
break;
}
let lookahead1 = content.lookahead1();
$(
match &mut $fname {
$crate::private::Option::None => {
if let $crate::private::Option::Some(value) = <$ftype as $crate::EasyArgumentField>::try_parse(&lookahead1, &content)? {
$fname = $crate::private::Option::Some(value);
if content.is_empty() {
break;
}
content.parse::<$crate::private::Comma>()?;
continue
}
}
$crate::private::Option::Some($fname) => {
if <$ftype as $crate::EasyArgumentField>::try_extend($fname, &lookahead1, &content)? {
if content.is_empty() {
break;
}
content.parse::<$crate::private::Comma>()?;
continue
}
}
}
)*
return $crate::private::Result::Err(lookahead1.error());
}
}
$crate::private::Result::Ok($name {
$nname,
$(
$fname: match $fname {
$crate::private::Option::None => <$ftype as $crate::EasyArgumentField>::missing().map_err(|msg| stream.error(msg))?,
$crate::private::Option::Some($fname) => $fname,
},
)*
})
}
}
impl $crate::EasyArgument for $name {
fn name_display() -> &'static str {
<$ntype as $crate::EasyToken>::display()
}
fn name_span(&self) -> $crate::private::Span {
<$ntype as $crate::private::Spanned>::span(&self.$nname)
}
}
};
}
#[macro_export]
macro_rules! easy_argument_value {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$(#[$nmeta:meta])* $nvis:vis $nname:ident: $ntype:ty,
$(#[$vmeta:meta])* $vvis:vis $vname:ident: $vtype:ty
$(,)?
}
) => {
$(#[$meta])*
$vis struct $name {
$(#[$nmeta])* $nvis $nname: $ntype,
$(#[$vmeta])* $vvis $vname: $vtype,
}
impl $crate::EasyPeek for $name {
fn peek(lookahead1: &$crate::private::Lookahead1) -> $crate::private::bool {
<$ntype as $crate::EasyPeek>::peek(lookahead1)
}
fn peek_stream(stream: $crate::private::ParseStream) -> $crate::private::bool {
<$ntype as $crate::EasyPeek>::peek_stream(stream)
}
}
impl $crate::private::Parse for $name {
fn parse(stream: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
let $nname = stream.parse::<$ntype>()?;
let _ = stream.parse::<$crate::private::Eq>()?;
let $vname = <$vtype as $crate::private::Parse>::parse(stream)?;
$crate::private::Result::Ok($name {
$nname,
$vname,
})
}
}
impl $crate::EasyArgument for $name {
fn name_display() -> &'static str {
<$ntype as $crate::EasyToken>::display()
}
fn name_span(&self) -> $crate::private::Span {
<$ntype as $crate::private::Spanned>::span(&self.$nname)
}
}
};
(
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$(#[$nmeta:meta])* $nvis:vis $nname:ident: $ntype:ty,
$(#[$vmeta:meta])* ? $vvis:vis $vname:ident: $vtype:ty
$(,)?
}
) => {
$(#[$meta])*
$vis struct $name {
$(#[$nmeta])* $nvis $nname: $ntype,
$(#[$vmeta])* $vvis $vname: $vtype,
}
impl $crate::EasyPeek for $name {
fn peek(lookahead1: &$crate::private::Lookahead1) -> $crate::private::bool {
<$ntype as $crate::EasyPeek>::peek(lookahead1)
}
fn peek_stream(stream: $crate::private::ParseStream) -> $crate::private::bool {
<$ntype as $crate::EasyPeek>::peek_stream(stream)
}
}
impl $crate::private::Parse for $name {
fn parse(stream: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
let $nname = stream.parse::<$ntype>()?;
if stream.is_empty() {
$crate::private::Result::Ok($name {
$nname,
$vname: <$vtype as $crate::private::Default>::default(),
})
} else {
let _ = stream.parse::<$crate::private::Eq>()?;
let $vname = <$vtype as $crate::private::Parse>::parse(stream)?;
$crate::private::Result::Ok($name {
$nname,
$vname,
})
}
}
}
impl $crate::EasyArgument for $name {
fn name_display() -> &'static str {
<$ntype as $crate::EasyToken>::display()
}
fn name_span(&self) -> $crate::private::Span {
<$ntype as $crate::private::Spanned>::span(&self.$nname)
}
}
};
(
$(#[$meta:meta])*
$vis:vis struct $name:ident (
$(#[$nmeta:meta])* $nvis:vis $ntype:ty,
$(#[$vmeta:meta])* $vvis:vis $vtype:ty
$(,)?
);
) => {
$(#[$meta])*
$vis struct $name (
$(#[$nmeta])* $nvis $ntype,
$(#[$vmeta])* $vvis $vtype,
);
impl $crate::EasyPeek for $name {
fn peek(lookahead1: &$crate::private::Lookahead1) -> $crate::private::bool {
<$ntype as $crate::EasyPeek>::peek(lookahead1)
}
fn peek_stream(stream: $crate::private::ParseStream) -> $crate::private::bool {
<$ntype as $crate::EasyPeek>::peek_stream(stream)
}
}
impl $crate::private::Parse for $name {
fn parse(stream: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
let name = stream.parse::<$ntype>()?;
let _ = stream.parse::<$crate::private::Eq>()?;
let value = <$vtype as $crate::private::Parse>::parse(stream)?;
$crate::private::Result::Ok($name(name, value))
}
}
impl $crate::EasyArgument for $name {
fn name_display() -> &'static str {
<$ntype as $crate::EasyToken>::display()
}
fn name_span(&self) -> $crate::private::Span {
<$ntype as $crate::private::Spanned>::span(&self.0)
}
}
};
(
$(#[$meta:meta])*
$vis:vis struct $name:ident (
$(#[$nmeta:meta])* $nvis:vis $nname:ident: $ntype:ty,
$(#[$vmeta:meta])* ? $vvis:vis $vname:ident: $vtype:ty
$(,)?
);
) => {
$(#[$meta])*
$vis struct $name (
$(#[$nmeta])* $nvis $ntype,
$(#[$vmeta])* $vvis $vtype,
);
impl $crate::EasyPeek for $name {
fn peek(lookahead1: &$crate::private::Lookahead1) -> $crate::private::bool {
<$ntype as $crate::EasyPeek>::peek(lookahead1)
}
fn peek_stream(stream: $crate::private::ParseStream) -> $crate::private::bool {
<$ntype as $crate::EasyPeek>::peek_stream(stream)
}
}
impl $crate::private::Parse for $name {
fn parse(stream: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
let name = stream.parse::<$ntype>()?;
if stream.is_empty() {
$crate::private::Result::Ok($name(name, <$vtype as $crate::private::Default>::default()))
} else {
let _ = stream.parse::<$crate::private::Eq>()?;
let value = <$vtype as $crate::private::Parse>::parse(stream)?;
$crate::private::Result::Ok($name(name, value))
}
}
}
impl $crate::EasyArgument for $name {
fn name_display() -> &'static str {
<$ntype as $crate::EasyToken>::display()
}
fn name_span(&self) -> $crate::private::Span {
<$ntype as $crate::private::Spanned>::span(&self.0)
}
}
};
}
pub trait EasyArgumentGroup {
fn try_parse(lookahead1: &Lookahead1, stream: ParseStream) -> syn::Result<Option<Self>>
where
Self: Sized;
fn overlap_error(&self, other: &Self) -> syn::Error;
fn missing_error() -> String;
}
impl<T> EasyArgumentGroup for T
where
T: EasyArgument,
{
#[inline]
fn try_parse(lookahead1: &Lookahead1, stream: ParseStream) -> syn::Result<Option<Self>> {
if <T as EasyPeek>::peek(lookahead1) {
T::parse(stream).map(Some)
} else {
Ok(None)
}
}
fn overlap_error(&self, other: &Self) -> syn::Error {
syn::Error::new(
other.name_span(),
format!(
"{} can be specified at most once",
<T as EasyArgument>::name_display()
),
)
}
fn missing_error() -> String {
format!(
"{} attribute is required",
<T as EasyArgument>::name_display()
)
}
}
#[macro_export]
macro_rules! easy_argument_group {
(
$(#[$meta:meta])*
$vis:vis enum $name:ident {
$( $(#[$vmeta:meta])* $vname:ident ( $(#[$vtmeta:meta])* $vtype:ty ) ),*
$(,)?
}
) => {
$crate::easy_parse! {
$(#[$meta])*
$vis enum $name {
$( $(#[$vmeta])* $vname ( $(#[$vtmeta])* $vtype ), )*
}
}
impl $name {
#[inline]
pub fn name_display(&self) -> &'static str {
match *self {
$( $name :: $vname (_) => <$vtype as $crate::EasyArgument>::name_display(), )*
}
}
#[inline]
pub fn name_span(&self) -> $crate::private::Span {
match *self {
$( $name :: $vname (ref var) => <$vtype as $crate::EasyArgument>::name_span(var), )*
}
}
}
impl $crate::EasyArgumentGroup for $name {
#[inline]
fn try_parse(lookahead1: &$crate::private::Lookahead1, stream: $crate::private::ParseStream) -> $crate::private::Result<$crate::private::Option<Self>, $crate::private::Error> {
#![allow(unused_variables)]
$(
if <$vtype as $crate::EasyPeek>::peek(&lookahead1) {
let variant = <$vtype as $crate::private::Parse>::parse(stream)?;
return $crate::private::Result::Ok($crate::private::Option::Some($name::$vname(variant)));
}
)*
$crate::private::Result::Ok($crate::private::Option::None)
}
#[inline]
fn overlap_error(&self, other: &Self) -> $crate::private::Error {
let msg = if $crate::private::discriminant(self) == $crate::private::discriminant(other) {
$crate::private::format!("{} can be specified only once", self.name_display())
} else {
$crate::private::format!("{} is mutually exclusive with {}", self.name_display(), other.name_display())
};
$crate::private::Error::new(other.name_span(), msg)
}
fn missing_error() -> String {
$crate::private::format!(
$crate::private::concat!("One of {{", $(
$crate::easy_replace_tokens!("{}, ", $vname),
)* "}} is expected"),
$(<$vtype as $crate::EasyArgument>::name_display(),)*
)
}
}
};
}
pub trait EasyArgumentField {
fn try_parse(lookahead1: &Lookahead1, stream: ParseStream) -> syn::Result<Option<Self>>
where
Self: Sized;
fn try_extend(&mut self, lookahead1: &Lookahead1, stream: ParseStream) -> syn::Result<bool>;
fn missing() -> Result<Self, String>
where
Self: Sized;
}
impl<T> EasyArgumentField for T
where
T: EasyArgumentGroup,
{
fn try_parse(lookahead1: &Lookahead1, stream: ParseStream) -> syn::Result<Option<Self>> {
<T as EasyArgumentGroup>::try_parse(lookahead1, stream)
}
fn try_extend(&mut self, lookahead1: &Lookahead1, stream: ParseStream) -> syn::Result<bool> {
match <T as EasyArgumentGroup>::try_parse(lookahead1, stream)? {
None => Ok(false),
Some(other) => Err(self.overlap_error(&other)),
}
}
fn missing() -> Result<Self, String> {
Err(T::missing_error())
}
}
impl<T> EasyArgumentField for Option<T>
where
T: EasyArgumentField,
{
fn try_parse(lookahead1: &Lookahead1, stream: ParseStream) -> syn::Result<Option<Self>> {
<T as EasyArgumentField>::try_parse(lookahead1, stream).map(Some)
}
fn try_extend(&mut self, lookahead1: &Lookahead1, stream: ParseStream) -> syn::Result<bool> {
match self {
None => match <T as EasyArgumentField>::try_parse(lookahead1, stream)? {
None => Ok(false),
Some(attr) => {
*self = Some(attr);
Ok(true)
}
},
Some(attr) => attr.try_extend(lookahead1, stream),
}
}
fn missing() -> Result<Self, String> {
Ok(None)
}
}
impl<T> EasyArgumentField for Vec<T>
where
T: EasyArgumentGroup,
{
fn try_parse(lookahead1: &Lookahead1, stream: ParseStream) -> syn::Result<Option<Self>> {
match <T as EasyArgumentGroup>::try_parse(lookahead1, stream)? {
None => Ok(None),
Some(attr) => Ok(Some(vec![attr])),
}
}
fn try_extend(&mut self, lookahead1: &Lookahead1, stream: ParseStream) -> syn::Result<bool> {
match <T as EasyArgumentGroup>::try_parse(lookahead1, stream)? {
None => Ok(false),
Some(attr) => {
self.push(attr);
Ok(true)
}
}
}
fn missing() -> Result<Self, String> {
Ok(Vec::new())
}
}
#[macro_export]
macro_rules! easy_flags {
( $(#[$onemeta:meta])* $ovis:vis $one:ident($onekw:ident) $(| $(#[$manymeta:meta])* $mvis:vis $many:ident($manykw:ident))? { $( $(#[$flagmeta:meta])* $flag:ident($flagkw:ident)),* $(,)? }) => {
$($crate::easy_token!($flagkw);)*
$crate::easy_token!($onekw);
$(#[$onemeta])*
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
$ovis enum $one {
$( $(#[$flagmeta])* $flag($flagkw), )*
}
impl $one {
#[allow(dead_code)]
$ovis fn try_parse_terminated<T: $crate::private::Parse>(lookahead1: &$crate::private::Lookahead1, stream: $crate::private::ParseStream) -> $crate::private::Result<$crate::private::Option<$crate::private::Punctuated<Self, $crate::private::Comma>>, $crate::private::Error> {
if $( lookahead1.peek($flagkw) || )* false {
stream.parse_terminated::<Self, $crate::private::Comma>($crate::private::Parse::parse).map($crate::private::Option::Some)
} else {
$crate::private::Result::Ok($crate::private::Option::None)
}
}
}
impl $crate::private::Spanned for $one {
fn span(&self) -> $crate::private::Span {
match *self {
$( $one::$flag (ref flag) => $crate::private::Spanned::span(flag), )*
}
}
}
impl $crate::EasyArgumentGroup for $one {
fn try_parse(lookahead1: &$crate::private::Lookahead1, stream: $crate::private::ParseStream) -> $crate::private::Result<$crate::private::Option<Self>, $crate::private::Error> {
#![allow(unused_variables)]
$(
if lookahead1.peek($flagkw) {
let flag = stream.parse::<$flagkw>()?;
return $crate::private::Result::Ok( $crate::private::Option::Some( $one::$flag(flag)) );
}
)*
$crate::private::Result::Ok($crate::private::Option::None)
}
fn overlap_error(&self, other: &Self) -> $crate::private::Error {
let msg = $crate::private::concat!("Only one flag {", $( $crate::private::stringify!($flagkw), ", ", )* "} is expected");
$crate::private::Error::new(
$crate::private::Spanned::span(other),
msg,
)
}
fn missing_error() -> $crate::private::String {
String::from($crate::private::concat!("One flag of {", $( $crate::private::stringify!($flagkw), ", ", )* "} is expected"))
}
}
impl $crate::private::Parse for $one {
fn parse(stream: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
let lookahead1 = stream.lookahead1();
match <Self as $crate::EasyArgumentGroup>::try_parse(&lookahead1, stream)? {
$crate::private::Option::None => $crate::private::Result::Err(lookahead1.error()),
$crate::private::Option::Some(flag) => $crate::private::Result::Ok(flag),
}
}
}
$(
$crate::easy_token!($manykw);
$(#[$manymeta])*
#[derive(Clone, Debug)]
#[allow(dead_code)]
$mvis struct $many {
pub start_span: $crate::private::Span,
pub end_span: $crate::private::Span,
pub flags: $crate::private::Punctuated<$one, $crate::private::Comma>,
}
impl $many {
#[allow(dead_code)]
pub fn new(span: $crate::private::Span) -> Self {
$many {
start_span: span,
end_span: span,
flags: $crate::private::Punctuated::new(),
}
}
}
impl $crate::private::Default for $many {
fn default() -> Self {
$many {
start_span: $crate::private::Span::call_site(),
end_span: $crate::private::Span::call_site(),
flags: $crate::private::Punctuated::default(),
}
}
}
impl $crate::private::Spanned for $many {
fn span(&self) -> $crate::private::Span {
self.start_span.join(self.end_span).unwrap_or(self.start_span)
}
}
impl $crate::EasyArgumentField for $many {
fn try_parse(lookahead1: &$crate::private::Lookahead1, stream: $crate::private::ParseStream) -> $crate::private::Result<$crate::private::Option<Self>, $crate::private::Error> {
if lookahead1.peek($onekw) {
let one = stream.parse::<$onekw>()?;
let content;
$crate::private::parenthesized!(content in stream);
let flag = content.parse::<$one>()?;
$crate::private::Result::Ok($crate::private::Option::Some($many {
start_span: $crate::private::Spanned::span(&one),
end_span: $crate::private::Spanned::span(&flag),
flags: {
let mut flags = $crate::private::Punctuated::new();
flags.push(flag);
flags
},
}))
} else if lookahead1.peek($manykw) {
let many = stream.parse::<$manykw>()?;
let content;
$crate::private::parenthesized!(content in stream);
let flags = content.parse_terminated(<$one as $crate::private::Parse>::parse)?;
let end_span = flags.last().map($crate::private::Spanned::span).unwrap_or($crate::private::Spanned::span(&many));
$crate::private::Result::Ok($crate::private::Option::Some($many {
start_span: $crate::private::Spanned::span(&many),
end_span,
flags,
}))
} else {
match $one::try_parse_terminated::<$crate::private::Comma>(lookahead1, stream)? {
$crate::private::Option::None => $crate::private::Result::Ok($crate::private::Option::None),
$crate::private::Option::Some(flags) => {
let flag = flags.last().unwrap();
let span = $crate::private::Spanned::span(flag);
$crate::private::Result::Ok($crate::private::Option::Some($many {
start_span: span,
end_span: span,
flags,
}))
}
}
}
}
fn try_extend(&mut self, lookahead1: &$crate::private::Lookahead1, stream: $crate::private::ParseStream) -> $crate::private::Result<$crate::private::bool, $crate::private::Error> {
if lookahead1.peek($onekw) {
let _ = stream.parse::<$onekw>()?;
let content;
$crate::private::parenthesized!(content in stream);
let flag = content.parse::<$one>()?;
self.end_span = $crate::private::Spanned::span(&flag);
self.flags.push(flag);
$crate::private::Result::Ok(true)
} else if lookahead1.peek($manykw) {
let many = stream.parse::<$manykw>()?;
let content;
$crate::private::parenthesized!(content in stream);
let flags = content.parse_terminated::<_, $crate::private::Comma>(<$one as $crate::private::Parse>::parse)?;
self.end_span = flags.last().map($crate::private::Spanned::span).unwrap_or($crate::private::Spanned::span(&many));
self.flags.extend(flags);
$crate::private::Result::Ok(true)
} else {
match $one::try_parse_terminated::<$crate::private::Comma>(lookahead1, stream)? {
$crate::private::Option::None => $crate::private::Result::Ok(false),
$crate::private::Option::Some(flags) => {
let flag = flags.last().unwrap();
self.end_span = $crate::private::Spanned::span(flag);
self.flags.extend(flags);
$crate::private::Result::Ok(true)
}
}
}
}
fn missing() -> $crate::private::Result<Self, $crate::private::String> {
$crate::private::Result::Err(<$one as $crate::EasyArgumentGroup>::missing_error())
}
}
impl $crate::private::Parse for $many {
fn parse(stream: $crate::private::ParseStream) -> $crate::private::Result<Self, $crate::private::Error> {
let lookahead1 = stream.lookahead1();
match <Self as $crate::EasyArgumentField>::try_parse(&lookahead1, stream)? {
$crate::private::Option::None => $crate::private::Result::Err(lookahead1.error()),
$crate::private::Option::Some(flag) => $crate::private::Result::Ok(flag),
}
}
}
)?
};
}
#[macro_export]
macro_rules! easy_terminated {
(
@($punct:ident)
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$($(#[$fmeta:meta])* $fvis:vis $fname:ident : $ftype:ty),*
$(,)?
}
) => {
$(#[$meta])*
$vis struct $name {
$($(#[$fmeta])* $fvis $fname : $ftype,)*
}
impl $crate::private::Parse for $name {
fn parse(stream: $crate::private::ParseStream) -> $crate::private::Result<Self> {
$(let $fname = $crate::private::None;)*
loop {
if stream.is_empty() {
break;
}
let lookahead1 = stream.lookahead1();
$(
match &mut $fname {
$crate::private::Option::None => {
if let $crate::private::Option::Some(value) = <$ftype as $crate::EasyArgumentField>::try_parse(&lookahead1, stream)? {
$fname = $crate::private::Option::Some(value);
if stream.is_empty() {
break;
}
stream.parse::<$punct>()?;
continue
}
}
$crate::private::Option::Some($fname) => {
if <$ftype as $crate::EasyArgumentField>::try_extend($fname, &lookahead1, stream)? {
if stream.is_empty() {
break;
}
stream.parse::<$punct>()?;
continue
}
}
}
)*
return $crate::private::Result::Err(lookahead1.error());
}
$crate::private::Result::Ok($name {
$(
$fname: match $fname {
$crate::private::Option::None => <$ftype as $crate::EasyArgumentField>::missing().map_err(|msg| stream.error(msg))?,
$crate::private::Option::Some($fname) => $fname,
},
)*
})
}
}
};
}
#[macro_export]
macro_rules! easy_separated {
(
@($punct:ident)
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$($(#[$fmeta:meta])* $fvis:vis $fname:ident : $ftype:ty),*
$(,)?
}
) => {
$(#[$meta])*
$vis struct $name {
$($(#[$fmeta])* $fvis $fname : $ftype,)*
}
impl $crate::private::Parse for $name {
fn parse(stream: $crate::private::ParseStream) -> $crate::private::Result<Self> {
$(let $fname = $crate::private::None;)*
loop {
if stream.is_empty() {
break;
}
let lookahead1 = stream.lookahead1();
$(
match &mut $fname {
$crate::private::Option::None => {
if let $crate::private::Option::Some(value) = <$ftype as $crate::EasyArgumentField>::try_parse(&lookahead1, stream)? {
$fname = $crate::private::Option::Some(value);
if !<$punct as $crate::private::EasyPeek>::peek_stream(stream) {
break;
}
stream.parse::<$punct>()?;
continue
}
}
$crate::private::Option::Some($fname) => {
if <$ftype as $crate::EasyArgumentField>::try_extend($fname, &lookahead1, stream)? {
if !<$punct as $crate::private::EasyPeek>::peek_stream(stream) {
break;
}
stream.parse::<$punct>()?;
continue
}
}
}
)*
return $crate::private::Result::Err(lookahead1.error());
}
$crate::private::Result::Ok($name {
$(
$fname: match $fname {
$crate::private::Option::None => <$ftype as $crate::EasyArgumentField>::missing().map_err(|msg| stream.error(msg))?,
$crate::private::Option::Some($fname) => $fname,
},
)*
})
}
}
};
}
pub trait EasyAttributes {
fn parse(attrs: &[syn::Attribute], span: Span) -> syn::Result<Self>
where
Self: Sized;
}
#[macro_export]
macro_rules! easy_attributes {
(
@($namespace:ident)
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$( $(#[$fmeta:meta])* $fvis:vis $fname:ident : $ftype:ty),*
$(,)?
}
) => {
$(#[$meta])*
$vis struct $name {
$( $(#[$fmeta])* $fvis $fname : $ftype,)*
}
impl $crate::EasyAttributes for $name {
fn parse(attrs: &[$crate::private::Attribute], span: $crate::private::Span) -> $crate::private::Result<Self, $crate::private::Error> {
$(let mut $fname = $crate::private::Option::None;)*
for attr in attrs {
if attr.path.is_ident(::core::stringify!($namespace)) {
attr.parse_args_with(|stream: $crate::private::ParseStream| {
loop {
if stream.is_empty() {
return $crate::private::Result::Ok(());
}
let lookahead1 = stream.lookahead1();
$(
match &mut $fname {
$crate::private::Option::None => {
if let $crate::private::Option::Some(value) = <$ftype as $crate::EasyArgumentField>::try_parse(&lookahead1, stream)? {
$fname = $crate::private::Option::Some(value);
if stream.is_empty() {
return $crate::private::Result::Ok(());
}
stream.parse::<$crate::private::Comma>()?;
continue;
}
}
$crate::private::Option::Some($fname) => {
if <$ftype as $crate::EasyArgumentField>::try_extend($fname, &lookahead1, stream)? {
if stream.is_empty() {
return $crate::private::Result::Ok(());
}
stream.parse::<$crate::private::Comma>()?;
continue;
}
}
}
)*
return $crate::private::Result::Err(lookahead1.error())
}
})?;
}
}
$crate::private::Result::Ok($name {
$(
$fname: match $fname {
$crate::private::Option::None => <$ftype as $crate::EasyArgumentField>::missing().map_err(|msg| $crate::private::Error::new(span, msg))?,
$crate::private::Option::Some($fname) => $fname,
},
)*
})
}
}
};
}
easy_parse! {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ReferenceExpr {
! Member {
member: syn::Member,
},
Expr {
const_: syn::Token![const],
expr: syn::Expr,
},
}
}
#[cfg(any(test, doc))]
#[allow(missing_docs)]
pub mod examples {
easy_flags! {
pub Nya(nya) | pub Nyas(nyas) {
Puk(puk),
Pak(pak),
}
}
easy_parse! {
#[derive(Clone, Debug)]
pub struct Foo {
pub foo: syn::Ident,
}
}
easy_parse! {
#[derive(Clone, Copy, Debug)]
pub struct Bar;
}
easy_parse! {
#[derive(Clone, Debug)]
pub struct Baz(pub syn::Member);
}
easy_parse! {
#[derive(Clone, Debug)]
pub enum FooBar {
! Bar(Bar),
Foo(Foo),
}
}
easy_token!(arg);
easy_argument! {
#[derive(Clone, Debug)]
pub struct Arg {
pub arg: arg,
pub foobar: FooBar,
}
}
easy_token!(outer);
easy_argument_tuple! {
#[derive(Clone, Debug)]
pub struct Outer {
pub outer: outer,
pub arg: Arg,
}
}
}
#[cfg(test)]
mod tests {
use proc_macro2::Span;
use crate::EasyAttributes;
#[allow(warnings)]
enum Option {}
#[allow(warnings)]
const None: () = ();
#[allow(warnings)]
enum Result {}
#[allow(warnings)]
const Ok: () = ();
#[allow(warnings)]
const Err: () = ();
#[allow(warnings)]
enum Vec {}
#[allow(warnings)]
macro_rules! vec {
() => {
compile_error!();
};
}
trait Default {}
#[allow(warnings)]
enum bool {}
easy_flags! {
pub Nya(nya) |
Nyas(nyas) {
Puk(puk),
Pak(pak),
}
}
easy_token!(foo);
easy_token!(bar);
easy_token!(baz);
easy_token!(a);
easy_token!(b);
easy_argument_value! {
#[derive(Clone, Debug)]
pub struct A {
pub a: a,
pub ident: syn::Ident,
}
}
easy_argument_value! {
#[derive(Clone, Debug)]
pub struct B {
pub b: b,
pub lit: syn::LitInt,
}
}
easy_argument_tuple! {
#[derive(Clone, Debug)]
pub struct Foo {
pub name: foo,
pub a: A,
pub b: B,
}
}
easy_argument! {
#[derive(Clone, Debug)]
pub struct Bar {
pub name: bar,
pub ident: syn::Ident,
}
}
easy_argument_group! {
#[derive(Clone, Debug)]
pub enum Group {
Foo(
Foo
),
Bar(
Bar
),
}
}
easy_attributes! {
@(easy)
#[derive(Clone, Default)]
pub struct Attributes {
pub foo: std::option::Option<Foo>,
pub bar: std::option::Option<Bar>,
}
}
#[test]
fn test1() {
let attrs = quote::quote!(
#[easy(foo(a = a, b = 42), bar b)]
);
let attrs = syn::parse::Parser::parse2(syn::Attribute::parse_outer, attrs).unwrap();
let bar = Attributes::parse(&attrs, Span::call_site()).unwrap();
match &bar.foo {
std::option::Option::Some(Foo {
a: A { ident, .. },
b: B { lit, .. },
..
}) => {
assert_eq!(ident, "a");
assert_eq!(lit.base10_parse::<u32>().unwrap(), 42);
}
_ => panic!(),
}
match &bar.bar {
std::option::Option::Some(bar) => assert_eq!(bar.ident, "b"),
std::option::Option::None => panic!(),
}
}
}