deluxe_core/
parse_meta.rs

1use crate::{parse_helpers::*, Errors, Result};
2use proc_macro2::Span;
3use quote::ToTokens;
4use std::{
5    borrow::Borrow,
6    collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
7    fmt::{self, Write},
8    hash::Hash,
9};
10use syn::{
11    parse::{Nothing, Parse, ParseBuffer, ParseStream, Peek},
12    punctuated::Punctuated,
13    Token,
14};
15
16/// The context a meta item parser is operating in.
17#[derive(Debug, Clone, Copy)]
18pub enum ParseMode {
19    /// Named context, corresponding to [`syn::FieldsNamed`].
20    ///
21    /// Contains the [`Span`](proc_macro2::Span) of the name tokens.
22    Named(Span),
23    /// Unnamed context, corresponding to [`syn::FieldsUnnamed`].
24    Unnamed,
25}
26
27impl ParseMode {
28    /// Converts `self` to a [`Self::Named`].
29    ///
30    /// If `self` is [`Unnamed`](Self::Unnamed), uses the [`Span`](proc_macro2::Span) from `input`.
31    #[inline]
32    pub fn to_named(&self, input: ParseStream) -> Self {
33        match self {
34            Self::Unnamed => Self::Named(input.span()),
35            m => *m,
36        }
37    }
38    /// Gets the stored [`Span`](proc_macro2::Span).
39    ///
40    /// If `self` is [`Unnamed`](Self::Unnamed), returns [`None`].
41    #[inline]
42    pub fn named_span(&self) -> Option<Span> {
43        match self {
44            Self::Named(s) => Some(*s),
45            _ => None,
46        }
47    }
48    /// Gets the stored [`Span`](proc_macro2::Span).
49    ///
50    /// If `self` is [`Unnamed`](Self::Unnamed), returns the [`Span`](proc_macro2::Span) from
51    /// `input`.
52    #[inline]
53    pub fn to_span(&self, input: ParseStream) -> Span {
54        self.named_span().unwrap_or_else(|| input.span())
55    }
56    /// Gets the stored [`Span`](proc_macro2::Span).
57    ///
58    /// If `self` is [`Unnamed`](Self::Unnamed), returns <code>[inputs_span]\(inputs)</code>.
59    #[inline]
60    pub fn to_full_span<'s, S: Borrow<ParseBuffer<'s>>>(&self, inputs: &[S]) -> Span {
61        self.named_span().unwrap_or_else(|| inputs_span(inputs))
62    }
63}
64
65/// Base trait for parsing a single field out of [`syn::parse::ParseStream`].
66///
67/// This trait is conceptually similar to [`syn::parse::Parse`], but with a few key differences:
68/// - It can tell when an item is being parsed from a tuple struct or a struct with named fields.
69/// - It can be parsed "inline" by containers that consume the surrounding delimiters.
70/// - It can be parsed as a "flag" by containers that allow empty fields.
71/// - It can provide custom parsing when it is used with a named attribute.
72///
73/// Implementations are provided for all [primitives](std::primitive) and [standard
74/// collections](std::collections), as well as for tuples, arrays, and for most parseable
75/// node structures in [`syn`].
76pub trait ParseMetaItem: Sized {
77    /// Parse the item from the tokens in `input`.
78    ///
79    /// If the item can contain commas, the whole item should be wrapped in a pair of delimiters.
80    /// The stream should should not parse any trailing commas or additional tokens past the end of
81    /// the item.
82    ///
83    /// The `_mode` argument describes whether this item is being parsed in a named or an unnamed
84    /// context. This argument will rarely be used. It only should be checked when an item uses
85    /// [`Self::parse_meta_item_flag`] to provide shorthand for a default enum value, and wants to
86    /// avoid parsing it in a named context. In an unnamed context, both values will still need to
87    /// be parsed. See the source to the
88    /// [implementation](ParseMetaItem#impl-ParseMetaItem-for-Option<T>) of this trait on
89    /// <code>[Option]&lt;T></code> for an example of when to check `_mode`.
90    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self>;
91    /// Parse the item in an inline context.
92    ///
93    /// The stream can consume any number of commas. Items with a finite length should not consume
94    /// a trailing comma. See [`Self::parse_meta_item`] for a description of the `_mode` argument.
95    ///
96    /// This function should be implemented for custom data structures, but is not intended to be
97    /// called by a parser of a structure containing it as a field. Instead, the custom data
98    /// structure should implement [`ParseMetaFlatUnnamed::parse_meta_flat_unnamed`],
99    /// [`ParseMetaFlatNamed::parse_meta_flat_named`], or
100    /// [`ParseMetaRest::parse_meta_rest`]. Then, the implementation of this
101    /// function should delegate to one of those methods.
102    ///
103    /// The default implementation directly calls [`Self::parse_meta_item`].
104    #[inline]
105    fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(
106        inputs: &[S],
107        _mode: ParseMode,
108    ) -> Result<Self> {
109        parse_first(inputs, _mode, Self::parse_meta_item)
110    }
111    /// Parses an empty flag value.
112    ///
113    /// Only called when parsing a struct with named fields, with no value given after the field
114    /// name. `_span` is the span of the token following the name.
115    ///
116    /// The default implementation returns an error.
117    #[inline]
118    fn parse_meta_item_flag(_span: Span) -> Result<Self> {
119        Err(flag_disallowed_error(_span))
120    }
121    /// Parses the item following a name.
122    ///
123    /// Only called when parsing a struct with named fields. Normally implementations will not need
124    /// to override this method.
125    ///
126    /// The default implementation simply calls
127    /// [`parse_helpers::parse_named_meta_item`](crate::parse_helpers::parse_named_meta_item).
128    #[inline]
129    fn parse_meta_item_named(input: ParseStream, _name: &str, span: Span) -> Result<Self> {
130        parse_named_meta_item(input, span)
131    }
132    /// Fallback for when a required item is missing.
133    ///
134    /// Only called when a required (non-default) field was omitted from a parsed attribute.
135    /// Implementations on types that implement [`Default`] will most likely want to return
136    /// <code>[Ok]\([Default::default]\(\)\)</code> here.
137    ///
138    /// The default implementation returns an error.
139    #[inline]
140    fn missing_meta_item(name: &str, span: Span) -> Result<Self> {
141        Err(missing_field_error(name, span))
142    }
143}
144
145/// Parses a meta item for a structure with unnamed fields.
146///
147/// Automatically implemented by `derive(ParseMetaItem)` for tuple
148/// structures, but can also be manually implemented for array-like types.
149///
150/// A parent structure that wants to flatten items of this type into its own fields should call
151/// [`Self::parse_meta_flat_unnamed`].
152pub trait ParseMetaFlatUnnamed: Sized {
153    /// Returns the number of fields in this structure.
154    ///
155    /// Returns [`None`] if it can parse any number of fields.
156    ///
157    /// Currently, this is only useful when generating error messages.
158    fn field_count() -> Option<usize>;
159    /// Parse the item from a group of inline contexts.
160    ///
161    /// The streams can consume any number of commas. The streams in `inputs` should not be
162    /// considered contiguous, but should imply a trailing comma if one is not present.
163    /// Implementations should parse each stream in order, continuing to the next stream when the
164    /// current one is exhausted.
165    ///
166    /// If the structure can take any number of fields, it should parse all streams to the end and
167    /// ensure that a traiing comma is parsed.
168    ///
169    /// If the structure contains a finite number of fields, then trailing comma should not be
170    /// consumed. Once all fields are parsed, the function should return, without any further
171    /// modifications to the current stream or any following streams.
172    ///
173    /// `index` is the starting offset into the currently parsing tuple. It should be used as a
174    /// base when generating error messages.
175    fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
176        inputs: &[S],
177        _mode: ParseMode,
178        index: usize,
179    ) -> Result<Self>;
180}
181
182/// Parses a meta item for a structure with named fields.
183///
184/// Automatically implemented by `derive(ParseMetaItem)` for structures with named fields, and for
185/// enums.
186///
187/// A parent structure that wants to flatten items of this type into its own fields should call
188/// [`Self::parse_meta_flat_named`].
189pub trait ParseMetaFlatNamed: Sized {
190    /// Returns an array specifying all optional and required fields accepted by this structure.
191    fn field_names() -> &'static [&'static str];
192    /// Parse the item from a group of inline named contexts.
193    ///
194    /// The streams can consume any number of commas. The streams in `inputs` should not be
195    /// considered contiguous, but should imply a trailing comma if one is not present.
196    /// Implementations should parse each stream in order, continuing to the next stream when the
197    /// current one is exhausted.
198    ///
199    /// All streams should be parsed to the end, skipping over unknown fields, and consuming a
200    /// trailing comma if present. The [`crate::parse_helpers::parse_struct`] helper should be used
201    /// for convenience. `prefix` should be stripped off the names of all fields before pattern
202    /// matching on them.
203    ///
204    /// If `validate` is true, then an error should be generated upon encountering any
205    /// fields not in [`Self::field_names`].
206    fn parse_meta_flat_named<'s, S: Borrow<ParseBuffer<'s>>>(
207        inputs: &[S],
208        _mode: ParseMode,
209        prefix: &str,
210        validate: bool,
211    ) -> Result<Self>;
212    /// A flag noting if this parser will consume all unknown fields.
213    ///
214    /// Should be set to `true` only for structures containing a `#[deluxe(rest)]` field.
215    const ACCEPTS_ALL: bool = false;
216}
217
218/// Parses a meta item for a structure with named fields that concatenates all matching items.
219///
220/// Should be implemented on collection types. Implementations are provided for the common
221/// collection types in [`std`].
222pub trait ParseMetaAppend: Sized {
223    /// Parse the item from a group of inline named contexts.
224    ///
225    /// Fields with names matching any path in `paths` will be appended. Non-matching fields should
226    /// be skipped with [`crate::parse_helpers::skip_meta_item`].
227    fn parse_meta_append<'s, S, I, P>(inputs: &[S], paths: I) -> Result<Self>
228    where
229        S: Borrow<ParseBuffer<'s>>,
230        I: IntoIterator<Item = P>,
231        I::IntoIter: Clone,
232        P: AsRef<str>;
233}
234
235/// Parses a meta item for a structure with named fields that consumes all fields.
236///
237/// Should be implemented on map types. Implementations are provided for the common map types in
238/// [`std`].
239pub trait ParseMetaRest: Sized {
240    /// Parse the item from a group of inline named contexts.
241    ///
242    /// Fields with names in `exclude` should be should be skipped with
243    /// [`crate::parse_helpers::skip_meta_item`].
244    fn parse_meta_rest<'s, S: Borrow<ParseBuffer<'s>>>(
245        inputs: &[S],
246        exclude: &[&str],
247    ) -> Result<Self>;
248}
249
250/// A trait for converting an attribute key to a string.
251///
252/// Used for performing path comparisons and for constructing error messages when using arbitrary
253/// types as attribute keys. Currently only used by the [`ParseMetaItem`] implementations for
254/// [`BTreeMap`] and [`HashMap`].
255pub trait ToKeyString: Sized {
256    /// Formats the given value as a key string.
257    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result;
258    /// Runs function `f` with the key converted to a `&str`.
259    ///
260    /// Can be specialized by values that can pass a cheaply borrowed `&str`. The default
261    /// implementation calls `f` with the result from [`key_to_string`].
262    fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
263        f(&key_to_string(self))
264    }
265}
266
267macro_rules! impl_parse_meta_item_primitive {
268    ($ty:ty, $lit:ty, $conv:ident) => {
269        impl ParseMetaItem for $ty {
270            #[inline]
271            fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
272                impl_parse_meta_item_primitive!(@conv input, _mode, $lit, $conv)
273            }
274        }
275        impl ToKeyString for $ty {
276            #[inline]
277            fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
278                fmt::Display::fmt(self, f)
279            }
280        }
281    };
282    (@conv $input:ident, $mode:ident, $lit:ty, base10_parse) => {
283        $input.parse::<$lit>()?.base10_parse()
284    };
285    (@conv $input:ident, $mode:ident, $lit:ty, value) => {
286        Ok($input.parse::<$lit>()?.value())
287    };
288    (@conv $input:ident, $mode:ident, $lit:ty, from_str) => {
289        $crate::with::from_str::parse_meta_item($input, $mode)
290    };
291}
292
293impl_parse_meta_item_primitive!(i8, syn::LitInt, base10_parse);
294impl_parse_meta_item_primitive!(i16, syn::LitInt, base10_parse);
295impl_parse_meta_item_primitive!(i32, syn::LitInt, base10_parse);
296impl_parse_meta_item_primitive!(i64, syn::LitInt, base10_parse);
297impl_parse_meta_item_primitive!(i128, syn::LitInt, base10_parse);
298impl_parse_meta_item_primitive!(isize, syn::LitInt, base10_parse);
299
300impl ParseMetaItem for u8 {
301    #[inline]
302    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
303        let lookahead = input.lookahead1();
304        if lookahead.peek(syn::LitByte) {
305            Ok(input.parse::<syn::LitByte>()?.value())
306        } else if lookahead.peek(syn::LitInt) {
307            Ok(input.parse::<syn::LitInt>()?.base10_parse()?)
308        } else {
309            Err(lookahead.error())
310        }
311    }
312}
313
314impl_parse_meta_item_primitive!(u16, syn::LitInt, base10_parse);
315impl_parse_meta_item_primitive!(u32, syn::LitInt, base10_parse);
316impl_parse_meta_item_primitive!(u64, syn::LitInt, base10_parse);
317impl_parse_meta_item_primitive!(u128, syn::LitInt, base10_parse);
318impl_parse_meta_item_primitive!(usize, syn::LitInt, base10_parse);
319
320impl_parse_meta_item_primitive!(f32, syn::LitFloat, base10_parse);
321impl_parse_meta_item_primitive!(f64, syn::LitFloat, base10_parse);
322
323impl ParseMetaItem for bool {
324    #[inline]
325    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
326        Ok(input.parse::<syn::LitBool>()?.value())
327    }
328    #[inline]
329    fn parse_meta_item_flag(_: Span) -> Result<Self> {
330        Ok(true)
331    }
332}
333
334impl_parse_meta_item_primitive!(std::num::NonZeroI8, syn::LitInt, base10_parse);
335impl_parse_meta_item_primitive!(std::num::NonZeroI16, syn::LitInt, base10_parse);
336impl_parse_meta_item_primitive!(std::num::NonZeroI32, syn::LitInt, base10_parse);
337impl_parse_meta_item_primitive!(std::num::NonZeroI64, syn::LitInt, base10_parse);
338impl_parse_meta_item_primitive!(std::num::NonZeroI128, syn::LitInt, base10_parse);
339impl_parse_meta_item_primitive!(std::num::NonZeroIsize, syn::LitInt, base10_parse);
340
341impl_parse_meta_item_primitive!(std::num::NonZeroU8, syn::LitInt, base10_parse);
342impl_parse_meta_item_primitive!(std::num::NonZeroU16, syn::LitInt, base10_parse);
343impl_parse_meta_item_primitive!(std::num::NonZeroU32, syn::LitInt, base10_parse);
344impl_parse_meta_item_primitive!(std::num::NonZeroU64, syn::LitInt, base10_parse);
345impl_parse_meta_item_primitive!(std::num::NonZeroU128, syn::LitInt, base10_parse);
346impl_parse_meta_item_primitive!(std::num::NonZeroUsize, syn::LitInt, base10_parse);
347
348impl_parse_meta_item_primitive!(char, syn::LitChar, value);
349
350impl ParseMetaItem for String {
351    #[inline]
352    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
353        Ok(input.parse::<syn::LitStr>()?.value())
354    }
355}
356
357impl ToKeyString for String {
358    #[inline]
359    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
360        fmt::Display::fmt(self, f)
361    }
362    #[inline]
363    fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
364        f(self)
365    }
366}
367
368impl ParseMetaItem for std::path::PathBuf {
369    #[inline]
370    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
371        Ok(Self::from(input.parse::<syn::LitStr>()?.value()))
372    }
373}
374
375impl ToKeyString for std::path::PathBuf {
376    #[inline]
377    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
378        f.write_str(&self.to_string_lossy())
379    }
380    #[inline]
381    fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
382        f(&self.to_string_lossy())
383    }
384}
385
386impl ParseMetaItem for std::ffi::OsString {
387    #[inline]
388    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
389        Ok(Self::from(input.parse::<syn::LitStr>()?.value()))
390    }
391}
392
393impl ToKeyString for std::ffi::OsString {
394    #[inline]
395    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
396        f.write_str(&self.to_string_lossy())
397    }
398    #[inline]
399    fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
400        f(&self.to_string_lossy())
401    }
402}
403
404impl_parse_meta_item_primitive!(std::net::IpAddr, syn::LitStr, from_str);
405impl_parse_meta_item_primitive!(std::net::Ipv4Addr, syn::LitStr, from_str);
406impl_parse_meta_item_primitive!(std::net::Ipv6Addr, syn::LitStr, from_str);
407impl_parse_meta_item_primitive!(std::net::SocketAddr, syn::LitStr, from_str);
408impl_parse_meta_item_primitive!(std::net::SocketAddrV4, syn::LitStr, from_str);
409impl_parse_meta_item_primitive!(std::net::SocketAddrV6, syn::LitStr, from_str);
410
411impl<T: ParseMetaItem> ParseMetaItem for Option<T> {
412    #[inline]
413    fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
414        match mode {
415            ParseMode::Named(_) => T::parse_meta_item(input, mode).map(Some),
416            ParseMode::Unnamed => {
417                mod keywords {
418                    syn::custom_keyword!(Some);
419                    syn::custom_keyword!(None);
420                }
421                let lookahead = input.lookahead1();
422                if lookahead.peek(keywords::Some) {
423                    input.parse::<keywords::Some>()?;
424                    Paren::parse_delimited_meta_item(input, mode).map(Some)
425                } else if lookahead.peek(keywords::None) {
426                    input.parse::<keywords::None>()?;
427                    Ok(None)
428                } else {
429                    Err(lookahead.error())
430                }
431            }
432        }
433    }
434    #[inline]
435    fn parse_meta_item_flag(span: Span) -> Result<Self> {
436        T::parse_meta_item_flag(span).map(Some)
437    }
438    #[inline]
439    fn missing_meta_item(_name: &str, _span: Span) -> Result<Self> {
440        Ok(None)
441    }
442}
443
444impl<T: ToKeyString> ToKeyString for Option<T> {
445    #[inline]
446    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
447        match self {
448            Some(v) => {
449                f.write_str("Some(")?;
450                v.fmt_key_string(f)?;
451                f.write_char(')')
452            }
453            None => f.write_str("None"),
454        }
455    }
456}
457
458impl<T: ParseMetaItem, const N: usize> ParseMetaItem for [T; N] {
459    #[inline]
460    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
461        Bracket::parse_delimited_meta_item(input, ParseMode::Unnamed)
462    }
463    #[inline]
464    fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(
465        inputs: &[S],
466        _mode: ParseMode,
467    ) -> Result<Self> {
468        Self::parse_meta_flat_unnamed(inputs, _mode, 0)
469    }
470}
471
472impl<T: ParseMetaItem, const N: usize> ParseMetaFlatUnnamed for [T; N] {
473    #[inline]
474    fn field_count() -> Option<usize> {
475        Some(N)
476    }
477    fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
478        inputs: &[S],
479        _mode: ParseMode,
480        index: usize,
481    ) -> Result<Self> {
482        let mut a = arrayvec::ArrayVec::<T, N>::new();
483        let errors = Errors::new();
484        let mut failed = 0;
485        errors.push_result(parse_tuple_struct(inputs, N, |stream, _, _| {
486            match errors.push_result(T::parse_meta_item(stream, ParseMode::Unnamed)) {
487                Some(v) => a.push(v),
488                None => {
489                    failed += 1;
490                    skip_meta_item(stream);
491                }
492            }
493            Ok(())
494        }));
495        if a.len() + failed != N {
496            errors.push(
497                inputs_span(inputs),
498                format!(
499                    "Expected array at index {} of length {}, got {}",
500                    index,
501                    N,
502                    a.len() + failed,
503                ),
504            );
505        }
506        errors.check()?;
507        Ok(a.into_inner().unwrap_or_else(|_| unreachable!()))
508    }
509}
510
511impl<T: ToKeyString, const N: usize> ToKeyString for [T; N] {
512    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
513        f.write_char('[')?;
514        for (i, v) in self.iter().enumerate() {
515            if i > 0 {
516                f.write_str(", ")?;
517            }
518            v.fmt_key_string(f)?;
519        }
520        f.write_char(']')
521    }
522}
523
524macro_rules! impl_parse_meta_item_collection {
525    ($ty:ident <$param:ident $(: $bound:tt $(+ $bounds:tt)*)?>, $ident:ident, $item:ident, $push:expr) => {
526        impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaItem for $ty <$param> {
527            #[inline]
528            fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
529                Bracket::parse_delimited_meta_item(input, ParseMode::Unnamed)
530            }
531            #[inline]
532            fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(inputs: &[S], _mode: ParseMode) -> Result<Self> {
533                Self::parse_meta_flat_unnamed(inputs, _mode, 0)
534            }
535        }
536
537        impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaFlatUnnamed for $ty <$param> {
538            #[inline]
539            fn field_count() -> Option<usize> {
540                None
541            }
542            fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
543                inputs: &[S],
544                _mode: ParseMode,
545                _index: usize
546            ) -> Result<Self> {
547                let mut $ident = Self::new();
548                let errors = Errors::new();
549                for input in inputs {
550                    let input = input.borrow();
551                    loop {
552                        if input.is_empty() {
553                            break;
554                        }
555                        match errors.push_result($param::parse_meta_item(input, ParseMode::Unnamed)) {
556                            Some($item) => $push,
557                            None => skip_meta_item(input),
558                        }
559                        if !input.is_empty() {
560                            input.parse::<Token![,]>()?;
561                        }
562                    }
563                }
564                errors.check()?;
565                Ok($ident)
566            }
567        }
568
569        impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaAppend for $ty <$param> {
570            fn parse_meta_append<'s, S, I, P>(inputs: &[S], paths: I) -> Result<Self>
571            where
572                S: Borrow<ParseBuffer<'s>>,
573                I: IntoIterator<Item = P>,
574                I::IntoIter: Clone,
575                P: AsRef<str>
576            {
577                let mut $ident = Self::new();
578                let errors = Errors::new();
579                let paths = paths.into_iter();
580                errors.push_result(parse_struct(inputs, |input, p, pspan| {
581                    if paths.clone().any(|path| path.as_ref() == p) {
582                        match errors.push_result(<_>::parse_meta_item_named(input, p, pspan)) {
583                            Some($item) => $push,
584                            None => skip_meta_item(input),
585                        }
586                    } else {
587                        skip_meta_item(input);
588                    }
589                    Ok(())
590                }));
591                errors.check()?;
592                Ok($ident)
593            }
594        }
595
596        impl<$param: ToKeyString $(+ $bound $(+ $bounds)*)?> ToKeyString for $ty <$param> {
597            fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
598                f.write_char('[')?;
599                for (i, v) in self.iter().enumerate() {
600                    if i > 0 {
601                        f.write_str(", ")?;
602                    }
603                    v.fmt_key_string(f)?;
604                }
605                f.write_char(']')
606            }
607        }
608    };
609}
610
611macro_rules! impl_parse_meta_item_set {
612    ($ty:ident <$param:ident $(: $bound:tt $(+ $bounds:tt)*)?>, $ident:ident, $item:ident, $push:expr) => {
613        impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaItem for $ty <$param> {
614            #[inline]
615            fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
616                Bracket::parse_delimited_meta_item(input, ParseMode::Unnamed)
617            }
618            #[inline]
619            fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(inputs: &[S], _mode: ParseMode) -> Result<Self> {
620                Self::parse_meta_flat_unnamed(inputs, _mode, 0)
621            }
622        }
623
624        impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaFlatUnnamed for $ty <$param> {
625            #[inline]
626            fn field_count() -> Option<usize> {
627                None
628            }
629            fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
630                inputs: &[S],
631                _mode: ParseMode,
632                _index: usize
633            ) -> Result<Self> {
634                let mut $ident = Self::new();
635                let errors = Errors::new();
636                for input in inputs {
637                    let input = input.borrow();
638                    loop {
639                        if input.is_empty() {
640                            break;
641                        }
642                        let span = input.span();
643                        match errors.push_result($param::parse_meta_item(input, ParseMode::Unnamed)) {
644                            Some($item) => if !$push {
645                                let span = input.span().join(span).unwrap_or(span);
646                                errors.push(span, "Duplicate key");
647                            },
648                            None => skip_meta_item(input),
649                        }
650                        if !input.is_empty() {
651                            input.parse::<Token![,]>()?;
652                        }
653                    }
654                }
655                errors.check()?;
656                Ok($ident)
657            }
658        }
659
660        impl<$param: ParseMetaItem $(+ $bound $(+ $bounds)*)?> ParseMetaAppend for $ty <$param> {
661            fn parse_meta_append<'s, S, I, P>(
662                inputs: &[S],
663                paths: I,
664            ) -> Result<Self>
665            where
666                S: Borrow<ParseBuffer<'s>>,
667                I: IntoIterator<Item = P>,
668                I::IntoIter: Clone,
669                P: AsRef<str>
670            {
671                let errors = Errors::new();
672                let mut $ident = Self::new();
673                let paths = paths.into_iter();
674                parse_struct(inputs, |input, p, pspan| {
675                    if paths.clone().any(|path| path.as_ref() == p) {
676                        let span = input.span();
677                        let $item = <_>::parse_meta_item_named(input, p, pspan);
678                        let span = input.span().join(span).unwrap_or(span);
679                        match errors.push_result($item) {
680                            Some($item) => if !$push {
681                                errors.push(span, "Duplicate key");
682                            },
683                            None => skip_meta_item(input),
684                        }
685                    } else {
686                        skip_meta_item(input);
687                    }
688                    Ok(())
689                })?;
690                errors.check()?;
691                Ok($ident)
692            }
693        }
694
695        impl<$param: ToKeyString $(+ $bound $(+ $bounds)*)?> ToKeyString for $ty <$param> {
696            fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
697                f.write_char('[')?;
698                for (i, v) in self.iter().enumerate() {
699                    if i > 0 {
700                        f.write_str(", ")?;
701                    }
702                    v.fmt_key_string(f)?;
703                }
704                f.write_char(']')
705            }
706        }
707    };
708}
709
710macro_rules! impl_parse_meta_item_map {
711    (
712        $ty:ident <$kp:ident $(: $kbound:tt $(+ $kbounds:tt)*)?, $vp:ident>,
713        $ident:ident, $key:ident, $value:ident, $push:expr
714    ) => {
715        impl<$kp, $vp> ParseMetaItem for $ty <$kp, $vp>
716        where
717            $kp: ParseMetaItem + ToKeyString $(+ $kbound $(+ $kbounds)*)?,
718            $vp: ParseMetaItem,
719        {
720            #[inline]
721            fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
722                Brace::parse_delimited_meta_item(input, _mode)
723            }
724            #[inline]
725            fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(inputs: &[S], mode: ParseMode) -> Result<Self> {
726                <Self as ParseMetaFlatUnnamed>::parse_meta_flat_unnamed(inputs, mode, 0)
727            }
728        }
729
730        impl<$kp, $vp> ParseMetaFlatUnnamed for $ty <$kp, $vp>
731        where
732            $kp: ParseMetaItem + ToKeyString $(+ $kbound $(+ $kbounds)*)?,
733            $vp: ParseMetaItem,
734        {
735            #[inline]
736            fn field_count() -> Option<usize> {
737                None
738            }
739            fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
740                inputs: &[S],
741                _mode: ParseMode,
742                _index: usize
743            ) -> Result<Self> {
744                let mut $ident = Self::new();
745                let errors = Errors::new();
746                for input in inputs {
747                    let input = input.borrow();
748                    loop {
749                        if input.is_empty() {
750                            break;
751                        }
752                        let start = input.span();
753                        let $key = $kp::parse_meta_item(input, ParseMode::Unnamed)?;
754                        let span = input.span().join(start).unwrap_or(start);
755                        let $value = errors.push_result($key.with_key_string(|ks| {
756                            <_>::parse_meta_item_named(input, &ks, start)
757                        }));
758                        match $value {
759                            Some($value) => if !$push {
760                                errors.push(span, "Duplicate key");
761                            }
762                            None => skip_meta_item(input),
763                        }
764                        if !input.is_empty() {
765                            input.parse::<Token![,]>()?;
766                        }
767                    }
768                }
769                errors.check()?;
770                Ok($ident)
771            }
772        }
773
774        impl<$kp, $vp> ParseMetaRest for $ty <$kp, $vp>
775        where
776            $kp: ParseMetaItem + ToKeyString $(+ $kbound $(+ $kbounds)*)?,
777            $vp: ParseMetaItem,
778        {
779            fn parse_meta_rest<'s, S: Borrow<ParseBuffer<'s>>>(
780                inputs: &[S],
781                exclude: &[&str],
782            ) -> Result<Self> {
783                let mut $ident = Self::new();
784                let errors = Errors::new();
785                for input in inputs {
786                    let input = input.borrow();
787                    loop {
788                        if input.is_empty() {
789                            break;
790                        }
791                        let start = input.span();
792                        let $key = $kp::parse_meta_item(input, ParseMode::Unnamed)?;
793                        let span = input.span().join(start).unwrap_or(start);
794                        let $value = errors.push_result($key.with_key_string(|ks| {
795                            if exclude.contains(&ks) {
796                                skip_meta_item(input);
797                                Ok::<_, crate::Error>(None)
798                            } else {
799                                Ok(Some(<_>::parse_meta_item_named(input, &ks, start)?))
800                            }
801                        })).flatten();
802                        if let Some($value) = $value {
803                            if !$push {
804                                errors.push(span, "Duplicate key");
805                            }
806                        }
807                        if !input.is_empty() {
808                            input.parse::<Token![,]>()?;
809                        }
810                    }
811                }
812                errors.check()?;
813                Ok($ident)
814            }
815        }
816
817        impl<$kp, $vp> ToKeyString for $ty <$kp, $vp>
818        where
819            $kp: ToKeyString $(+ $kbound $(+ $kbounds)*)?,
820            $vp: ToKeyString,
821        {
822            fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
823                f.write_char('{')?;
824                for (i, (k, v)) in self.iter().enumerate() {
825                    if i > 0 {
826                        f.write_str(", ")?;
827                    }
828                    k.fmt_key_string(f)?;
829                    f.write_str(" = ")?;
830                    v.fmt_key_string(f)?;
831                }
832                f.write_char('}')
833            }
834        }
835    };
836}
837
838impl_parse_meta_item_collection!(Vec<T>, v, item, v.push(item));
839impl_parse_meta_item_set!(BTreeSet<T: Ord>, set, item, set.insert(item));
840impl_parse_meta_item_map!(BTreeMap<K: Ord, V>, map, key, value, map.insert(key, value).is_none());
841impl_parse_meta_item_collection!(BinaryHeap<T: Ord>, heap, item, heap.push(item));
842impl_parse_meta_item_set!(HashSet<T: Hash + Eq>, set, item, set.insert(item));
843impl_parse_meta_item_map!(HashMap<K: Hash + Eq, V>, map, key, value, map.insert(key, value).is_none());
844impl_parse_meta_item_collection!(LinkedList<T>, list, item, list.push_back(item));
845impl_parse_meta_item_collection!(VecDeque<T>, v, item, v.push_back(item));
846
847macro_rules! impl_parse_meta_item_wrapper {
848    ($i:ident $(::$ip:ident)* <$param:ident>) => {
849        impl<$param: ParseMetaItem> ParseMetaItem for $i $(::$ip)* <$param> {
850            #[inline]
851            fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
852                Ok(Self::new($param::parse_meta_item(input, mode)?))
853            }
854            #[inline]
855            fn parse_meta_item_flag(span: Span) -> Result<Self> {
856                $param::parse_meta_item_flag(span).map(Self::new)
857            }
858        }
859    };
860}
861
862impl_parse_meta_item_wrapper!(Box<T>);
863
864impl<T: ToKeyString> ToKeyString for Box<T> {
865    #[inline]
866    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
867        (**self).fmt_key_string(f)
868    }
869    #[inline]
870    fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
871        (**self).with_key_string(f)
872    }
873}
874
875impl_parse_meta_item_wrapper!(std::rc::Rc<T>);
876
877impl<T: ToKeyString> ToKeyString for std::rc::Rc<T> {
878    #[inline]
879    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
880        (**self).fmt_key_string(f)
881    }
882    #[inline]
883    fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
884        (**self).with_key_string(f)
885    }
886}
887impl_parse_meta_item_wrapper!(std::cell::Cell<T>);
888
889impl<T: ToKeyString + Copy> ToKeyString for std::cell::Cell<T> {
890    #[inline]
891    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
892        self.get().fmt_key_string(f)
893    }
894    #[inline]
895    fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
896        self.get().with_key_string(f)
897    }
898}
899
900impl_parse_meta_item_wrapper!(std::cell::RefCell<T>);
901
902impl<T: ToKeyString> ToKeyString for std::cell::RefCell<T> {
903    #[inline]
904    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
905        self.borrow().fmt_key_string(f)
906    }
907    #[inline]
908    fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
909        self.borrow().with_key_string(f)
910    }
911}
912
913impl<'t, T: ParseMetaItem + Clone> ParseMetaItem for std::borrow::Cow<'t, T> {
914    #[inline]
915    fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
916        Ok(Self::Owned(T::parse_meta_item(input, mode)?))
917    }
918    #[inline]
919    fn parse_meta_item_flag(span: Span) -> Result<Self> {
920        T::parse_meta_item_flag(span).map(Self::Owned)
921    }
922}
923
924impl<'t, T: ToKeyString + Clone> ToKeyString for std::borrow::Cow<'t, T> {
925    #[inline]
926    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
927        (**self).fmt_key_string(f)
928    }
929    #[inline]
930    fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
931        (**self).with_key_string(f)
932    }
933}
934
935impl ParseMetaItem for proc_macro2::TokenTree {
936    #[inline]
937    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
938        input.step(|cursor| {
939            cursor
940                .token_tree()
941                .ok_or_else(|| crate::Error::new(cursor.span(), "unexpected end of tokens"))
942        })
943    }
944}
945
946macro_rules! impl_fmt_key_string_display {
947    ($(#[$attr:meta])* $ty:ty) => {
948        $(#[$attr])*
949        impl ToKeyString for $ty {
950            #[inline]
951            fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
952                fmt::Display::fmt(self, f)
953            }
954        }
955    };
956    ($ty:ty, #proc_macro) => {
957        impl_fmt_key_string_display!(
958            #[cfg(feature = "proc-macro")]
959            #[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
960            $ty
961        );
962    };
963}
964
965impl_fmt_key_string_display!(proc_macro2::TokenTree);
966
967/// Consumes up to the next comma or the end of the stream. Returns an error if the stream is
968/// empty or the first token is a comma.
969impl ParseMetaItem for proc_macro2::TokenStream {
970    #[inline]
971    fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
972        if input.peek(Token![,]) {
973            return Err(syn::Error::new(input.span(), "unexpected comma"));
974        }
975        input.step(|cursor| {
976            let mut cursor = *cursor;
977            let mut tts = Vec::new();
978            while let Some((tt, rest)) = cursor.token_tree() {
979                match tt {
980                    proc_macro2::TokenTree::Punct(p) if p.as_char() == ',' => break,
981                    tt => tts.push(tt),
982                }
983                cursor = rest;
984            }
985            if tts.is_empty() {
986                return Err(syn::Error::new(mode.to_span(input), "expected token"));
987            }
988            Ok((tts.into_iter().collect(), cursor))
989        })
990    }
991    #[inline]
992    fn parse_meta_item_flag(_: Span) -> Result<Self> {
993        Ok(Default::default())
994    }
995    #[inline]
996    fn missing_meta_item(_name: &str, _span: Span) -> Result<Self> {
997        Ok(Default::default())
998    }
999}
1000
1001impl ParseMetaFlatUnnamed for proc_macro2::TokenStream {
1002    #[inline]
1003    fn field_count() -> Option<usize> {
1004        None
1005    }
1006    fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
1007        inputs: &[S],
1008        _mode: ParseMode,
1009        _index: usize,
1010    ) -> Result<Self> {
1011        let mut tts = Self::new();
1012        for input in inputs {
1013            let input = input.borrow();
1014            loop {
1015                if input.is_empty() {
1016                    break;
1017                }
1018                tts.extend(Self::parse_meta_item(input, ParseMode::Unnamed)?);
1019            }
1020        }
1021        Ok(tts)
1022    }
1023}
1024
1025impl_fmt_key_string_display!(proc_macro2::TokenStream);
1026
1027impl ParseMetaItem for proc_macro2::Literal {
1028    #[inline]
1029    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1030        input.step(|cursor| {
1031            cursor
1032                .literal()
1033                .ok_or_else(|| crate::Error::new(cursor.span(), "expected literal"))
1034        })
1035    }
1036}
1037
1038impl_fmt_key_string_display!(proc_macro2::Literal);
1039
1040impl ParseMetaItem for proc_macro2::Punct {
1041    #[inline]
1042    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1043        input.step(|cursor| {
1044            cursor
1045                .punct()
1046                .ok_or_else(|| crate::Error::new(cursor.span(), "expected punctuation"))
1047        })
1048    }
1049}
1050
1051impl_fmt_key_string_display!(proc_macro2::Punct);
1052
1053impl ParseMetaItem for proc_macro2::Group {
1054    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1055        input.step(|cursor| {
1056            for delim in {
1057                use proc_macro2::Delimiter::*;
1058                [Parenthesis, Brace, Bracket, None]
1059            } {
1060                if let Some((group, _, cursor)) = cursor.group(delim) {
1061                    return Ok((proc_macro2::Group::new(delim, group.token_stream()), cursor));
1062                }
1063            }
1064            Err(crate::Error::new(
1065                cursor.span(),
1066                "expected parenthesis or brace or bracket",
1067            ))
1068        })
1069    }
1070}
1071
1072#[cfg(feature = "proc-macro")]
1073#[inline]
1074fn convert_token_tree(tt: proc_macro2::TokenTree) -> syn::Result<proc_macro::TokenTree> {
1075    #[inline]
1076    fn convert_delimiter(d: proc_macro2::Delimiter) -> proc_macro::Delimiter {
1077        match d {
1078            proc_macro2::Delimiter::Parenthesis => proc_macro::Delimiter::Parenthesis,
1079            proc_macro2::Delimiter::Brace => proc_macro::Delimiter::Brace,
1080            proc_macro2::Delimiter::Bracket => proc_macro::Delimiter::Bracket,
1081            proc_macro2::Delimiter::None => proc_macro::Delimiter::None,
1082        }
1083    }
1084    #[inline]
1085    fn convert_spacing(s: proc_macro2::Spacing) -> proc_macro::Spacing {
1086        match s {
1087            proc_macro2::Spacing::Alone => proc_macro::Spacing::Alone,
1088            proc_macro2::Spacing::Joint => proc_macro::Spacing::Joint,
1089        }
1090    }
1091    Ok(match tt {
1092        proc_macro2::TokenTree::Group(g) => {
1093            proc_macro::Group::new(convert_delimiter(g.delimiter()), g.stream().into()).into()
1094        }
1095        proc_macro2::TokenTree::Ident(i) => {
1096            proc_macro::Ident::new(&i.to_string(), i.span().unwrap()).into()
1097        }
1098        proc_macro2::TokenTree::Punct(p) => {
1099            proc_macro::Punct::new(p.as_char(), convert_spacing(p.spacing())).into()
1100        }
1101        proc_macro2::TokenTree::Literal(l) => l
1102            .to_string()
1103            .parse::<proc_macro::Literal>()
1104            .map(|mut pl| {
1105                pl.set_span(l.span().unwrap());
1106                pl
1107            })
1108            .map_err(|e| syn::Error::new(l.span(), e))?
1109            .into(),
1110    })
1111}
1112
1113#[cfg(feature = "proc-macro")]
1114#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
1115impl ParseMetaItem for proc_macro::TokenTree {
1116    #[inline]
1117    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1118        convert_token_tree(input.parse::<proc_macro2::TokenTree>()?)
1119    }
1120}
1121
1122impl_fmt_key_string_display!(proc_macro::TokenTree, #proc_macro);
1123
1124#[cfg(feature = "proc-macro")]
1125#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
1126impl ParseMetaItem for proc_macro::TokenStream {
1127    #[inline]
1128    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1129        Ok(input.parse::<proc_macro2::TokenStream>()?.into())
1130    }
1131}
1132
1133impl_fmt_key_string_display!(proc_macro::TokenStream, #proc_macro);
1134
1135#[cfg(feature = "proc-macro")]
1136#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
1137impl ParseMetaItem for proc_macro::Literal {
1138    #[inline]
1139    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1140        match convert_token_tree(proc_macro2::TokenTree::Literal(input.parse()?))? {
1141            proc_macro::TokenTree::Literal(l) => Ok(l),
1142            _ => unreachable!(),
1143        }
1144    }
1145}
1146
1147impl_fmt_key_string_display!(proc_macro::Literal, #proc_macro);
1148
1149#[cfg(feature = "proc-macro")]
1150#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
1151impl ParseMetaItem for proc_macro::Punct {
1152    #[inline]
1153    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1154        match convert_token_tree(proc_macro2::TokenTree::Punct(input.parse()?))? {
1155            proc_macro::TokenTree::Punct(p) => Ok(p),
1156            _ => unreachable!(),
1157        }
1158    }
1159}
1160
1161impl_fmt_key_string_display!(proc_macro::Punct, #proc_macro);
1162
1163#[cfg(feature = "proc-macro")]
1164#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
1165impl ParseMetaItem for proc_macro::Group {
1166    #[inline]
1167    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1168        match convert_token_tree(proc_macro2::TokenTree::Group(input.parse()?))? {
1169            proc_macro::TokenTree::Group(g) => Ok(g),
1170            _ => unreachable!(),
1171        }
1172    }
1173}
1174
1175impl_fmt_key_string_display!(proc_macro::Group, #proc_macro);
1176
1177#[cfg(feature = "proc-macro")]
1178#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
1179impl ParseMetaItem for proc_macro::Ident {
1180    #[inline]
1181    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1182        match convert_token_tree(proc_macro2::TokenTree::Ident(input.parse()?))? {
1183            proc_macro::TokenTree::Ident(i) => Ok(i),
1184            _ => unreachable!(),
1185        }
1186    }
1187}
1188
1189impl_fmt_key_string_display!(proc_macro::Ident, #proc_macro);
1190
1191impl<T: ParseMetaItem, P: Parse + Peek + Default> ParseMetaItem for Punctuated<T, P> {
1192    #[inline]
1193    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1194        Bracket::parse_delimited_meta_item(input, ParseMode::Unnamed)
1195    }
1196    #[inline]
1197    fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(
1198        inputs: &[S],
1199        _mode: ParseMode,
1200    ) -> Result<Self> {
1201        Self::parse_meta_flat_unnamed(inputs, _mode, 0)
1202    }
1203}
1204
1205impl<T: ParseMetaItem, P: Parse + Peek + Default> ParseMetaFlatUnnamed for Punctuated<T, P> {
1206    #[inline]
1207    fn field_count() -> Option<usize> {
1208        None
1209    }
1210    fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
1211        inputs: &[S],
1212        _mode: ParseMode,
1213        _index: usize,
1214    ) -> Result<Self> {
1215        let mut p = Punctuated::new();
1216        let errors = Errors::new();
1217        for input in inputs {
1218            let input = input.borrow();
1219            loop {
1220                if input.is_empty() {
1221                    break;
1222                }
1223                match errors.push_result(T::parse_meta_item(input, ParseMode::Unnamed)) {
1224                    Some(v) => {
1225                        p.push(v);
1226                        if !input.is_empty() && errors.push_result(input.parse::<P>()).is_some() {
1227                            break;
1228                        }
1229                    }
1230                    None => {
1231                        // skip tokens until we find a P
1232                        while !input.is_empty() {
1233                            if input.peek(P::default()) {
1234                                input.parse::<P>()?;
1235                                break;
1236                            }
1237                            input.step(|c| Ok(((), c.token_tree().map(|(_, c)| c).unwrap())))?;
1238                        }
1239                    }
1240                }
1241            }
1242        }
1243        errors.check()?;
1244        Ok(p)
1245    }
1246}
1247
1248impl<T: ToKeyString, P: ToTokens> ToKeyString for Punctuated<T, P> {
1249    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
1250        f.write_char('[')?;
1251        for p in self.pairs() {
1252            match p {
1253                syn::punctuated::Pair::Punctuated(t, p) => {
1254                    t.fmt_key_string(f)?;
1255                    p.to_token_stream().fmt_key_string(f)?;
1256                    f.write_char(' ')?;
1257                }
1258                syn::punctuated::Pair::End(t) => t.fmt_key_string(f)?,
1259            }
1260        }
1261        f.write_char(']')
1262    }
1263}
1264
1265macro_rules! impl_parse_meta_item_syn {
1266    ($(#[$attr:meta])* $ty:ty) => {
1267        $(#[$attr])*
1268        impl ParseMetaItem for $ty {
1269            #[inline]
1270            fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1271                input.parse()
1272            }
1273        }
1274        $(#[$attr])*
1275        impl ToKeyString for $ty {
1276            #[inline]
1277            fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
1278                self.to_token_stream().fmt_key_string(f)
1279            }
1280        }
1281    };
1282    ($ty:ty, #full) => {
1283        impl_parse_meta_item_syn!(
1284            #[cfg(feature = "full")]
1285            #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
1286            $ty
1287        );
1288    };
1289}
1290
1291macro_rules! impl_parse_meta_paren_item_syn {
1292    ($(#[$attr:meta])* $ty:ty) => {
1293        $(#[$attr])*
1294        impl ParseMetaItem for $ty {
1295            #[inline]
1296            fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
1297                match mode {
1298                    ParseMode::Named(_) => {
1299                        let content = Paren::parse_delimited(input)?;
1300                        let ret = content.parse()?;
1301                        content.parse::<Nothing>()?;
1302                        Ok(ret)
1303                    }
1304                    ParseMode::Unnamed => Ok(input.parse()?),
1305                }
1306            }
1307        }
1308        $(#[$attr])*
1309        impl ToKeyString for $ty {
1310            #[inline]
1311            fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
1312                self.to_token_stream().fmt_key_string(f)
1313            }
1314        }
1315    };
1316    ($ty:ty, #full) => {
1317        impl_parse_meta_paren_item_syn!(
1318            #[cfg(feature = "full")]
1319            #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
1320            $ty
1321        );
1322    };
1323}
1324
1325impl_parse_meta_item_syn!(syn::AngleBracketedGenericArguments);
1326impl_parse_meta_item_syn!(syn::BareFnArg);
1327impl_parse_meta_item_syn!(syn::BoundLifetimes);
1328impl_parse_meta_item_syn!(syn::BinOp);
1329impl_parse_meta_item_syn!(syn::Expr, #full);
1330impl_parse_meta_item_syn!(syn::ExprArray, #full);
1331impl_parse_meta_paren_item_syn!(syn::ExprAssign, #full);
1332impl_parse_meta_item_syn!(syn::ExprCall, #full);
1333impl_parse_meta_item_syn!(syn::ExprCast, #full);
1334impl_parse_meta_item_syn!(syn::ExprField, #full);
1335impl_parse_meta_item_syn!(syn::ExprIndex, #full);
1336impl_parse_meta_item_syn!(syn::ExprLit, #full);
1337impl_parse_meta_item_syn!(syn::ExprMethodCall, #full);
1338impl_parse_meta_item_syn!(syn::ExprParen, #full);
1339impl_parse_meta_item_syn!(syn::ExprPath, #full);
1340impl_parse_meta_item_syn!(syn::ExprRange, #full);
1341impl_parse_meta_item_syn!(syn::ExprRepeat, #full);
1342impl_parse_meta_item_syn!(syn::ExprTuple, #full);
1343impl_parse_meta_item_syn!(syn::FnArg, #full);
1344impl_parse_meta_item_syn!(syn::GenericParam);
1345impl ParseMetaItem for syn::Ident {
1346    #[inline]
1347    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1348        syn::ext::IdentExt::parse_any(input)
1349    }
1350}
1351impl ToKeyString for syn::Ident {
1352    #[inline]
1353    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
1354        fmt::Display::fmt(self, f)
1355    }
1356}
1357impl_parse_meta_item_syn!(syn::Lifetime);
1358impl_parse_meta_item_syn!(syn::LifetimeParam);
1359impl_parse_meta_item_syn!(syn::Lit);
1360impl_parse_meta_item_syn!(syn::LitStr);
1361impl_parse_meta_item_syn!(syn::LitByteStr);
1362impl_parse_meta_item_syn!(syn::LitByte);
1363impl_parse_meta_item_syn!(syn::LitChar);
1364impl_parse_meta_item_syn!(syn::LitInt);
1365impl_parse_meta_item_syn!(syn::LitFloat);
1366impl_parse_meta_item_syn!(syn::LitBool);
1367impl_parse_meta_item_syn!(syn::MetaList);
1368impl_parse_meta_paren_item_syn!(syn::Meta);
1369impl_parse_meta_paren_item_syn!(syn::MetaNameValue);
1370#[cfg(feature = "full")]
1371#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
1372impl ParseMetaItem for syn::Pat {
1373    #[inline]
1374    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1375        syn::Pat::parse_single(input)
1376    }
1377}
1378#[cfg(feature = "full")]
1379#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
1380impl ToKeyString for syn::Pat {
1381    #[inline]
1382    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
1383        self.to_token_stream().fmt_key_string(f)
1384    }
1385}
1386impl ParseMetaItem for syn::Path {
1387    #[inline]
1388    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1389        input.parse()
1390    }
1391}
1392impl ToKeyString for syn::Path {
1393    #[inline]
1394    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
1395        for (i, seg) in self.segments.iter().enumerate() {
1396            if i > 0 {
1397                f.write_str("::")?;
1398            }
1399            seg.ident.fmt_key_string(f)?;
1400            if !seg.arguments.is_empty() {
1401                seg.arguments.to_token_stream().fmt_key_string(f)?;
1402            }
1403        }
1404        Ok(())
1405    }
1406}
1407impl_parse_meta_item_syn!(syn::PathSegment);
1408impl_parse_meta_item_syn!(syn::ParenthesizedGenericArguments);
1409impl_parse_meta_item_syn!(syn::Receiver, #full);
1410impl_parse_meta_item_syn!(syn::Signature, #full);
1411impl_parse_meta_item_syn!(syn::TraitBound);
1412impl_parse_meta_item_syn!(syn::Type);
1413impl_parse_meta_item_syn!(syn::TypeArray);
1414impl_parse_meta_item_syn!(syn::TypeBareFn);
1415impl_parse_meta_item_syn!(syn::TypeImplTrait);
1416impl_parse_meta_item_syn!(syn::TypePath);
1417impl_parse_meta_item_syn!(syn::TypePtr);
1418impl_parse_meta_item_syn!(syn::TypeReference);
1419impl_parse_meta_item_syn!(syn::TypeSlice);
1420impl_parse_meta_item_syn!(syn::TypeTraitObject);
1421impl_parse_meta_item_syn!(syn::TypeTuple);
1422impl_parse_meta_item_syn!(syn::TypeParamBound);
1423impl_parse_meta_item_syn!(syn::UseTree, #full);
1424impl_parse_meta_item_syn!(syn::UnOp);
1425impl_parse_meta_item_syn!(syn::Visibility);
1426impl_parse_meta_item_syn!(syn::WherePredicate);
1427
1428impl ParseMetaItem for () {
1429    #[inline]
1430    fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1431        let content = Paren::parse_delimited(input)?;
1432        content.parse::<Nothing>()?;
1433        Ok(())
1434    }
1435    #[inline]
1436    fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(
1437        inputs: &[S],
1438        _mode: ParseMode,
1439    ) -> Result<Self> {
1440        for input in inputs {
1441            input.borrow().parse::<Nothing>()?;
1442        }
1443        Ok(())
1444    }
1445    #[inline]
1446    fn parse_meta_item_flag(_: Span) -> Result<Self> {
1447        Ok(())
1448    }
1449}
1450
1451impl ToKeyString for () {
1452    #[inline]
1453    fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
1454        f.write_str("()")
1455    }
1456    #[inline]
1457    fn with_key_string<R>(&self, f: impl FnOnce(&str) -> R) -> R {
1458        f("()")
1459    }
1460}
1461
1462macro_rules! impl_parse_meta_item_tuple {
1463    ($len:literal: $($index:tt $param:tt $item:ident)+) => {
1464        impl<$($param: ParseMetaItem,)+> ParseMetaItem for ($($param,)+) {
1465            #[inline]
1466            fn parse_meta_item(input: ParseStream, _mode: ParseMode) -> Result<Self> {
1467                Paren::parse_delimited_meta_item(input, ParseMode::Unnamed)
1468            }
1469            #[inline]
1470            fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(inputs: &[S], _mode: ParseMode) -> Result<Self> {
1471                Self::parse_meta_flat_unnamed(inputs, _mode, 0)
1472            }
1473        }
1474
1475        impl<$($param: ParseMetaItem,)+> ParseMetaFlatUnnamed for ($($param,)+) {
1476            #[inline]
1477            fn field_count() -> Option<usize> {
1478                Some($len)
1479            }
1480            fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
1481                inputs: &[S],
1482                _mode: ParseMode,
1483                _index: usize
1484            ) -> Result<Self> {
1485                $(let mut $item = FieldStatus::None;)+
1486                let errors = Errors::new();
1487                errors.push_result(parse_tuple_struct(inputs, $len, |stream, _, index| {
1488                    match index {
1489                        $($index => $item.parse_unnamed_item(stream, &errors),)+
1490                        _ => unreachable!(),
1491                    }
1492                    Ok(())
1493                }));
1494                $(if $item.is_none() {
1495                    errors.push(
1496                        inputs_span(inputs),
1497                        format!("Expected tuple of length {}, got {}", $len, $index),
1498                    );
1499                    return errors.bail();
1500                };)+
1501                errors.check()?;
1502                $(let $item = $item.unwrap_or_else(|| unreachable!());)+
1503                Ok(($($item,)+))
1504            }
1505        }
1506
1507        impl<$($param: ToKeyString,)+> ToKeyString for ($($param,)+) {
1508            #[inline]
1509            fn fmt_key_string(&self, f: &mut fmt::Formatter) -> fmt::Result {
1510                f.write_char('(')?;
1511
1512                $(
1513                    impl_parse_meta_item_tuple!(@push_comma f, $index);
1514                    self.$index.fmt_key_string(f)?;
1515                )+
1516                f.write_char(')')
1517            }
1518        }
1519    };
1520    (@push_comma $f:ident, 0) => { };
1521    (@push_comma $f:ident, $index:literal) => { $f.write_str(", ")?; };
1522}
1523
1524impl_parse_meta_item_tuple!(1: 0 T0 t0);
1525impl_parse_meta_item_tuple!(2: 0 T0 t0 1 T1 t1);
1526impl_parse_meta_item_tuple!(3: 0 T0 t0 1 T1 t1 2 T2 t2);
1527impl_parse_meta_item_tuple!(4: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3);
1528impl_parse_meta_item_tuple!(5: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4);
1529impl_parse_meta_item_tuple!(6: 0 T0 t0 1 T1 t1 2 T2 t2 3 T3 t3 4 T4 t4 5 T5 t5);
1530impl_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);
1531impl_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);
1532impl_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);
1533impl_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);
1534impl_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);
1535impl_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);
1536impl_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);
1537impl_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);
1538impl_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);
1539impl_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);