attrs/
lib.rs

1//! An ergonomic [`Parser`] for `#[attributes]`, built on parser combinators.
2//!
3//! ```
4//! # strum_lite::strum!( #[derive(PartialEq, Debug)] enum Casing { Kebab = "kebab-case", Snake = "snake_case" });
5//! # fn main() -> syn::Result<()> {
6//! # use syn::*;
7//! # use attrs::*;
8//! # use quote::ToTokens as _;
9//! let mut rename_all = None::<Casing>;
10//! let mut untagged = false;
11//! let mut deny_unknown_fields = false;
12//! let mut path_to_serde: Path = parse_quote!(::serde);
13//! let attrs: Vec<Attribute> = parse_quote! {
14//!     #[serde(rename_all = "kebab-case", untagged)]
15//!     #[serde(crate = "custom::path")]
16//! };
17//!
18//! Attrs::new()
19//!     .once("rename_all", with::eq(set::from_str(&mut rename_all)))
20//!     .once("untagged", set::flag(&mut untagged))
21//!     .once("deny_unknown_fields", set::flag(&mut deny_unknown_fields))
22//!     .once("crate", with::eq(on::parse_str(&mut path_to_serde)))
23//!     .parse_attrs("serde", &attrs)?;
24//!
25//! assert_eq!(rename_all, Some(Casing::Kebab));
26//! assert!(untagged);
27//! assert!(!deny_unknown_fields); // not encountered, so not set
28//! assert_eq!(path_to_serde.to_token_stream().to_string(), "custom :: path");
29//! # Ok(()) }
30//! ```
31//!
32//! # Guide
33//!
34//! `#[attributes]` as they are used [in the Rust compiler](https://doc.rust-lang.org/reference/attributes.html#meta-item-attribute-syntax)
35//! and [in the wild](https://serde.rs/attributes.html) tend to look like this:
36//!
37//! ```
38//! # const _: &str = stringify! {
39//!   #[repr(align(128), C)]
40//! //  ^^^^ ^^^^^ ^^^   ^
41//! //  path  key (val)  bare key
42//!
43//!   #[serde(rename_all = "kebab-case", untagged)]
44//! // ^^^^^^ ^^^^^^^^^^   ^^^^^^^^^^^^  ^^^^^^^^
45//! //  path     key     =      val      bare key
46//! # };
47//! ```
48//!
49//! To use this library, create an [`Attrs`],
50//! and register different `key`s, each with a parsing function.
51//!
52//! This library provides many parsing functions, but there are four key kinds:
53//! - [`lit`](set::lit) takes a literal like `true` or `100` from the input.
54//! - [`from_str`](set::from_str) takes a `".."` string from the input,
55//!   before trying to [`FromStr`] it into an object.
56//! - [`parse_str`](set::parse_str) takes a `".."` string from the input,
57//!   before trying to [`syn::parse`] it into an object.
58//! - [`parse`](set::parse) directly tries to [`syn::parse`] the input.
59//!
60//! Every function takes an `&mut` reference to its destination,
61//! which will be filled in when the corresponding `key` is encountered.
62//! The [`on`] module acts on direct references,
63//! whereas the [`set`] module acts on [`Option`]s, filling them with [`Some`].
64//!
65//! The main ways to separate a key from its value are provided as combinators in the [`with`] module:
66//! - [`with::eq`] take an `=` from the input.
67//! - [`with::paren`] take a group `(..)` from the input.
68//!
69//! You may choose to accept a `key` [`once`](Attrs::once) or [`many`](Attrs::many) times,
70//! and you can, of course, write your own parsing functions for whatever syntax you have in mind.
71
72use core::{fmt, fmt::Display, mem, str::FromStr};
73use std::{
74    borrow::Cow,
75    collections::{BTreeMap, btree_map::Entry},
76    rc::Rc,
77    sync::Arc,
78};
79
80use proc_macro2::{Span, TokenStream};
81use syn::{
82    Attribute, Ident, LitBool, LitStr, Token,
83    ext::IdentExt as _,
84    parse::{Parse, ParseStream, Parser},
85};
86
87/// Ergonomic [`Parser`] for `#[attributes]`.
88///
89/// See [crate documentation](mod@self) for more.
90///
91/// ```
92/// # fn main() -> syn::Result<()> {
93/// # use attrs::*;
94/// let mut untagged = false;
95/// let mut krate = None::<syn::Path>;
96///
97/// let parseme: syn::Attribute = syn::parse_quote! {
98///     #[serde(untagged, crate = "path::to::serde")]
99/// };
100///
101/// parseme.parse_args_with(
102///     Attrs::new()
103///         .once("untagged", set::flag(&mut untagged))
104///         .once("crate", with::eq(set::parse_str(&mut krate)))
105/// )?;
106///
107/// assert!(krate.is_some() && untagged);
108/// # Ok(()) }
109/// ```
110#[derive(Default)]
111pub struct Attrs<'a> {
112    map: BTreeMap<Ident, Attr<'a>>,
113    #[expect(clippy::type_complexity)]
114    fallback: Option<Box<dyn 'a + FnMut(&Ident, ParseStream<'_>) -> syn::Result<()>>>,
115}
116impl fmt::Debug for Attrs<'_> {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        f.debug_struct("Attrs")
119            .field("map", &self.map)
120            .field(
121                "fallback",
122                &match self.fallback {
123                    Some(_) => "Some(..)",
124                    None => "None",
125                },
126            )
127            .finish()
128    }
129}
130
131impl<'a> Attrs<'a> {
132    /// Create a new empty parser.
133    pub fn new() -> Self {
134        Self::default()
135    }
136    /// Whether `key` already exists in this parser.
137    pub fn contains<Q>(&self, key: &Q) -> bool
138    where
139        Q: ?Sized,
140        Ident: PartialEq<Q>,
141    {
142        self.map.keys().any(|it| it == key)
143    }
144    /// Parse tokens following `key` using `f`, at most once.
145    ///
146    /// See [crate documentation](mod@self) for more.
147    ///
148    /// # Panics
149    /// - If `key` has already been registered.
150    /// - If `key` is an invalid ident.
151    #[track_caller]
152    pub fn once<K, F>(&mut self, key: K, f: F) -> &mut Self
153    where
154        K: UnwrapIdent,
155        F: 'a + FnOnce(ParseStream<'_>) -> syn::Result<()>,
156    {
157        self.insert(key, Attr::Once(Once::Some(Box::new(f))))
158    }
159    /// Parse tokens following `key` using `f`, potentially many times.
160    ///
161    /// See [crate documentation](mod@self) for more.
162    ///
163    /// # Panics
164    /// - If `key` has already been registered.
165    /// - If `key` is an invalid ident.
166    #[track_caller]
167    pub fn many<K, F>(&mut self, key: K, f: F) -> &mut Self
168    where
169        K: UnwrapIdent,
170        F: 'a + FnMut(ParseStream<'_>) -> syn::Result<()>,
171    {
172        self.insert(key, Attr::Many(Box::new(f)))
173    }
174    /// Parse unrecognised keys using `f`.
175    ///
176    /// ```
177    /// # fn main() -> syn::Result<()> {
178    /// # use attrs::*;
179    /// let mut krate = None::<syn::Path>;
180    ///
181    /// let parseme: syn::Attribute = syn::parse_quote! {
182    ///     #[serde(crate = "path::to::serde")]
183    /// };
184    ///
185    /// parseme.parse_args_with(Attrs::new().fallback(|key, input| {
186    ///     assert_eq!(key, "crate");
187    ///     input.parse::<syn::Token![=]>()?;
188    ///     krate = Some(input.parse::<syn::LitStr>()?.parse()?);
189    ///     Ok(())
190    /// }))?;
191    ///
192    /// assert!(krate.is_some());
193    /// # Ok(()) }
194    /// ```
195    pub fn fallback<F>(&mut self, f: F) -> &mut Self
196    where
197        F: 'a + FnMut(&Ident, ParseStream<'_>) -> syn::Result<()>,
198    {
199        self.fallback = Some(Box::new(f));
200        self
201    }
202    /// If the key `alias` is encountered, call the parser for `key`.
203    ///
204    /// See [module documentation](mod@self) for more.
205    ///
206    /// # Panics
207    /// - If `alias` has already been registered.
208    /// - If `alias` is an invalid ident.
209    /// - If `key` has not been registered.
210    #[track_caller]
211    pub fn alias<A, K>(&mut self, alias: A, key: K) -> &mut Self
212    where
213        A: UnwrapIdent,
214        K: UnwrapIdent,
215    {
216        let key = key.unwrap_ident();
217        assert!(
218            self.contains(&key),
219            "`{key}` is not registered (aliases may only be registered after their destination)"
220        );
221        self.insert(alias, Attr::AliasFor(key.unwrap_ident()))
222    }
223    /// Parse all the [`Attribute`]s where their path is the given `path`.
224    ///
225    /// ```
226    /// # fn main() -> syn::Result<()> {
227    /// # use syn::*;
228    /// # use attrs::*;
229    ///
230    /// let mut rename_all = None::<String>;
231    /// let mut untagged = false;
232    /// let mut deny_unknown_fields = false;
233    /// let attrs: Vec<Attribute> = parse_quote! {
234    ///     #[serde(rename_all = "kebab-case", untagged)]
235    ///     #[default] // SKIPPED
236    ///     #[serde(deny_unknown_fields)]
237    /// };
238    ///
239    /// Attrs::new()
240    ///     .once("rename_all", with::eq(set::from_str(&mut rename_all)))
241    ///     .once("untagged", set::flag(&mut untagged))
242    ///     .once("deny_unknown_fields", set::flag(&mut deny_unknown_fields))
243    ///     .parse_attrs("serde", &attrs)?;
244    ///
245    /// assert!(rename_all.is_some() && untagged && deny_unknown_fields);
246    /// # Ok(()) }
247    /// ```
248    pub fn parse_attrs<Q>(&mut self, path: &Q, attrs: &[Attribute]) -> syn::Result<()>
249    where
250        Q: ?Sized,
251        Ident: PartialEq<Q>,
252    {
253        for attr in attrs {
254            if attr.path().is_ident(path) {
255                attr.parse_args_with(&mut *self)?
256            }
257        }
258        Ok(())
259    }
260
261    /// Parse and remove all the [`Attribute`]s where their path is the given `path`.
262    ///
263    /// ```
264    /// # fn main() -> syn::Result<()> {
265    /// # use syn::*;
266    /// # use attrs::*;
267    ///
268    /// let mut rename_all = None::<String>;
269    /// let mut untagged = false;
270    /// let mut deny_unknown_fields = false;
271    /// let mut attrs: Vec<Attribute> = parse_quote! {
272    ///     #[serde(rename_all = "kebab-case", untagged)]
273    ///     #[default] // SKIPPED
274    ///     #[serde(deny_unknown_fields)]
275    /// };
276    ///
277    /// Attrs::new()
278    ///     .once("rename_all", with::eq(set::from_str(&mut rename_all)))
279    ///     .once("untagged", set::flag(&mut untagged))
280    ///     .once("deny_unknown_fields", set::flag(&mut deny_unknown_fields))
281    ///     .extract_from("serde", &mut attrs)?;
282    ///
283    /// assert!(rename_all.is_some() && untagged && deny_unknown_fields);
284    /// assert_eq!(attrs.len(), 1); // `#[default]` is still there
285    /// # Ok(()) }
286    /// ```
287    pub fn extract_from<Q>(&mut self, path: &Q, attrs: &mut Vec<Attribute>) -> syn::Result<()>
288    where
289        Q: ?Sized,
290        Ident: PartialEq<Q>,
291    {
292        let mut e = None;
293        attrs.retain(|attr| match attr.path().is_ident(path) {
294            true => {
295                match (e.as_mut(), attr.parse_args_with(&mut *self)) {
296                    (_, Ok(())) => {}
297                    (None, Err(e2)) => e = Some(e2),
298                    (Some(e1), Err(e2)) => e1.combine(e2),
299                }
300                false // parsed - remove from `attrs`
301            }
302            false => true, // not ours - leave in `attrs`
303        });
304        e.map(Err).unwrap_or(Ok(()))
305    }
306
307    /// Parse the entirety of input as a sequence of registered `key`s,
308    /// followed by the appropriate combinator,
309    /// separated by commas.
310    fn _parse(&mut self, input: ParseStream<'_>) -> syn::Result<()> {
311        let msg = Phrase {
312            many: "Expected one of",
313            one: "Expected",
314            none: match &self.fallback {
315                Some(_) => "No explicit arguments specified",
316                None => "No arguments accepted",
317            },
318            conjunction: "or",
319            iter: self
320                .map
321                .iter()
322                .filter_map(|(k, v)| match v {
323                    Attr::AliasFor(_) => None,
324                    Attr::Once(_) | Attr::Many(_) => Some(k.clone()),
325                })
326                .collect::<Vec<_>>(),
327        };
328        // parse input
329        loop {
330            if input.is_empty() {
331                break;
332            }
333            match input.call(Ident::parse_any) {
334                Ok(it) => {
335                    let mut key = it.unraw();
336                    // follow redirects
337                    loop {
338                        break match (self.map.get_mut(&key), &mut self.fallback) {
339                            (Some(attr), _) => match attr {
340                                Attr::AliasFor(redirect) => {
341                                    key = redirect.clone();
342                                    continue;
343                                }
344                                Attr::Once(once) => {
345                                    match mem::replace(once, Once::Already(it.span())) {
346                                        Once::Some(f) => f(input)?,
347                                        Once::Already(already) => {
348                                            let mut e =
349                                                syn::Error::new(it.span(), "Duplicate argument");
350                                            e.combine(syn::Error::new(
351                                                already,
352                                                "Already used here",
353                                            ));
354                                            return Err(e);
355                                        }
356                                    }
357                                }
358                                Attr::Many(f) => f(input)?,
359                            },
360                            (None, Some(fallback)) => match fallback(&key, input) {
361                                Ok(()) => {}
362                                Err(mut e) => {
363                                    e.combine(syn::Error::new(e.span(), msg));
364                                    return Err(e);
365                                }
366                            },
367                            (None, None) => return Err(syn::Error::new(it.span(), msg)),
368                        };
369                    }
370                }
371                Err(mut e) => {
372                    e.combine(syn::Error::new(e.span(), msg));
373                    return Err(e);
374                }
375            }
376            if input.is_empty() {
377                break;
378            }
379            input.parse::<Token![,]>()?;
380        }
381        Ok(())
382    }
383
384    #[track_caller]
385    fn insert(&mut self, key: impl UnwrapIdent, val: Attr<'a>) -> &mut Self {
386        match self.map.entry(key.unwrap_ident()) {
387            Entry::Vacant(it) => it.insert(val),
388            Entry::Occupied(it) => panic!("duplicate entry for key `{}`", it.key()),
389        };
390        self
391    }
392
393    fn into_parser(mut self) -> impl FnMut(ParseStream<'_>) -> syn::Result<()> {
394        move |input| self._parse(input)
395    }
396    fn as_parser(&mut self) -> impl FnMut(ParseStream<'_>) -> syn::Result<()> {
397        |input| self._parse(input)
398    }
399}
400
401enum Attr<'a> {
402    AliasFor(Ident),
403    Once(Once<'a>),
404    Many(Box<dyn 'a + FnMut(ParseStream<'_>) -> syn::Result<()>>),
405}
406
407impl fmt::Debug for Attr<'_> {
408    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
409        match self {
410            Self::AliasFor(it) => f.debug_tuple("AliasFor").field(it).finish(),
411            Self::Once(it) => f.debug_tuple("Once").field(it).finish(),
412            Self::Many(_) => f.debug_tuple("Many").finish_non_exhaustive(),
413        }
414    }
415}
416
417enum Once<'a> {
418    Some(Box<dyn 'a + FnOnce(ParseStream<'_>) -> syn::Result<()>>),
419    Already(Span),
420}
421impl fmt::Debug for Once<'_> {
422    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
423        match self {
424            Self::Some(_) => f.debug_tuple("Some").finish_non_exhaustive(),
425            Self::Already(span) => f.debug_tuple("Already").field(span).finish(),
426        }
427    }
428}
429
430/// Borrow from this object as a [`Parser`].
431///
432/// ```
433/// # fn main() -> syn::Result<()> {
434/// # use attrs::*;
435/// # use syn::*;
436/// use syn::parse::Parser as _;
437///
438/// let mut untagged = false;
439/// let mut krate = None::<Path>;
440///
441/// Attrs::new()
442///     .once("untagged", set::flag(&mut untagged))
443///     .once("crate", with::eq(set::parse_str(&mut krate)))
444///     .parse_str(r#"untagged, crate = "path::to::serde""#)?;
445///
446/// assert!(krate.is_some() && untagged);
447/// # Ok(()) }
448/// ```
449impl Parser for &mut Attrs<'_> {
450    type Output = ();
451    fn parse2(self, tokens: TokenStream) -> syn::Result<Self::Output> {
452        self.as_parser().parse2(tokens)
453    }
454}
455
456/// Move this object into a [`Parser`].
457///
458/// ```
459/// # fn main() -> syn::Result<()> {
460/// # use attrs::*;
461/// # use syn::*;
462/// use syn::parse::Parser as _;
463///
464/// let mut untagged = false;
465/// let mut krate = None::<Path>;
466///
467/// let mut attrs = Attrs::new();
468/// attrs
469///     .once("untagged", set::flag(&mut untagged))
470///     .once("crate", with::eq(set::parse_str(&mut krate)));
471/// attrs.parse_str(r#"untagged, crate = "path::to::serde""#)?;
472///
473/// assert!(krate.is_some() && untagged);
474/// # Ok(()) }
475/// ```
476impl Parser for Attrs<'_> {
477    type Output = ();
478    fn parse2(self, tokens: TokenStream) -> syn::Result<Self::Output> {
479        self.into_parser().parse2(tokens)
480    }
481}
482
483#[test]
484fn test() {
485    use quote::quote;
486    use syn::{punctuated::Punctuated, *};
487
488    strum_lite::strum! {
489        #[derive(PartialEq, Debug)]
490        enum Casing {
491            Pascal = "PascalCase",
492            Snake = "snake_case",
493        }
494    }
495
496    let mut casing = Casing::Snake;
497    let mut vis = Visibility::Inherited;
498    let mut opt_pred = None::<WherePredicate>;
499    let mut use_unsafe = false;
500    let mut aliases = vec![];
501
502    Attrs::new()
503        // `rename_all = "snake_case"`
504        .once("rename_all", with::eq(on::from_str(&mut casing)))
505        // `vis = pub` or `vis(pub)`
506        .once("vis", with::peq(on::parse(&mut vis)))
507        // `use_unsafe`
508        .once("use_unsafe", set::flag(&mut use_unsafe))
509        // `where(T: Foo)`
510        .once("where", with::paren(set::parse(&mut opt_pred)))
511        // `alias("hello", "world"), alias("goodbye")`
512        .many(
513            "alias",
514            with::paren(|input| {
515                aliases.extend(Punctuated::<LitStr, Token![,]>::parse_separated_nonempty(
516                    input,
517                )?);
518                Ok(())
519            }),
520        )
521        .parse2(quote! {
522            rename_all = "PascalCase",
523            vis = pub,
524            use_unsafe,
525            where(T: Ord),
526            alias("hello", "world"),
527            alias("goodbye")
528        })
529        .unwrap();
530    assert_eq!(casing, Casing::Pascal);
531    assert!(matches!(vis, Visibility::Public(_)));
532    assert!(opt_pred.is_some());
533    assert!(use_unsafe);
534    assert_eq!(aliases.len(), 3);
535}
536
537/// Conversion to an [`Ident`].
538///
539/// This is primarily an ergonomic aid, and SHOULD NOT be used on untrusted inputs.
540pub trait UnwrapIdent {
541    /// # Panics
542    /// - Implementors may decide to panic.
543    #[track_caller]
544    fn unwrap_ident(&self) -> Ident;
545}
546
547impl UnwrapIdent for str {
548    #[track_caller]
549    fn unwrap_ident(&self) -> Ident {
550        Ident::new(self, Span::call_site())
551    }
552}
553impl UnwrapIdent for String {
554    #[track_caller]
555    fn unwrap_ident(&self) -> Ident {
556        <str>::unwrap_ident(self)
557    }
558}
559impl UnwrapIdent for Cow<'_, str> {
560    #[track_caller]
561    fn unwrap_ident(&self) -> Ident {
562        <str>::unwrap_ident(self)
563    }
564}
565impl UnwrapIdent for Ident {
566    #[track_caller]
567    fn unwrap_ident(&self) -> Ident {
568        self.clone()
569    }
570}
571impl<T: UnwrapIdent + ?Sized> UnwrapIdent for &T {
572    #[track_caller]
573    fn unwrap_ident(&self) -> Ident {
574        T::unwrap_ident(self)
575    }
576}
577impl<T: UnwrapIdent + ?Sized> UnwrapIdent for Box<T> {
578    #[track_caller]
579    fn unwrap_ident(&self) -> Ident {
580        T::unwrap_ident(self)
581    }
582}
583impl<T: UnwrapIdent + ?Sized> UnwrapIdent for Rc<T> {
584    #[track_caller]
585    fn unwrap_ident(&self) -> Ident {
586        T::unwrap_ident(self)
587    }
588}
589impl<T: UnwrapIdent + ?Sized> UnwrapIdent for Arc<T> {
590    #[track_caller]
591    fn unwrap_ident(&self) -> Ident {
592        T::unwrap_ident(self)
593    }
594}
595
596/// Wrap parsing functions so that they are e.g preceded by `=` or surrounded by `(..)`.
597pub mod with {
598    use syn::{
599        Token, braced, bracketed, parenthesized,
600        parse::{ParseStream, discouraged::AnyDelimiter},
601        token,
602    };
603
604    /// Take an `=` before appling `f`.
605    ///
606    /// Users should be careful that `f` doesn't consume too far into the input.
607    pub fn eq<'a, F>(mut f: F) -> impl 'a + FnMut(ParseStream<'_>) -> syn::Result<()>
608    where
609        F: 'a + FnMut(ParseStream<'_>) -> syn::Result<()>,
610    {
611        move |input| {
612            input.parse::<Token![=]>()?;
613            f(input)
614        }
615    }
616    /// Take a `(...)`, appling `f` to its contents.
617    pub fn paren<'a, F>(mut f: F) -> impl 'a + FnMut(ParseStream<'_>) -> syn::Result<()>
618    where
619        F: 'a + FnMut(ParseStream<'_>) -> syn::Result<()>,
620    {
621        move |input| {
622            let content;
623            parenthesized!(content in input);
624            f(&content)
625        }
626    }
627    /// Take a `[...]`, appling `f` to its contents.
628    pub fn bracket<'a, F>(mut f: F) -> impl 'a + FnMut(ParseStream<'_>) -> syn::Result<()>
629    where
630        F: 'a + FnMut(ParseStream<'_>) -> syn::Result<()>,
631    {
632        move |input| {
633            let content;
634            bracketed!(content in input);
635            f(&content)
636        }
637    }
638    /// Take a `{...}`, appling `f` to its contents.
639    pub fn brace<'a, F>(mut f: F) -> impl 'a + FnMut(ParseStream<'_>) -> syn::Result<()>
640    where
641        F: 'a + FnMut(ParseStream<'_>) -> syn::Result<()>,
642    {
643        move |input| {
644            let content;
645            braced!(content in input);
646            f(&content)
647        }
648    }
649    /// Take any group (`(...)`, `[...]`, `{...}`), appling `f` to its contents.
650    pub fn delim<'a, F>(mut f: F) -> impl 'a + FnMut(ParseStream<'_>) -> syn::Result<()>
651    where
652        F: 'a + FnMut(ParseStream<'_>) -> syn::Result<()>,
653    {
654        move |input| {
655            let (_, _, content) = input.parse_any_delimiter()?;
656            f(&content)
657        }
658    }
659
660    /// Either:
661    /// - Take an `=` before applying `f`.
662    ///   See also [`eq`].
663    /// - Take a `(...)` before applying `f` to its contents.
664    pub fn peq<'a, F>(mut f: F) -> impl 'a + FnMut(ParseStream<'_>) -> syn::Result<()>
665    where
666        F: 'a + FnMut(ParseStream<'_>) -> syn::Result<()>,
667    {
668        move |input| {
669            if input.peek(Token![=]) {
670                input.parse::<Token![=]>()?;
671                f(input)
672            } else if input.peek(token::Paren) {
673                let content;
674                parenthesized!(content in input);
675                f(&content)
676            } else {
677                Err(input.error("Expected a `=` or `(..)`"))
678            }
679        }
680    }
681}
682
683/// Create [`Parser`]s that write to [`&mut Option<T>`](Option).
684pub mod set {
685    use super::*;
686
687    #[deprecated = "use `flag::free` instead"]
688    pub use flag::free as flag;
689
690    /// Parse a [`LitBool`], assigning it to `dst` in [`Some`].
691    ///
692    /// ```
693    /// #![expect(deprecated)]
694    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
695    /// # fn main() -> syn::Result<()> {
696    /// let mut val = None;
697    ///
698    /// Attrs::new()
699    ///     .once("key", with::eq(set::bool(&mut val)))
700    ///     .parse2(quote!(key = true))?;
701    ///
702    /// assert_eq!(val, Some(true));
703    /// # Ok(()) }
704    /// ```
705    #[deprecated = "Use `set::lit` instead"]
706    pub fn bool(dst: &mut Option<bool>) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
707        |input| parse::set::lit(dst, input)
708    }
709    /// Parse a [`Parse`]-able, assigning it to `dst` in [`Some`].
710    ///
711    /// You should take care that the [`Parse`] does not advance into subsequent keys,
712    /// else use [`parse_str`] instead.
713    ///
714    /// ```
715    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
716    /// # use proc_macro2::{Span, Ident};
717    /// # fn main() -> syn::Result<()> {
718    /// let mut val = None::<Ident>;
719    ///
720    /// Attrs::new()
721    ///     .once("key", with::eq(set::parse(&mut val)))
722    ///     .parse2(quote!(key = Value))?;
723    ///
724    /// assert_eq!(val, Some(Ident::new("Value", Span::call_site())));
725    /// # Ok(()) }
726    /// ```
727    pub fn parse<T: Parse>(
728        dst: &mut Option<T>,
729    ) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
730        |input| parse::set::parse(dst, input)
731    }
732    /// 1. Parse a [`LitStr`].
733    /// 2. Parse the contents of that string using [`FromStr`].
734    /// 3. Assign the result to `dst` in [`Some`].
735    ///
736    /// ```
737    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
738    /// # use core::net::Ipv4Addr;
739    /// # fn main() -> syn::Result<()> {
740    /// let mut val = None::<Ipv4Addr>;
741    ///
742    /// Attrs::new()
743    ///     .once("key", with::eq(set::from_str(&mut val)))
744    ///     .parse2(quote!(key = "127.0.0.1"))?;
745    ///
746    /// assert_eq!(val, Some(Ipv4Addr::LOCALHOST));
747    /// # Ok(()) }
748    /// ```
749    pub fn from_str<T: FromStr>(
750        dst: &mut Option<T>,
751    ) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()>
752    where
753        T::Err: Display,
754    {
755        |input| parse::set::from_str(dst, input)
756    }
757    /// 1. Parse a [`LitStr`].
758    /// 2. Parse the contents of that string into the [`Parse`]-able.
759    /// 3. Assign the result to `dst` in [`Some`].
760    ///
761    /// ```
762    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
763    /// # use proc_macro2::{Span, Ident};
764    /// # fn main() -> syn::Result<()> {
765    /// let mut val = None::<Ident>;
766    ///
767    /// Attrs::new()
768    ///     .once("key", with::eq(set::parse_str(&mut val)))
769    ///     .parse2(quote!(key = "Value"))?;
770    ///
771    /// assert_eq!(val, Some(Ident::new("Value", Span::call_site())));
772    /// # Ok(()) }
773    /// ```
774    pub fn parse_str<T: Parse>(
775        dst: &mut Option<T>,
776    ) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
777        |input| parse::set::parse_str(dst, input)
778    }
779
780    /// If `input` contains a [`LitStr`],
781    /// then parse the contents of that string into the [`Parse`]-able in [`Some`].
782    /// Else, directly parse it from `input`.
783    ///
784    /// ```
785    /// # use {attrs::*, syn::{parse::Parser as _, parse_quote}, quote::quote};
786    /// # use proc_macro2::{Span, Ident};
787    /// # fn main() -> syn::Result<()> {
788    /// let mut raw = None::<syn::Path>;
789    /// let mut str = None::<syn::Path>;
790    ///
791    /// Attrs::new()
792    ///     .once("raw", with::eq(set::maybe_str(&mut raw)))
793    ///     .once("str", with::eq(set::maybe_str(&mut str)))
794    ///     .parse2(quote!(raw = raw::path, str = "str::path"))?;
795    ///
796    /// assert_eq!(raw, Some(parse_quote!(raw::path)));
797    /// assert_eq!(str, Some(parse_quote!(str::path)));
798    /// # Ok(()) }
799    /// ```
800    pub fn maybe_str<T: Parse>(
801        dst: &mut Option<T>,
802    ) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
803        |input| parse::set::maybe_str(dst, input)
804    }
805
806    /// Parse the appropriate [`syn::Lit`],
807    /// extracting the value,
808    /// and assigning the result to `dst` in [`Some`].
809    ///
810    /// ```
811    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
812    /// # use proc_macro2::{Span, Ident};
813    /// # fn main() -> syn::Result<()> {
814    /// let mut byte = None::<u8>;
815    /// let mut usize = None::<usize>;
816    /// let mut isize = None::<isize>;
817    /// let mut float = None::<f32>;
818    /// let mut bool = None::<bool>;
819    /// let mut char = None::<char>;
820    /// let mut string = None::<String>;
821    /// let mut bytes = None::<Vec<u8>>;
822    ///
823    /// Attrs::new()
824    ///     .once("byte", with::eq(set::lit(&mut byte)))
825    ///     .once("usize", with::eq(set::lit(&mut usize)))
826    ///     .once("isize", with::eq(set::lit(&mut isize)))
827    ///     .once("float", with::eq(set::lit(&mut float)))
828    ///     .once("bool", with::eq(set::lit(&mut bool)))
829    ///     .once("char", with::eq(set::lit(&mut char)))
830    ///     .once("string", with::eq(set::lit(&mut string)))
831    ///     .once("bytes", with::eq(set::lit(&mut bytes)))
832    ///     .parse2(quote! {
833    ///         byte = b'A',
834    ///         usize = 123,
835    ///         isize = -456,
836    ///         float = 7.89,
837    ///         bool = false,
838    ///         char = 'ð“€€',
839    ///         string = "hello",
840    ///         bytes = b"world",
841    ///     })?;
842    ///
843    /// assert_eq!(byte, Some(b'A'));
844    /// assert_eq!(usize, Some(123));
845    /// assert_eq!(isize, Some(-456));
846    /// assert_eq!(float, Some(7.89));
847    /// assert_eq!(bool, Some(false));
848    /// assert_eq!(char, Some('ð“€€'));
849    /// assert_eq!(string, Some(String::from("hello")));
850    /// assert_eq!(bytes, Some(Vec::from(b"world")));
851    /// # Ok(()) }
852    /// ```
853    pub fn lit<T: Lit>(dst: &mut Option<T>) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
854        |input| parse::set::lit(dst, input)
855    }
856}
857
858/// Create [`Parser`]s that write to `&mut T` when they parse.
859pub mod on {
860    use super::*;
861
862    /// Parse a [`LitBool`], assigning its value to `dst`.
863    ///
864    /// ```
865    /// #![expect(deprecated)]
866    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
867    /// # fn main() -> syn::Result<()> {
868    /// let mut val = false;
869    ///
870    /// Attrs::new()
871    ///     .once("key", with::eq(on::bool(&mut val)))
872    ///     .parse2(quote!(key = true))?;
873    ///
874    /// assert!(val);
875    /// # Ok(()) }
876    #[deprecated = "Use `on::lit` instead"]
877    pub fn bool(dst: &mut bool) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
878        |input| parse::lit(dst, input)
879    }
880    /// Parse a [`Parse`]-able, assigning its value to `dst`.
881    ///
882    /// You should take care that the [`Parse`] does not advance into subsequent keys,
883    /// else use [`parse_str`] instead.
884    ///
885    /// ```
886    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
887    /// # use proc_macro2::{Span, Ident};
888    /// # fn main() -> syn::Result<()> {
889    /// let mut val = Ident::new("Default", Span::call_site());
890    ///
891    /// Attrs::new()
892    ///     .once("key", with::eq(on::parse(&mut val)))
893    ///     .parse2(quote!(key = Override))?;
894    ///
895    /// assert_eq!(val, Ident::new("Override", Span::call_site()));
896    /// # Ok(()) }
897    /// ```
898    pub fn parse<T: Parse>(dst: &mut T) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
899        |input| parse::parse(dst, input)
900    }
901    /// 1. Parse a [`LitStr`].
902    /// 2. Parse the contents of that string using [`FromStr`].
903    /// 3. Assign the result to `dst`.
904    ///
905    /// ```
906    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
907    /// # use core::net::Ipv4Addr;
908    /// # fn main() -> syn::Result<()> {
909    /// let mut val = Ipv4Addr::BROADCAST;
910    ///
911    /// Attrs::new()
912    ///     .once("key", with::eq(on::from_str(&mut val)))
913    ///     .parse2(quote!(key = "127.0.0.1"))?;
914    ///
915    /// assert_eq!(val, Ipv4Addr::LOCALHOST);
916    /// # Ok(()) }
917    /// ```
918    pub fn from_str<T: FromStr>(dst: &mut T) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()>
919    where
920        T::Err: Display,
921    {
922        |input| parse::from_str(dst, input)
923    }
924    /// 1. Parse a [`LitStr`].
925    /// 2. Parse the contents of that string into the [`Parse`]-able.
926    /// 3. Assign the result to `dst`.
927    ///
928    /// ```
929    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
930    /// # use proc_macro2::{Span, Ident};
931    /// # fn main() -> syn::Result<()> {
932    /// let mut val = Ident::new("Default", Span::call_site());
933    ///
934    /// Attrs::new()
935    ///     .once("key", with::eq(on::parse_str(&mut val)))
936    ///     .parse2(quote!(key = "Override"))?;
937    ///
938    /// assert_eq!(val, Ident::new("Override", Span::call_site()));
939    /// # Ok(()) }
940    /// ```
941    pub fn parse_str<T: Parse>(dst: &mut T) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
942        |input| parse::parse_str(dst, input)
943    }
944
945    /// If `input` contains a [`LitStr`],
946    /// then parse the contents of that string into the [`Parse`]-able.
947    /// Else, directly parse it from `input`.
948    ///
949    /// ```
950    /// # use {attrs::*, syn::{parse::Parser as _, parse_quote}, quote::quote};
951    /// # fn main() -> syn::Result<()> {
952    /// let mut raw: syn::Path = parse_quote!(default::path);
953    /// let mut str: syn::Path = parse_quote!(default::path);
954    ///
955    /// Attrs::new()
956    ///     .once("raw", with::eq(on::maybe_str(&mut raw)))
957    ///     .once("str", with::eq(on::maybe_str(&mut str)))
958    ///     .parse2(quote!(raw = raw::path, str = "str::path"))?;
959    ///
960    /// assert_eq!(raw, parse_quote!(raw::path));
961    /// assert_eq!(str, parse_quote!(str::path));
962    /// # Ok(()) }
963    /// ```
964    pub fn maybe_str<T: Parse>(dst: &mut T) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
965        |input| parse::maybe_str(dst, input)
966    }
967
968    /// Parse the appropriate [`syn::Lit`] from `input`,
969    /// extracting the value,
970    /// and assigning the result to `dst`.
971    ///
972    /// ```
973    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
974    /// # use proc_macro2::{Span, Ident};
975    /// # fn main() -> syn::Result<()> {
976    /// let mut byte = 0u8;
977    /// let mut usize = 0usize;
978    /// let mut isize = 0isize;
979    /// let mut float = 0.0f32;
980    /// let mut bool = false;
981    /// let mut char = 'a';
982    /// let mut string = String::new();
983    /// let mut bytes = Vec::new();
984    ///
985    /// Attrs::new()
986    ///     .once("byte", with::eq(on::lit(&mut byte)))
987    ///     .once("usize", with::eq(on::lit(&mut usize)))
988    ///     .once("isize", with::eq(on::lit(&mut isize)))
989    ///     .once("float", with::eq(on::lit(&mut float)))
990    ///     .once("bool", with::eq(on::lit(&mut bool)))
991    ///     .once("char", with::eq(on::lit(&mut char)))
992    ///     .once("string", with::eq(on::lit(&mut string)))
993    ///     .once("bytes", with::eq(on::lit(&mut bytes)))
994    ///     .parse2(quote! {
995    ///         byte = b'A',
996    ///         usize = 123,
997    ///         isize = -456,
998    ///         float = 7.89,
999    ///         bool = false,
1000    ///         char = 'ð“€€',
1001    ///         string = "hello",
1002    ///         bytes = b"world",
1003    ///     })?;
1004    ///
1005    /// assert_eq!(byte, b'A');
1006    /// assert_eq!(usize, 123);
1007    /// assert_eq!(isize, -456);
1008    /// assert_eq!(float, 7.89);
1009    /// assert_eq!(bool, false);
1010    /// assert_eq!(char, 'ð“€€');
1011    /// assert_eq!(string, "hello");
1012    /// assert_eq!(bytes, b"world");
1013    /// # Ok(()) }
1014    /// ```
1015    pub fn lit<T: Lit>(dst: &mut T) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
1016        |input| parse::lit(dst, input)
1017    }
1018}
1019
1020/// Create [`Parser`]s which set [`bool`]s.
1021pub mod flag {
1022    use syn::token;
1023
1024    use super::*;
1025
1026    /// Ignores the input, and just sets `dst` to `true`.
1027    ///
1028    /// ```
1029    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
1030    /// # fn main() -> syn::Result<()> {
1031    /// let mut val = false;
1032    ///
1033    /// Attrs::new()
1034    ///     .once("bare", flag::free(&mut val))
1035    ///     .parse2(quote!(bare))?;
1036    ///
1037    /// assert!(val);
1038    /// # Ok(()) }
1039    /// ```
1040    pub fn free(dst: &mut bool) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
1041        |_| {
1042            *dst = true;
1043            Ok(())
1044        }
1045    }
1046    /// Accept `key` or `key = true`
1047    ///
1048    /// ```
1049    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
1050    /// # fn main() -> syn::Result<()> {
1051    /// let mut val1 = false;
1052    /// let mut val2 = true;
1053    ///
1054    /// Attrs::new()
1055    ///     .once("bare", flag::or_eq(&mut val1))
1056    ///     .once("explicit", flag::or_eq(&mut val2))
1057    ///     .parse2(quote!(bare, explicit = false))?;
1058    ///
1059    /// assert!(val1);
1060    /// assert!(!val2);
1061    /// # Ok(()) }
1062    /// ```
1063    pub fn or_eq(dst: &mut bool) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
1064        |input| match input.peek(Token![=]) {
1065            true => with::eq(on::lit(dst))(input),
1066            false => free(dst)(input),
1067        }
1068    }
1069    /// Accept `key` or `key(true)`
1070    ///
1071    /// ```
1072    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
1073    /// # fn main() -> syn::Result<()> {
1074    /// let mut val1 = false;
1075    /// let mut val2 = true;
1076    ///
1077    /// Attrs::new()
1078    ///     .once("bare", flag::or_paren(&mut val1))
1079    ///     .once("explicit", flag::or_paren(&mut val2))
1080    ///     .parse2(quote!(bare, explicit(false)))?;
1081    ///
1082    /// assert!(val1);
1083    /// assert!(!val2);
1084    /// # Ok(()) }
1085    /// ```
1086    pub fn or_paren(dst: &mut bool) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
1087        |input| match input.peek(token::Paren) {
1088            true => with::paren(on::lit(dst))(input),
1089            false => free(dst)(input),
1090        }
1091    }
1092    /// Accept `key`, `key = true` or `key(true)`
1093    ///
1094    /// ```
1095    /// # use {attrs::*, syn::parse::Parser as _, quote::quote};
1096    /// # fn main() -> syn::Result<()> {
1097    /// let mut val1 = false;
1098    /// let mut val2 = true;
1099    /// let mut val3 = true;
1100    ///
1101    /// Attrs::new()
1102    ///     .once("bare", flag::or_peq(&mut val1))
1103    ///     .once("eq", flag::or_peq(&mut val2))
1104    ///     .once("paren", flag::or_peq(&mut val3))
1105    ///     .parse2(quote!(bare, eq = false, paren(false)))?;
1106    ///
1107    /// assert!(val1);
1108    /// assert!(!val2);
1109    /// assert!(!val3);
1110    /// # Ok(()) }
1111    pub fn or_peq(dst: &mut bool) -> impl '_ + FnMut(ParseStream<'_>) -> syn::Result<()> {
1112        |input| match input.peek(Token![=]) || input.peek(token::Paren) {
1113            true => with::peq(on::lit(dst))(input),
1114            false => free(dst)(input),
1115        }
1116    }
1117}
1118
1119/// Straightforward parsing functions.
1120///
1121/// Useful for constructing your own leaf combinators.
1122pub mod parse {
1123    use super::*;
1124
1125    /// Parse a [`LitBool`] from `input`, assigning it to `dst`.
1126    #[deprecated = "Use `parse::lit` instead"]
1127    pub fn bool(dst: &mut bool, input: ParseStream<'_>) -> syn::Result<()> {
1128        *dst = input.parse::<LitBool>()?.value;
1129        Ok(())
1130    }
1131    /// Parse a [`Parse`]-able from `input`, assigning it to `dst`.
1132    pub fn parse<T: Parse>(dst: &mut T, input: ParseStream<'_>) -> syn::Result<()> {
1133        *dst = input.parse()?;
1134        Ok(())
1135    }
1136    /// 1. Parse a [`LitStr`] from `input`.
1137    /// 2. Parse the contents of that string using [`FromStr`].
1138    /// 3. Assign the result to `dst`.
1139    pub fn from_str<T: FromStr>(dst: &mut T, input: ParseStream<'_>) -> syn::Result<()>
1140    where
1141        T::Err: Display,
1142    {
1143        let lit_str = input.parse::<LitStr>()?;
1144        match lit_str.value().parse() {
1145            Ok(it) => {
1146                *dst = it;
1147                Ok(())
1148            }
1149            Err(e) => Err(syn::Error::new(lit_str.span(), e)),
1150        }
1151    }
1152    /// 1. Parse a [`LitStr`] from `input`.
1153    /// 2. Parse the contents of that string into the [`Parse`]-able.
1154    /// 3. Assign the result to `dst`.
1155    pub fn parse_str<T: Parse>(dst: &mut T, input: ParseStream<'_>) -> syn::Result<()> {
1156        let lit_str = input.parse::<LitStr>()?;
1157        *dst = T::parse.parse_str(&lit_str.value())?;
1158        Ok(())
1159    }
1160    /// If `input` contains a [`LitStr`],
1161    /// then parse the contents of that string into the [`Parse`]-able.
1162    /// Else, directly parse it from `input`.
1163    pub fn maybe_str<T: Parse>(dst: &mut T, input: ParseStream<'_>) -> syn::Result<()> {
1164        *dst = match input.peek(LitStr) {
1165            true => input.parse::<LitStr>()?.parse()?,
1166            false => input.parse()?,
1167        };
1168        Ok(())
1169    }
1170    /// Parse the appropriate [`syn::Lit`] from `input`,
1171    /// extracting the value,
1172    /// and assigning the result to `dst`.
1173    pub fn lit<T: Lit>(dst: &mut T, input: ParseStream<'_>) -> syn::Result<()> {
1174        *dst = Lit::parse(input)?;
1175        Ok(())
1176    }
1177
1178    /// Collect from `input` until a `,` is encountered.
1179    pub fn until_comma(input: ParseStream<'_>) -> syn::Result<TokenStream> {
1180        input.step(|cursor| {
1181            let mut tokens = TokenStream::new();
1182            let mut rest = *cursor;
1183            while let Some((tt, cursor)) = rest.token_tree() {
1184                rest = cursor;
1185                match tt {
1186                    proc_macro2::TokenTree::Punct(it) if it.as_char() == ',' => break,
1187                    tt => tokens.extend([tt]),
1188                };
1189            }
1190            Ok((tokens, rest))
1191        })
1192    }
1193
1194    /// Straightforward parsing functions that set [`Option`]s.
1195    pub mod set {
1196        use super::*;
1197
1198        /// Parse a [`LitBool`] from `input`, assigning it to `dst` in [`Some`].
1199        #[deprecated = "Use `parse::set::lit` instead"]
1200        pub fn bool(dst: &mut Option<bool>, input: ParseStream<'_>) -> syn::Result<()> {
1201            *dst = Some(input.parse::<LitBool>()?.value);
1202            Ok(())
1203        }
1204        /// Parse a [`Parse`]-able from `input`, assigning it to `dst` in [`Some`].
1205        pub fn parse<T: Parse>(dst: &mut Option<T>, input: ParseStream<'_>) -> syn::Result<()> {
1206            *dst = Some(input.parse()?);
1207            Ok(())
1208        }
1209        /// 1. Parse a [`LitStr`] from `input`.
1210        /// 2. Parse the contents of that string using [`FromStr`].
1211        /// 3. Assign the result to `dst` in [`Some`].
1212        pub fn from_str<T: FromStr>(dst: &mut Option<T>, input: ParseStream<'_>) -> syn::Result<()>
1213        where
1214            T::Err: Display,
1215        {
1216            let lit_str = input.parse::<LitStr>()?;
1217            match lit_str.value().parse() {
1218                Ok(it) => {
1219                    *dst = Some(it);
1220                    Ok(())
1221                }
1222                Err(e) => Err(syn::Error::new(lit_str.span(), e)),
1223            }
1224        }
1225        /// 1. Parse a [`LitStr`] from `input`.
1226        /// 2. Parse the contents of that string into the [`Parse`]-able.
1227        /// 3. Assign the result to `dst` in [`Some`].
1228        pub fn parse_str<T: Parse>(dst: &mut Option<T>, input: ParseStream<'_>) -> syn::Result<()> {
1229            *dst = Some(input.parse::<LitStr>()?.parse()?);
1230            Ok(())
1231        }
1232
1233        /// If `input` contains a [`LitStr`],
1234        /// then parse the contents of that string into the [`Parse`]-able in [`Some`].
1235        /// Else, directly parse it from `input`.
1236        pub fn maybe_str<T: Parse>(dst: &mut Option<T>, input: ParseStream<'_>) -> syn::Result<()> {
1237            *dst = Some(match input.peek(LitStr) {
1238                true => input.parse::<LitStr>()?.parse()?,
1239                false => input.parse()?,
1240            });
1241            Ok(())
1242        }
1243        /// Parse the appropriate [`syn::Lit`] from `input`,
1244        /// extracting the value,
1245        /// and assigning the result to `dst` in [`Some`].
1246        pub fn lit<T: Lit>(dst: &mut Option<T>, input: ParseStream<'_>) -> syn::Result<()> {
1247            *dst = Some(Lit::parse(input)?);
1248            Ok(())
1249        }
1250    }
1251}
1252
1253/// A value that can be parsed by this crate from a [`syn::Lit`].
1254///
1255/// See [`set::lit`] and [`on::lit`] for usage examples.
1256///
1257/// This trait is sealed, and cannot be implemented for types outside this crate.
1258pub trait Lit: Sized + sealed::Sealed {
1259    fn parse(input: ParseStream<'_>) -> syn::Result<Self>;
1260}
1261
1262mod sealed {
1263    pub trait Sealed {}
1264    macro_rules! sealed {
1265            ($($ty:ty),* $(,)?) => {
1266                $(impl Sealed for $ty {})*
1267            };
1268        }
1269    sealed! {
1270        u8, u16, u32, u64, u128, usize,
1271        i8, i16, i32, i64, i128, isize,
1272        f32, f64,
1273        bool,
1274        char,
1275        String,
1276        Vec<u8>,
1277    }
1278}
1279
1280macro_rules! num {
1281        ($($via:ty {
1282            $($ty:ty),* $(,)?
1283        } )*) => {
1284            $(
1285                $(
1286                    impl Lit for $ty {
1287                        fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
1288                            let lit = input.parse::<$via>()?;
1289                            match lit.suffix() {
1290                                "" | stringify!($ty) => lit.base10_parse(),
1291                                _ => Err(syn::Error::new(
1292                                    lit.span(),
1293                                    concat!("Expected suffix `", stringify!($ty), "`"),
1294                                )),
1295                            }
1296                        }
1297                    }
1298                )*
1299            )*
1300        };
1301    }
1302
1303num! {
1304    syn::LitInt {
1305            u16, u32, u64, u128, usize,
1306        i8, i16, i32, i64, i128, isize,
1307    }
1308    syn::LitFloat {
1309        f32, f64
1310    }
1311}
1312
1313impl Lit for u8 {
1314    /// Note that bytes may parsed from a [`LitInt`](syn::LitInt) or a [`LitByte`](syn::LitByte).
1315    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
1316        match input.parse::<syn::Lit>()? {
1317            syn::Lit::Byte(it) => Ok(it.value()),
1318            syn::Lit::Int(it) => match it.suffix() {
1319                "" | "u8" => it.base10_parse(),
1320                _ => Err(syn::Error::new(it.span(), "Expected suffix `u8`")),
1321            },
1322            other => Err(syn::Error::new(
1323                other.span(),
1324                "Expected a u8 or byte literal",
1325            )),
1326        }
1327    }
1328}
1329
1330impl Lit for bool {
1331    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
1332        Ok(input.parse::<syn::LitBool>()?.value())
1333    }
1334}
1335impl Lit for String {
1336    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
1337        Ok(input.parse::<syn::LitStr>()?.value())
1338    }
1339}
1340impl Lit for Vec<u8> {
1341    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
1342        Ok(input.parse::<syn::LitByteStr>()?.value())
1343    }
1344}
1345impl Lit for char {
1346    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
1347        Ok(input.parse::<syn::LitChar>()?.value())
1348    }
1349}
1350
1351#[derive(Clone, Copy)]
1352struct Phrase<'a, I> {
1353    /// `Expected one of`
1354    pub many: &'a str,
1355    /// `Expected`
1356    pub one: &'a str,
1357    /// `No registered keys`
1358    pub none: &'a str,
1359    /// `or`
1360    pub conjunction: &'a str,
1361    pub iter: I,
1362}
1363
1364impl<I: Clone + IntoIterator> fmt::Display for Phrase<'_, I>
1365where
1366    I::Item: fmt::Display,
1367{
1368    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1369        let Self {
1370            many,
1371            one,
1372            none,
1373            conjunction,
1374            iter,
1375        } = self.clone();
1376        let mut iter = iter.into_iter().peekable();
1377        match iter.next() {
1378            Some(first) => match iter.peek() {
1379                Some(_) => {
1380                    f.write_fmt(format_args!("{many} `{first}`"))?;
1381                    while let Some(it) = iter.next() {
1382                        match iter.peek() {
1383                            Some(_) => f.write_fmt(format_args!(", `{it}`"))?,
1384                            None => f.write_fmt(format_args!(" {conjunction} `{it}`"))?,
1385                        }
1386                    }
1387                    Ok(())
1388                }
1389                None => f.write_fmt(format_args!("{one} `{first}`")),
1390            },
1391            None => f.write_str(none),
1392        }
1393    }
1394}