use crate::{parse_helpers::*, Errors, Result};
use proc_macro2::Span;
use quote::ToTokens;
use std::{
borrow::Borrow,
collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
fmt::{self, Write},
hash::Hash,
};
use syn::{
parse::{Nothing, Parse, ParseBuffer, ParseStream, Peek},
punctuated::Punctuated,
Token,
};
#[derive(Debug, Clone, Copy)]
pub enum ParseMode {
Named(Span),
Unnamed,
}
impl ParseMode {
#[inline]
pub fn to_named(&self, input: ParseStream) -> Self {
match self {
Self::Unnamed => Self::Named(input.span()),
m => *m,
}
}
#[inline]
pub fn named_span(&self) -> Option<Span> {
match self {
Self::Named(s) => Some(*s),
_ => None,
}
}
#[inline]
pub fn to_span(&self, input: ParseStream) -> Span {
self.named_span().unwrap_or_else(|| input.span())
}
#[inline]
pub fn to_full_span<'s, S: Borrow<ParseBuffer<'s>>>(&self, inputs: &[S]) -> Span {
self.named_span().unwrap_or_else(|| inputs_span(inputs))
}
}
pub trait ParseMetaItem: Sized {
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self>;
#[inline]
fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
) -> Result<Self> {
parse_first(inputs, _mode, Self::parse_meta_item)
}
#[inline]
fn parse_meta_item_flag(_span: Span) -> Result<Self> {
Err(flag_disallowed_error(_span))
}
#[inline]
fn parse_meta_item_named(input: ParseStream, _name: &str, span: Span) -> Result<Self> {
parse_named_meta_item(input, span)
}
#[inline]
fn missing_meta_item(name: &str, span: Span) -> Result<Self> {
Err(missing_field_error(name, span))
}
}
pub trait ParseMetaFlatUnnamed: Sized {
fn field_count() -> Option<usize>;
fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
index: usize,
) -> Result<Self>;
}
pub trait ParseMetaFlatNamed: Sized {
fn field_names() -> &'static [&'static str];
fn parse_meta_flat_named<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
prefix: &str,
validate: bool,
) -> Result<Self>;
const ACCEPTS_ALL: bool = false;
}
pub trait ParseMetaAppend: Sized {
fn parse_meta_append<'s, S, I, P>(inputs: &[S], paths: I) -> Result<Self>
where
S: Borrow<ParseBuffer<'s>>,
I: IntoIterator<Item = P>,
I::IntoIter: Clone,
P: AsRef<str>;
}
pub trait ParseMetaRest: Sized {
fn parse_meta_rest<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
exclude: &[&str],
) -> Result<Self>;
}
pub trait ToKeyString: Sized {
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result;
fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
f(&key_to_string(self))
}
}
macro_rules! impl_parse_meta_item_primitive {
($ty:ty, $lit:ty, $conv:ident) => {
impl ParseMetaItem for $ty {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
impl_parse_meta_item_primitive!(@conv input, _mode, $lit, $conv)
}
}
impl ToKeyString for $ty {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
};
(@conv $input:ident, $mode:ident, $lit:ty, base10_parse) => {
$input.parse::<$lit>()?.base10_parse()
};
(@conv $input:ident, $mode:ident, $lit:ty, value) => {
Ok($input.parse::<$lit>()?.value())
};
(@conv $input:ident, $mode:ident, $lit:ty, from_str) => {
$crate::with::from_str::parse_meta_item($input, $mode)
};
}
impl_parse_meta_item_primitive!(i8, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(i16, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(i32, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(i64, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(i128, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(isize, syn::LitInt, base10_parse);
impl ParseMetaItem for u8 {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(syn::LitByte) {
Ok(input.parse::<syn::LitByte>()?.value())
} else if lookahead.peek(syn::LitInt) {
Ok(input.parse::<syn::LitInt>()?.base10_parse()?)
} else {
Err(lookahead.error())
}
}
}
impl_parse_meta_item_primitive!(u16, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(u32, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(u64, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(u128, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(usize, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(f32, syn::LitFloat, base10_parse);
impl_parse_meta_item_primitive!(f64, syn::LitFloat, base10_parse);
impl ParseMetaItem for bool {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Ok(input.parse::<syn::LitBool>()?.value())
}
#[inline]
fn parse_meta_item_flag(_: Span) -> Result<Self> {
Ok(true)
}
}
impl_parse_meta_item_primitive!(std::num::NonZeroI8, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroI16, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroI32, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroI64, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroI128, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroIsize, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroU8, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroU16, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroU32, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroU64, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroU128, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(std::num::NonZeroUsize, syn::LitInt, base10_parse);
impl_parse_meta_item_primitive!(char, syn::LitChar, value);
impl ParseMetaItem for String {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Ok(input.parse::<syn::LitStr>()?.value())
}
}
impl ToKeyString for String {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
#[inline]
fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
f(self)
}
}
impl ParseMetaItem for std::path::PathBuf {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Ok(Self::from(input.parse::<syn::LitStr>()?.value()))
}
}
impl ToKeyString for std::path::PathBuf {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.to_string_lossy())
}
#[inline]
fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
f(&self.to_string_lossy())
}
}
impl ParseMetaItem for std::ffi::OsString {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Ok(Self::from(input.parse::<syn::LitStr>()?.value()))
}
}
impl ToKeyString for std::ffi::OsString {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.to_string_lossy())
}
#[inline]
fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
f(&self.to_string_lossy())
}
}
impl_parse_meta_item_primitive!(std::net::IpAddr, syn::LitStr, from_str);
impl_parse_meta_item_primitive!(std::net::Ipv4Addr, syn::LitStr, from_str);
impl_parse_meta_item_primitive!(std::net::Ipv6Addr, syn::LitStr, from_str);
impl_parse_meta_item_primitive!(std::net::SocketAddr, syn::LitStr, from_str);
impl_parse_meta_item_primitive!(std::net::SocketAddrV4, syn::LitStr, from_str);
impl_parse_meta_item_primitive!(std::net::SocketAddrV6, syn::LitStr, from_str);
impl<T: ParseMetaItem> ParseMetaItem for Option<T> {
#[inline]
fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
match mode {
ParseMode::Named(_) => T::parse_meta_item(input, mode).map(Some),
ParseMode::Unnamed => {
mod keywords {
syn::custom_keyword!(Some);
syn::custom_keyword!(None);
}
let lookahead = input.lookahead1();
if lookahead.peek(keywords::Some) {
input.parse::<keywords::Some>()?;
Paren::parse_delimited_meta_item(input, mode).map(Some)
} else if lookahead.peek(keywords::None) {
input.parse::<keywords::None>()?;
Ok(None)
} else {
Err(lookahead.error())
}
}
}
}
#[inline]
fn parse_meta_item_flag(span: Span) -> Result<Self> {
T::parse_meta_item_flag(span).map(Some)
}
#[inline]
fn missing_meta_item(_name: &str, _span: Span) -> Result<Self> {
Ok(None)
}
}
impl<T: ToKeyString> ToKeyString for Option<T> {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Some(v) => {
f.write_str("Some(")?;
v.fmt_key_string(f)?;
f.write_char(')')
}
None => f.write_str("None"),
}
}
}
impl<T: ParseMetaItem, const N: usize> ParseMetaItem for [T; N] {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Bracket::parse_delimited_meta_item(input, ParseMode::Unnamed)
}
#[inline]
fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
) -> Result<Self> {
Self::parse_meta_flat_unnamed(inputs, _mode, 0)
}
}
impl<T: ParseMetaItem, const N: usize> ParseMetaFlatUnnamed for [T; N] {
#[inline]
fn field_count() -> Option<usize> {
Some(N)
}
fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
index: usize,
) -> Result<Self> {
let mut a = arrayvec::ArrayVec::<T, N>::new();
let errors = Errors::new();
let mut failed = 0;
errors.push_result(parse_tuple_struct(inputs, N, |stream, _, _| {
match errors.push_result(T::parse_meta_item(stream, ParseMode::Unnamed)) {
Some(v) => a.push(v),
None => {
failed += 1;
skip_meta_item(stream);
}
}
Ok(())
}));
if a.len() + failed != N {
errors.push(
inputs_span(inputs),
format!(
"Expected array at index {} of length {}, got {}",
index,
N,
a.len() + failed,
),
);
}
errors.check()?;
Ok(a.into_inner().unwrap_or_else(|_| unreachable!()))
}
}
impl<T: ToKeyString, const N: usize> ToKeyString for [T; N] {
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char('[')?;
for (i, v) in self.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
v.fmt_key_string(f)?;
}
f.write_char(']')
}
}
macro_rules! impl_parse_meta_item_collection {
($ty:ident <$param:ident $(: $bound:tt $(+ $bounds:tt)*)?>, $ident:ident, $item:ident, $push:expr) => {
impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaItem for $ty <$param> {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Bracket::parse_delimited_meta_item(input, ParseMode::Unnamed)
}
#[inline]
fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(inputs: &[S], _mode: ParseMode) -> Result<Self> {
Self::parse_meta_flat_unnamed(inputs, _mode, 0)
}
}
impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaFlatUnnamed for $ty <$param> {
#[inline]
fn field_count() -> Option<usize> {
None
}
fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
_index: usize
) -> Result<Self> {
let mut $ident = Self::new();
let errors = Errors::new();
for input in inputs {
let input = input.borrow();
loop {
if input.is_empty() {
break;
}
match errors.push_result($param::parse_meta_item(input, ParseMode::Unnamed)) {
Some($item) => $push,
None => skip_meta_item(input),
}
if !input.is_empty() {
input.parse::<Token![,]>()?;
}
}
}
errors.check()?;
Ok($ident)
}
}
impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaAppend for $ty <$param> {
fn parse_meta_append<'s, S, I, P>(inputs: &[S], paths: I) -> Result<Self>
where
S: Borrow<ParseBuffer<'s>>,
I: IntoIterator<Item = P>,
I::IntoIter: Clone,
P: AsRef<str>
{
let mut $ident = Self::new();
let errors = Errors::new();
let paths = paths.into_iter();
errors.push_result(parse_struct(inputs, |input, p, pspan| {
if paths.clone().any(|path| path.as_ref() == p) {
match errors.push_result(<_>::parse_meta_item_named(input, p, pspan)) {
Some($item) => $push,
None => skip_meta_item(input),
}
} else {
skip_meta_item(input);
}
Ok(())
}));
errors.check()?;
Ok($ident)
}
}
impl<$param: ToKeyString $(+ $bound $(+ $bounds)*)?> ToKeyString for $ty <$param> {
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char('[')?;
for (i, v) in self.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
v.fmt_key_string(f)?;
}
f.write_char(']')
}
}
};
}
macro_rules! impl_parse_meta_item_set {
($ty:ident <$param:ident $(: $bound:tt $(+ $bounds:tt)*)?>, $ident:ident, $item:ident, $push:expr) => {
impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaItem for $ty <$param> {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Bracket::parse_delimited_meta_item(input, ParseMode::Unnamed)
}
#[inline]
fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(inputs: &[S], _mode: ParseMode) -> Result<Self> {
Self::parse_meta_flat_unnamed(inputs, _mode, 0)
}
}
impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaFlatUnnamed for $ty <$param> {
#[inline]
fn field_count() -> Option<usize> {
None
}
fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
_index: usize
) -> Result<Self> {
let mut $ident = Self::new();
let errors = Errors::new();
for input in inputs {
let input = input.borrow();
loop {
if input.is_empty() {
break;
}
let span = input.span();
match errors.push_result($param::parse_meta_item(input, ParseMode::Unnamed)) {
Some($item) => if !$push {
let span = input.span().join(span).unwrap_or(span);
errors.push(span, "Duplicate key");
},
None => skip_meta_item(input),
}
if !input.is_empty() {
input.parse::<Token![,]>()?;
}
}
}
errors.check()?;
Ok($ident)
}
}
impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaAppend for $ty <$param> {
fn parse_meta_append<'s, S, I, P>(
inputs: &[S],
paths: I,
) -> Result<Self>
where
S: Borrow<ParseBuffer<'s>>,
I: IntoIterator<Item = P>,
I::IntoIter: Clone,
P: AsRef<str>
{
let errors = Errors::new();
let mut $ident = Self::new();
let paths = paths.into_iter();
parse_struct(inputs, |input, p, pspan| {
if paths.clone().any(|path| path.as_ref() == p) {
let span = input.span();
let $item = <_>::parse_meta_item_named(input, p, pspan);
let span = input.span().join(span).unwrap_or(span);
match errors.push_result($item) {
Some($item) => if !$push {
errors.push(span, "Duplicate key");
},
None => skip_meta_item(input),
}
} else {
skip_meta_item(input);
}
Ok(())
})?;
errors.check()?;
Ok($ident)
}
}
impl<$param: ToKeyString $(+ $bound $(+ $bounds)*)?> ToKeyString for $ty <$param> {
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char('[')?;
for (i, v) in self.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
v.fmt_key_string(f)?;
}
f.write_char(']')
}
}
};
}
macro_rules! impl_parse_meta_item_map {
(
$ty:ident <$kp:ident $(: $kbound:tt $(+ $kbounds:tt)*)?, $vp:ident>,
$ident:ident, $key:ident, $value:ident, $push:expr
) => {
impl<$kp, $vp> ParseMetaItem for $ty <$kp, $vp>
where
$kp: ParseMetaItem + ToKeyString $(+ $kbound $(+ $kbounds)*)?,
$vp: ParseMetaItem,
{
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Brace::parse_delimited_meta_item(input, _mode)
}
#[inline]
fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(inputs: &[S], mode: ParseMode) -> Result<Self> {
<Self as ParseMetaFlatUnnamed>::parse_meta_flat_unnamed(inputs, mode, 0)
}
}
impl<$kp, $vp> ParseMetaFlatUnnamed for $ty <$kp, $vp>
where
$kp: ParseMetaItem + ToKeyString $(+ $kbound $(+ $kbounds)*)?,
$vp: ParseMetaItem,
{
#[inline]
fn field_count() -> Option<usize> {
None
}
fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
_index: usize
) -> Result<Self> {
let mut $ident = Self::new();
let errors = Errors::new();
for input in inputs {
let input = input.borrow();
loop {
if input.is_empty() {
break;
}
let start = input.span();
let $key = $kp::parse_meta_item(input, ParseMode::Unnamed)?;
let span = input.span().join(start).unwrap_or(start);
let $value = errors.push_result($key.with_key_string(|ks| {
<_>::parse_meta_item_named(input, &ks, start)
}));
match $value {
Some($value) => if !$push {
errors.push(span, "Duplicate key");
}
None => skip_meta_item(input),
}
if !input.is_empty() {
input.parse::<Token![,]>()?;
}
}
}
errors.check()?;
Ok($ident)
}
}
impl<$kp, $vp> ParseMetaRest for $ty <$kp, $vp>
where
$kp: ParseMetaItem + ToKeyString $(+ $kbound $(+ $kbounds)*)?,
$vp: ParseMetaItem,
{
fn parse_meta_rest<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
exclude: &[&str],
) -> Result<Self> {
let mut $ident = Self::new();
let errors = Errors::new();
for input in inputs {
let input = input.borrow();
loop {
if input.is_empty() {
break;
}
let start = input.span();
let $key = $kp::parse_meta_item(input, ParseMode::Unnamed)?;
let span = input.span().join(start).unwrap_or(start);
let $value = errors.push_result($key.with_key_string(|ks| {
if exclude.contains(&ks) {
skip_meta_item(input);
Ok::<_, crate::Error>(None)
} else {
Ok(Some(<_>::parse_meta_item_named(input, &ks, start)?))
}
})).flatten();
if let Some($value) = $value {
if !$push {
errors.push(span, "Duplicate key");
}
}
if !input.is_empty() {
input.parse::<Token![,]>()?;
}
}
}
errors.check()?;
Ok($ident)
}
}
impl<$kp, $vp> ToKeyString for $ty <$kp, $vp>
where
$kp: ToKeyString $(+ $kbound $(+ $kbounds)*)?,
$vp: ToKeyString,
{
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char('{')?;
for (i, (k, v)) in self.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
k.fmt_key_string(f)?;
f.write_str(" = ")?;
v.fmt_key_string(f)?;
}
f.write_char('}')
}
}
};
}
impl_parse_meta_item_collection!(Vec<T>, v, item, v.push(item));
impl_parse_meta_item_set!(BTreeSet<T: Ord>, set, item, set.insert(item));
impl_parse_meta_item_map!(BTreeMap<K: Ord, V>, map, key, value, map.insert(key, value).is_none());
impl_parse_meta_item_collection!(BinaryHeap<T: Ord>, heap, item, heap.push(item));
impl_parse_meta_item_set!(HashSet<T: Hash + Eq>, set, item, set.insert(item));
impl_parse_meta_item_map!(HashMap<K: Hash + Eq, V>, map, key, value, map.insert(key, value).is_none());
impl_parse_meta_item_collection!(LinkedList<T>, list, item, list.push_back(item));
impl_parse_meta_item_collection!(VecDeque<T>, v, item, v.push_back(item));
macro_rules! impl_parse_meta_item_wrapper {
($i:ident $(::$ip:ident)* <$param:ident>) => {
impl<$param: ParseMetaItem> ParseMetaItem for $i $(::$ip)* <$param> {
#[inline]
fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
Ok(Self::new($param::parse_meta_item(input, mode)?))
}
#[inline]
fn parse_meta_item_flag(span: Span) -> Result<Self> {
$param::parse_meta_item_flag(span).map(Self::new)
}
}
};
}
impl_parse_meta_item_wrapper!(Box<T>);
impl<T: ToKeyString> ToKeyString for Box<T> {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt_key_string(f)
}
#[inline]
fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
(**self).with_key_string(f)
}
}
impl_parse_meta_item_wrapper!(std::rc::Rc<T>);
impl<T: ToKeyString> ToKeyString for std::rc::Rc<T> {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt_key_string(f)
}
#[inline]
fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
(**self).with_key_string(f)
}
}
impl_parse_meta_item_wrapper!(std::cell::Cell<T>);
impl<T: ToKeyString + Copy> ToKeyString for std::cell::Cell<T> {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.get().fmt_key_string(f)
}
#[inline]
fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
self.get().with_key_string(f)
}
}
impl_parse_meta_item_wrapper!(std::cell::RefCell<T>);
impl<T: ToKeyString> ToKeyString for std::cell::RefCell<T> {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.borrow().fmt_key_string(f)
}
#[inline]
fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
self.borrow().with_key_string(f)
}
}
impl<'t, T: ParseMetaItem + Clone> ParseMetaItem for std::borrow::Cow<'t, T> {
#[inline]
fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
Ok(Self::Owned(T::parse_meta_item(input, mode)?))
}
#[inline]
fn parse_meta_item_flag(span: Span) -> Result<Self> {
T::parse_meta_item_flag(span).map(Self::Owned)
}
}
impl<'t, T: ToKeyString + Clone> ToKeyString for std::borrow::Cow<'t, T> {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt_key_string(f)
}
#[inline]
fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
(**self).with_key_string(f)
}
}
impl ParseMetaItem for proc_macro2::TokenTree {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
input.step(|cursor| {
cursor
.token_tree()
.ok_or_else(|| crate::Error::new(cursor.span(), "unexpected end of tokens"))
})
}
}
macro_rules! impl_fmt_key_string_display {
($(#[$attr:meta])* $ty:ty) => {
$(#[$attr])*
impl ToKeyString for $ty {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
};
($ty:ty, #proc_macro) => {
impl_fmt_key_string_display!(
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
$ty
);
};
}
impl_fmt_key_string_display!(proc_macro2::TokenTree);
impl ParseMetaItem for proc_macro2::TokenStream {
#[inline]
fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
if input.peek(Token![,]) {
return Err(syn::Error::new(input.span(), "unexpected comma"));
}
input.step(|cursor| {
let mut cursor = *cursor;
let mut tts = Vec::new();
while let Some((tt, rest)) = cursor.token_tree() {
match tt {
proc_macro2::TokenTree::Punct(p) if p.as_char() == ',' => break,
tt => tts.push(tt),
}
cursor = rest;
}
if tts.is_empty() {
return Err(syn::Error::new(mode.to_span(input), "expected token"));
}
Ok((tts.into_iter().collect(), cursor))
})
}
#[inline]
fn parse_meta_item_flag(_: Span) -> Result<Self> {
Ok(Default::default())
}
#[inline]
fn missing_meta_item(_name: &str, _span: Span) -> Result<Self> {
Ok(Default::default())
}
}
impl ParseMetaFlatUnnamed for proc_macro2::TokenStream {
#[inline]
fn field_count() -> Option<usize> {
None
}
fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
_index: usize,
) -> Result<Self> {
let mut tts = Self::new();
for input in inputs {
let input = input.borrow();
loop {
if input.is_empty() {
break;
}
tts.extend(Self::parse_meta_item(input, ParseMode::Unnamed)?);
}
}
Ok(tts)
}
}
impl_fmt_key_string_display!(proc_macro2::TokenStream);
impl ParseMetaItem for proc_macro2::Literal {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
input.step(|cursor| {
cursor
.literal()
.ok_or_else(|| crate::Error::new(cursor.span(), "expected literal"))
})
}
}
impl_fmt_key_string_display!(proc_macro2::Literal);
impl ParseMetaItem for proc_macro2::Punct {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
input.step(|cursor| {
cursor
.punct()
.ok_or_else(|| crate::Error::new(cursor.span(), "expected punctuation"))
})
}
}
impl_fmt_key_string_display!(proc_macro2::Punct);
impl ParseMetaItem for proc_macro2::Group {
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
input.step(|cursor| {
for delim in {
use proc_macro2::Delimiter::*;
[Parenthesis, Brace, Bracket, None]
} {
if let Some((group, _, cursor)) = cursor.group(delim) {
return Ok((proc_macro2::Group::new(delim, group.token_stream()), cursor));
}
}
Err(crate::Error::new(
cursor.span(),
"expected parenthesis or brace or bracket",
))
})
}
}
#[cfg(feature = "proc-macro")]
#[inline]
fn convert_token_tree(tt: proc_macro2::TokenTree) -> syn::Result<proc_macro::TokenTree> {
#[inline]
fn convert_delimiter(d: proc_macro2::Delimiter) -> proc_macro::Delimiter {
match d {
proc_macro2::Delimiter::Parenthesis => proc_macro::Delimiter::Parenthesis,
proc_macro2::Delimiter::Brace => proc_macro::Delimiter::Brace,
proc_macro2::Delimiter::Bracket => proc_macro::Delimiter::Bracket,
proc_macro2::Delimiter::None => proc_macro::Delimiter::None,
}
}
#[inline]
fn convert_spacing(s: proc_macro2::Spacing) -> proc_macro::Spacing {
match s {
proc_macro2::Spacing::Alone => proc_macro::Spacing::Alone,
proc_macro2::Spacing::Joint => proc_macro::Spacing::Joint,
}
}
Ok(match tt {
proc_macro2::TokenTree::Group(g) => {
proc_macro::Group::new(convert_delimiter(g.delimiter()), g.stream().into()).into()
}
proc_macro2::TokenTree::Ident(i) => {
proc_macro::Ident::new(&i.to_string(), i.span().unwrap()).into()
}
proc_macro2::TokenTree::Punct(p) => {
proc_macro::Punct::new(p.as_char(), convert_spacing(p.spacing())).into()
}
proc_macro2::TokenTree::Literal(l) => l
.to_string()
.parse::<proc_macro::Literal>()
.map(|mut pl| {
pl.set_span(l.span().unwrap());
pl
})
.map_err(|e| syn::Error::new(l.span(), e))?
.into(),
})
}
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
impl ParseMetaItem for proc_macro::TokenTree {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
convert_token_tree(input.parse::<proc_macro2::TokenTree>()?)
}
}
impl_fmt_key_string_display!(proc_macro::TokenTree, #proc_macro);
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
impl ParseMetaItem for proc_macro::TokenStream {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Ok(input.parse::<proc_macro2::TokenStream>()?.into())
}
}
impl_fmt_key_string_display!(proc_macro::TokenStream, #proc_macro);
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
impl ParseMetaItem for proc_macro::Literal {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
match convert_token_tree(proc_macro2::TokenTree::Literal(input.parse()?))? {
proc_macro::TokenTree::Literal(l) => Ok(l),
_ => unreachable!(),
}
}
}
impl_fmt_key_string_display!(proc_macro::Literal, #proc_macro);
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
impl ParseMetaItem for proc_macro::Punct {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
match convert_token_tree(proc_macro2::TokenTree::Punct(input.parse()?))? {
proc_macro::TokenTree::Punct(p) => Ok(p),
_ => unreachable!(),
}
}
}
impl_fmt_key_string_display!(proc_macro::Punct, #proc_macro);
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
impl ParseMetaItem for proc_macro::Group {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
match convert_token_tree(proc_macro2::TokenTree::Group(input.parse()?))? {
proc_macro::TokenTree::Group(g) => Ok(g),
_ => unreachable!(),
}
}
}
impl_fmt_key_string_display!(proc_macro::Group, #proc_macro);
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
impl ParseMetaItem for proc_macro::Ident {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
match convert_token_tree(proc_macro2::TokenTree::Ident(input.parse()?))? {
proc_macro::TokenTree::Ident(i) => Ok(i),
_ => unreachable!(),
}
}
}
impl_fmt_key_string_display!(proc_macro::Ident, #proc_macro);
impl<T: ParseMetaItem, P: Parse + Peek + Default> ParseMetaItem for Punctuated<T, P> {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Bracket::parse_delimited_meta_item(input, ParseMode::Unnamed)
}
#[inline]
fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
) -> Result<Self> {
Self::parse_meta_flat_unnamed(inputs, _mode, 0)
}
}
impl<T: ParseMetaItem, P: Parse + Peek + Default> ParseMetaFlatUnnamed for Punctuated<T, P> {
#[inline]
fn field_count() -> Option<usize> {
None
}
fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
_index: usize,
) -> Result<Self> {
let mut p = Punctuated::new();
let errors = Errors::new();
for input in inputs {
let input = input.borrow();
loop {
if input.is_empty() {
break;
}
match errors.push_result(T::parse_meta_item(input, ParseMode::Unnamed)) {
Some(v) => {
p.push(v);
if !input.is_empty() && errors.push_result(input.parse::<P>()).is_some() {
break;
}
}
None => {
while !input.is_empty() {
if input.peek(P::default()) {
input.parse::<P>()?;
break;
}
input.step(|c| Ok(((), c.token_tree().map(|(_, c)| c).unwrap())))?;
}
}
}
}
}
errors.check()?;
Ok(p)
}
}
impl<T: ToKeyString, P: ToTokens> ToKeyString for Punctuated<T, P> {
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char('[')?;
for p in self.pairs() {
match p {
syn::punctuated::Pair::Punctuated(t, p) => {
t.fmt_key_string(f)?;
p.to_token_stream().fmt_key_string(f)?;
f.write_char(' ')?;
}
syn::punctuated::Pair::End(t) => t.fmt_key_string(f)?,
}
}
f.write_char(']')
}
}
macro_rules! impl_parse_meta_item_syn {
($(#[$attr:meta])* $ty:ty) => {
$(#[$attr])*
impl ParseMetaItem for $ty {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
input.parse()
}
}
$(#[$attr])*
impl ToKeyString for $ty {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_token_stream().fmt_key_string(f)
}
}
};
($ty:ty, #full) => {
impl_parse_meta_item_syn!(
#[cfg(feature = "full")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
$ty
);
};
}
macro_rules! impl_parse_meta_paren_item_syn {
($(#[$attr:meta])* $ty:ty) => {
$(#[$attr])*
impl ParseMetaItem for $ty {
#[inline]
fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
match mode {
ParseMode::Named(_) => {
let content = Paren::parse_delimited(input)?;
let ret = content.parse()?;
content.parse::<Nothing>()?;
Ok(ret)
}
ParseMode::Unnamed => Ok(input.parse()?),
}
}
}
$(#[$attr])*
impl ToKeyString for $ty {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_token_stream().fmt_key_string(f)
}
}
};
($ty:ty, #full) => {
impl_parse_meta_paren_item_syn!(
#[cfg(feature = "full")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
$ty
);
};
}
impl_parse_meta_item_syn!(syn::AngleBracketedGenericArguments);
impl_parse_meta_item_syn!(syn::BareFnArg);
impl_parse_meta_item_syn!(syn::BoundLifetimes);
impl_parse_meta_item_syn!(syn::BinOp);
impl_parse_meta_item_syn!(syn::Expr, #full);
impl_parse_meta_item_syn!(syn::ExprArray, #full);
impl_parse_meta_paren_item_syn!(syn::ExprAssign, #full);
impl_parse_meta_item_syn!(syn::ExprCall, #full);
impl_parse_meta_item_syn!(syn::ExprCast, #full);
impl_parse_meta_item_syn!(syn::ExprField, #full);
impl_parse_meta_item_syn!(syn::ExprIndex, #full);
impl_parse_meta_item_syn!(syn::ExprLit, #full);
impl_parse_meta_item_syn!(syn::ExprMethodCall, #full);
impl_parse_meta_item_syn!(syn::ExprParen, #full);
impl_parse_meta_item_syn!(syn::ExprPath, #full);
impl_parse_meta_item_syn!(syn::ExprRange, #full);
impl_parse_meta_item_syn!(syn::ExprRepeat, #full);
impl_parse_meta_item_syn!(syn::ExprTuple, #full);
impl_parse_meta_item_syn!(syn::FnArg, #full);
impl_parse_meta_item_syn!(syn::GenericParam);
impl ParseMetaItem for syn::Ident {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
syn::ext::IdentExt::parse_any(input)
}
}
impl ToKeyString for syn::Ident {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl_parse_meta_item_syn!(syn::Lifetime);
impl_parse_meta_item_syn!(syn::LifetimeParam);
impl_parse_meta_item_syn!(syn::Lit);
impl_parse_meta_item_syn!(syn::LitStr);
impl_parse_meta_item_syn!(syn::LitByteStr);
impl_parse_meta_item_syn!(syn::LitByte);
impl_parse_meta_item_syn!(syn::LitChar);
impl_parse_meta_item_syn!(syn::LitInt);
impl_parse_meta_item_syn!(syn::LitFloat);
impl_parse_meta_item_syn!(syn::LitBool);
impl_parse_meta_item_syn!(syn::MetaList);
impl_parse_meta_paren_item_syn!(syn::Meta);
impl_parse_meta_paren_item_syn!(syn::MetaNameValue);
#[cfg(feature = "full")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
impl ParseMetaItem for syn::Pat {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
syn::Pat::parse_single(input)
}
}
#[cfg(feature = "full")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
impl ToKeyString for syn::Pat {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_token_stream().fmt_key_string(f)
}
}
impl ParseMetaItem for syn::Path {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
input.parse()
}
}
impl ToKeyString for syn::Path {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, seg) in self.segments.iter().enumerate() {
if i > 0 {
f.write_str("::")?;
}
seg.ident.fmt_key_string(f)?;
if !seg.arguments.is_empty() {
seg.arguments.to_token_stream().fmt_key_string(f)?;
}
}
Ok(())
}
}
impl_parse_meta_item_syn!(syn::PathSegment);
impl_parse_meta_item_syn!(syn::ParenthesizedGenericArguments);
impl_parse_meta_item_syn!(syn::Receiver, #full);
impl_parse_meta_item_syn!(syn::Signature, #full);
impl_parse_meta_item_syn!(syn::TraitBound);
impl_parse_meta_item_syn!(syn::Type);
impl_parse_meta_item_syn!(syn::TypeArray);
impl_parse_meta_item_syn!(syn::TypeBareFn);
impl_parse_meta_item_syn!(syn::TypeImplTrait);
impl_parse_meta_item_syn!(syn::TypePath);
impl_parse_meta_item_syn!(syn::TypePtr);
impl_parse_meta_item_syn!(syn::TypeReference);
impl_parse_meta_item_syn!(syn::TypeSlice);
impl_parse_meta_item_syn!(syn::TypeTraitObject);
impl_parse_meta_item_syn!(syn::TypeTuple);
impl_parse_meta_item_syn!(syn::TypeParamBound);
impl_parse_meta_item_syn!(syn::UseTree, #full);
impl_parse_meta_item_syn!(syn::UnOp);
impl_parse_meta_item_syn!(syn::Visibility);
impl_parse_meta_item_syn!(syn::WherePredicate);
impl ParseMetaItem for () {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
let content = Paren::parse_delimited(input)?;
content.parse::<Nothing>()?;
Ok(())
}
#[inline]
fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
) -> Result<Self> {
for input in inputs {
input.borrow().parse::<Nothing>()?;
}
Ok(())
}
#[inline]
fn parse_meta_item_flag(_: Span) -> Result<Self> {
Ok(())
}
}
impl ToKeyString for () {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("()")
}
#[inline]
fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
f("()")
}
}
macro_rules! impl_parse_meta_item_tuple {
($len:literal: $($index:tt $param:tt $item:ident)+) => {
impl<$($param: ParseMetaItem,)+> ParseMetaItem for ($($param,)+) {
#[inline]
fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
Paren::parse_delimited_meta_item(input, ParseMode::Unnamed)
}
#[inline]
fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(inputs: &[S], _mode: ParseMode) -> Result<Self> {
Self::parse_meta_flat_unnamed(inputs, _mode, 0)
}
}
impl<$($param: ParseMetaItem,)+> ParseMetaFlatUnnamed for ($($param,)+) {
#[inline]
fn field_count() -> Option<usize> {
Some($len)
}
fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
inputs: &[S],
_mode: ParseMode,
_index: usize
) -> Result<Self> {
$(let mut $item = FieldStatus::None;)+
let errors = Errors::new();
errors.push_result(parse_tuple_struct(inputs, $len, |stream, _, index| {
match index {
$($index => $item.parse_unnamed_item(stream, &errors),)+
_ => unreachable!(),
}
Ok(())
}));
$(if $item.is_none() {
errors.push(
inputs_span(inputs),
format!("Expected tuple of length {}, got {}", $len, $index),
);
return errors.bail();
};)+
errors.check()?;
$(let $item = $item.unwrap_or_else(|| unreachable!());)+
Ok(($($item,)+))
}
}
impl<$($param: ToKeyString,)+> ToKeyString for ($($param,)+) {
#[inline]
fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char('(')?;
$(
impl_parse_meta_item_tuple!(@push_comma f, $index);
self.$index.fmt_key_string(f)?;
)+
f.write_char(')')
}
}
};
(@push_comma $f:ident, 0) => { };
(@push_comma $f:ident, $index:literal) => { $f.write_str(", ")?; };
}
impl_parse_meta_item_tuple!(1: 0 T0 t0);
impl_parse_meta_item_tuple!(2: 0 T0 t0 1 T1 t1);
impl_parse_meta_item_tuple!(3: 0 T0 t0 1 T1 t1 2 T2 t2);
impl_parse_meta_item_tuple!(4: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3);
impl_parse_meta_item_tuple!(5: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4);
impl_parse_meta_item_tuple!(6: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5);
impl_parse_meta_item_tuple!(7: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5 6 T6 t6);
impl_parse_meta_item_tuple!(8: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5 6 T6 t6 7 T7 t7);
impl_parse_meta_item_tuple!(9: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5 6 T6 t6 7 T7 t7 8 T8 t8);
impl_parse_meta_item_tuple!(10: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5 6 T6 t6 7 T7 t7 8 T8 t8 9 T9 t9);
impl_parse_meta_item_tuple!(11: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5 6 T6 t6 7 T7 t7 8 T8 t8 9 T9 t9 10 T10 t10);
impl_parse_meta_item_tuple!(12: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5 6 T6 t6 7 T7 t7 8 T8 t8 9 T9 t9 10 T10 t10 11 T11 t11);
impl_parse_meta_item_tuple!(13: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5 6 T6 t6 7 T7 t7 8 T8 t8 9 T9 t9 10 T10 t10 11 T11 t11 12 T12 t12);
impl_parse_meta_item_tuple!(14: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5 6 T6 t6 7 T7 t7 8 T8 t8 9 T9 t9 10 T10 t10 11 T11 t11 12 T12 t12 13 T13 t13);
impl_parse_meta_item_tuple!(15: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5 6 T6 t6 7 T7 t7 8 T8 t8 9 T9 t9 10 T10 t10 11 T11 t11 12 T12 t12 13 T13 t13 14 T14 t14);
impl_parse_meta_item_tuple!(16: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5 6 T6 t6 7 T7 t7 8 T8 t8 9 T9 t9 10 T10 t10 11 T11 t11 12 T12 t12 13 T13 t13 14 T14 t14 15 T15 t15);