deluxe/lib.rs
1//! # Deluxe
2//!
3//! A procedural macro attribute parser.
4//!
5//! ### Abstract
6//!
7//! This crate offers attribute parsing closer to the design of attributes in C#. It has an
8//! interface similar to [serde](https://serde.rs). Attributes are written as plain Rust structs or
9//! enums, and then parsers for them are generated automatically. They can contain arbitrary
10//! expressions and can inherit from other attributes using a flattening mechanism.
11//!
12//! The parsers in this crate directly parse token streams using [`syn`]. As a result, most
13//! built-in Rust types and `syn` types can be used directly as fields.
14//!
15//! ### Usage
16//!
17//! Functionality in this crate is centered around three traits, and their respective derive macros:
18//! - **[`ExtractAttributes`](macro@ExtractAttributes)**
19//!
20//! Extracts attributes from an object containing a list of [`syn::Attribute`], and parses them
21//! into a Rust type. Should be implemented for top-level structures that will be parsed directly
22//! out of a set of matching attributes.
23//! - **[`ParseAttributes`](macro@ParseAttributes)**
24//!
25//! Parses a Rust type from any object containing a list of [`syn::Attribute`]. Should be used if
26//! the set of matching attributes can potentially be shared between this type and other types.
27//! - **[`ParseMetaItem`](macro@ParseMetaItem)**
28//!
29//! Parses a Rust type from a [`ParseStream`](syn::parse::ParseStream). Should be implemented for
30//! any types that can be nested inside an attribute.
31//!
32//! Basic usage of this crate in derive macros requires simply deriving one (or a few) of these
33//! traits, and then calling [`extract_attributes`] or [`parse_attributes`]. For more advanced
34//! functionality, several `#[deluxe(...)]` attributes are supported on structs, enums, variants
35//! and fields. See the examples below, and the documentation for each derive macro for a complete
36//! description of the supported attributes.
37//!
38//! A list of field types supported by default can be seen in the list of provided [`ParseMetaItem`
39//! implementations](trait@ParseMetaItem#foreign-impls). For more complex usage, manual
40//! implementations of these traits can be provided. See the documentation on individual traits in
41//! [`deluxe_core`] for more details on how to manually implement your own parsers.
42//!
43//! ### Related Crates
44//!
45//! Deluxe takes inspiration from the [darling](https://docs.rs/darling) crate, but offers a few
46//! enhancements over it. Darling is built around pre-parsed [`syn::Meta`] objects, and therefore
47//! is restricted to the [meta
48//! syntax](https://doc.rust-lang.org/stable/reference/attributes.html#meta-item-attribute-syntax).
49//! Deluxe parses its types directly from [`TokenStream`](proc_macro2::TokenStream) objects in the
50//! attributes and so is able to use any syntax that parses as a valid token tree. Deluxe also does
51//! not provide extra traits for parsing special `syn` objects like
52//! [`DeriveInput`](syn::DeriveInput) and [`Field`](syn::Field). Instead, Deluxe uses a generic
53//! trait to parse from any type containing a <code>[Vec]<[syn::Attribute]></code>.
54//!
55//! ### Examples
56//!
57//! #### Basic Derive Macro
58//!
59//! To create a derive macro that can add some simple metadata to a Rust type from an attribute,
60//! start by defining a struct that derives [`ExtractAttributes`](macro@ExtractAttributes). Then,
61//! call [`extract_attributes`] in your derive macro to create an instance of the struct:
62//!
63//! ```
64//! #[derive(deluxe::ExtractAttributes)]
65//! #[deluxe(attributes(my_desc))]
66//! struct MyDescription {
67//! name: String,
68//! version: String,
69//! }
70//!
71//! fn my_derive(item: proc_macro2::TokenStream) -> deluxe::Result<proc_macro2::TokenStream> {
72//! let mut input = syn::parse2::<syn::DeriveInput>(item)?;
73//!
74//! // Extract the attributes!
75//! let MyDescription { name, version } = deluxe::extract_attributes(&mut input)?;
76//!
77//! // Now get some info to generate an associated function...
78//! let ident = &input.ident;
79//! let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
80//!
81//! Ok(quote::quote! {
82//! impl #impl_generics #ident #type_generics #where_clause {
83//! fn my_desc() -> &'static str {
84//! concat!("Name: ", #name, ", Version: ", #version)
85//! }
86//! }
87//! })
88//! }
89//!
90//! # let tokens = my_derive(quote::quote! {
91//! # #[my_desc(name = "hello world", version = "0.2")]
92//! # struct Hello;
93//! # }).unwrap();
94//! # let i: syn::ItemImpl = syn::parse_quote! { #tokens };
95//! # assert_eq!(i, syn::parse_quote! {
96//! # impl Hello {
97//! # fn my_desc() -> &'static str {
98//! # concat!("Name: ", "hello world", ", Version: ", "0.2")
99//! # }
100//! # }
101//! # });
102//! ```
103//!
104//! Then, try adding the attribute in some code that uses your macro:
105//!
106//! ```ignore
107//! // In your macros crate
108//!
109//! #[proc_macro_derive(MyDescription, attributes(my_desc))]
110//! pub fn derive_my_description(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
111//! my_derive(item.into()).unwrap().into()
112//! }
113//! ```
114//!
115//! ```ignore
116//! // In your normal code
117//!
118//! #[derive(MyDescription, Default)]
119//! #[my_desc(name = "hello world", version = "0.2")]
120//! struct Hello {
121//! a: i32,
122//! b: String
123//! }
124//!
125//! let hello: Hello = Default::default();
126//! assert_eq!(hello.my_desc(), "Name: hello world, Version: 0.2");
127//! ```
128//!
129//! #### Basic Attribute Macro
130//!
131//! The `parse` and `parse2` functions included in this crate can also be used as simple helpers
132//! for attribute macros:
133//!
134//! ```
135//! #[derive(deluxe::ParseMetaItem)]
136//! struct MyDescription {
137//! name: String,
138//! version: String,
139//! }
140//!
141//! fn my_desc_attr(
142//! attr: proc_macro2::TokenStream,
143//! item: proc_macro2::TokenStream,
144//! ) -> deluxe::Result<proc_macro2::TokenStream> {
145//! let MyDescription { name, version } = deluxe::parse2::<MyDescription>(attr)?;
146//!
147//! Ok(quote::quote! {
148//! fn my_desc() -> &'static str {
149//! concat!("Name: ", #name, ", Version: ", #version)
150//! }
151//! #item
152//! })
153//! }
154//!
155//! # let tokens = my_desc_attr(
156//! # quote::quote!(name = "hello world", version = "0.2"),
157//! # quote::quote!(),
158//! # ).unwrap();
159//! # let f: syn::ItemFn = syn::parse_quote! { #tokens };
160//! # assert_eq!(f, syn::parse_quote! {
161//! # fn my_desc() -> &'static str {
162//! # concat!("Name: ", "hello world", ", Version: ", "0.2")
163//! # }
164//! # });
165//! ```
166//!
167//! ```ignore
168//! // In your macros crate
169//!
170//! #[proc_macro_attribute]
171//! pub fn my_desc(
172//! attr: proc_macro::TokenStream,
173//! item: proc_macro::TokenStream,
174//! ) -> proc_macro::TokenStream {
175//! my_desc_attr(attr.into(), item.into()).unwrap().into()
176//! }
177//! ```
178//!
179//! ```ignore
180//! // In your normal code
181//!
182//! #[my_desc(name = "hello world", version = "0.2")]
183//! fn nothing() {}
184//!
185//! assert_eq!(my_desc(), "Name: hello world, Version: 0.2");
186//! ```
187//!
188//! #### Field Attributes
189//!
190//! The attributes [`alias`](macro@ParseMetaItem#deluxealias--ident-1),
191//! [`default`](macro@ParseMetaItem#deluxedefault-1),
192//! [`rename`](macro@ParseMetaItem#deluxerename--ident-1), and
193//! [`skip`](macro@ParseMetaItem#deluxeskip-1) are supported, and behave the same as in Serde. The
194//! [`append`](macro@ParseMetaItem#deluxeappend) attribute can be used on [`Vec`] fields to
195//! aggregate all duplicates of a key. The [`rest`](macro@ParseMetaItem#deluxerest) attribute can
196//! be used to do custom processing on any unknown keys.
197//!
198//! ```
199//! #[derive(deluxe::ExtractAttributes)]
200//! #[deluxe(attributes(my_object))]
201//! struct MyObject {
202//! // Can be specified with key `id` or `object_id`
203//! #[deluxe(alias = object_id)]
204//! id: u64,
205//!
206//! // Field is optional, defaults to `Default::default` if not present
207//! #[deluxe(default)]
208//! count: u64,
209//!
210//! // Defaults to "Empty" if not present
211//! #[deluxe(default = String::from("Empty"))]
212//! contents: String,
213//!
214//! // Can be specified only with key `name`
215//! #[deluxe(rename = name)]
216//! s: String,
217//!
218//! // Skipped during parsing entirely
219//! #[deluxe(skip)]
220//! internal_flag: bool,
221//!
222//! // Appends any extra fields with the key `expr` to the Vec
223//! #[deluxe(append, rename = expr)]
224//! exprs: Vec<syn::Expr>,
225//!
226//! // Adds any unknown keys to the hash map
227//! #[deluxe(rest)]
228//! rest: std::collections::HashMap<syn::Path, syn::Expr>,
229//! }
230//! ```
231//!
232//! ```ignore
233//! // Omitted fields will be set to defaults
234//! #[derive(MyObject)]
235//! #[my_object(id = 1, name = "First", expr = 1 + 2, count = 3)]
236//! struct FirstObject;
237//!
238//! // `expr` can be specified multiple times because of the `append` attribute
239//! #[derive(MyObject)]
240//! #[my_object(object_id = 2, name = "Second", expr = 1 + 2, expr = 3 + 4)]
241//! struct SecondObject;
242//!
243//! // `unknown` and `extra` will be stored in the `rest` hashmap
244//! #[derive(MyObject)]
245//! #[my_object(id = 3, name = "Third", unknown = 1 + 2, extra = 3 + 4)]
246//! struct ThirdObject;
247//! ```
248//!
249//! #### Inheritance
250//!
251//! The [`flatten`](macro@ParseMetaItem#deluxeflatten-1) attribute can be used to parse keys from
252//! one structure inside another:
253//!
254//! ```
255//! #[derive(deluxe::ParseMetaItem)]
256//! struct A {
257//! id: u64,
258//! }
259//!
260//! #[derive(deluxe::ExtractAttributes)]
261//! #[deluxe(attributes(b))]
262//! struct B {
263//! #[deluxe(flatten)]
264//! a: A,
265//! name: String,
266//! }
267//! ```
268//!
269//! Then, fields from both `A` and `B` can be used when deriving `B`:
270//!
271//! ```ignore
272//! #[derive(B)]
273//! #[b(id = 123, name = "object")]
274//! struct Object;
275//! ```
276//!
277//! #### Attributes in Nested Code
278//!
279//! Extra attributes can be taken from within the code block attached to a macro. When used in an
280//! attribute macro, the attributes should be consumed so as not to produce an "unknown attribute"
281//! error when outputting tokens.
282//!
283//! ```
284//! #[derive(deluxe::ParseMetaItem, deluxe::ExtractAttributes)]
285//! struct MyDescription {
286//! name: String,
287//! version: String,
288//! }
289//!
290//! #[derive(deluxe::ExtractAttributes)]
291//! #[deluxe(attributes(author))]
292//! struct Authors(#[deluxe(flatten)] Vec<String>);
293//!
294//! fn my_derive(item: proc_macro2::TokenStream) -> deluxe::Result<proc_macro2::TokenStream> {
295//! let mut input = syn::parse2::<syn::DeriveInput>(item)?;
296//! let MyDescription { name, version } = deluxe::extract_attributes(&mut input)?;
297//! let mut authors = Vec::new();
298//! if let syn::Data::Struct(s) = &mut input.data {
299//! // Look through all fields in the struct for `author` attributes
300//! for field in s.fields.iter_mut() {
301//! let Authors(a) = deluxe::extract_attributes(field)?;
302//! authors.extend(a);
303//! }
304//! }
305//!
306//! let ident = &input.ident;
307//! let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
308//!
309//! Ok(quote::quote! {
310//! impl #impl_generics #ident #type_generics #where_clause {
311//! fn my_desc() -> &'static str {
312//! concat!("Name: ", #name, ", Version: ", #version #(, ", Author: ", #authors)*)
313//! }
314//! }
315//! })
316//! }
317//!
318//! # let tokens = my_derive(quote::quote! {
319//! # #[my_desc(name = "hello world", version = "0.2")]
320//! # struct Hello(#[author("Alice")] String);
321//! # }).unwrap();
322//! # let i: syn::ItemImpl = syn::parse_quote! { #tokens };
323//! # assert_eq!(i, syn::parse_quote! {
324//! # impl Hello {
325//! # fn my_desc() -> &'static str {
326//! # concat!("Name: ", "hello world", ", Version: ", "0.2", ", Author: ", "Alice")
327//! # }
328//! # }
329//! # });
330//!
331//! fn my_desc_mod(
332//! attr: proc_macro2::TokenStream,
333//! item: proc_macro2::TokenStream,
334//! ) -> deluxe::Result<proc_macro2::TokenStream> {
335//! let MyDescription { name, version } = deluxe::parse2::<MyDescription>(attr)?;
336//! let mut authors = Vec::new();
337//! let mut module = syn::parse2::<syn::ItemMod>(item)?;
338//!
339//! let (_, items) = module.content.as_mut().unwrap();
340//!
341//! // Look through all items in the module for `author` attributes
342//! for i in items.iter_mut() {
343//! // Extract the attributes to remove them from the final output
344//! let Authors(a) = deluxe::extract_attributes(i)?;
345//! authors.extend(a);
346//! }
347//!
348//! // Place a new function inside the module
349//! items.push(syn::parse_quote! {
350//! fn my_desc() -> &'static str {
351//! concat!("Name: ", #name, ", Version: ", #version #(, ", Author: ", #authors)*)
352//! }
353//! });
354//!
355//! Ok(quote::quote! { #module })
356//! }
357//!
358//! # let tokens = my_desc_mod(
359//! # quote::quote!(name = "hello world", version = "0.2"),
360//! # quote::quote!(mod abc {
361//! # #[author("Alice", "Bob")]
362//! # fn func1() {}
363//! # #[author("Carol")]
364//! # #[author("Dave")]
365//! # fn func2() {}
366//! # }),
367//! # ).unwrap();
368//! # let m: syn::ItemMod = syn::parse_quote! { #tokens };
369//! # assert_eq!(m, syn::parse_quote! {
370//! # mod abc {
371//! # fn func1() {}
372//! # fn func2() {}
373//! # fn my_desc() -> &'static str {
374//! # concat!(
375//! # "Name: ", "hello world", ", Version: ", "0.2",
376//! # ", Author: ", "Alice", ", Author: ", "Bob",
377//! # ", Author: ", "Carol", ", Author: ", "Dave"
378//! # )
379//! # }
380//! # }
381//! # });
382//! ```
383//!
384//! ```ignore
385//! // In your normal code
386//!
387//! #[derive(MyDescription, Default)]
388//! #[my_desc(name = "hello world", version = "0.2")]
389//! struct Hello {
390//! #[author("Alice")]
391//! a: i32,
392//! #[author("Bob")]
393//! b: String
394//! }
395//!
396//! let hello: Hello = Default::default();
397//! assert_eq!(hello.my_desc(), "Name: hello world, Version: 0.2, Author: Alice, Author: Bob");
398//!
399//! #[my_desc_mod(name = "hello world", version = "0.2")]
400//! mod abc {
401//! #[author("Alice", "Bob")]
402//! fn func1() {}
403//!
404//! #[author("Carol")]
405//! #[author("Dave")]
406//! fn func2() {}
407//! }
408//!
409//! assert_eq!(
410//! abc::my_desc(),
411//! "Name: hello world, Version: 0.2, Author: Alice, Author: Bob, Author: Carol, Author: Dave"
412//! );
413//! ```
414//!
415//! #### Tuple Structs, Tuples and Vecs
416//!
417//! Deluxe also supports parsing into data structures with unnamed fields.
418//!
419//! ```
420//! #[derive(deluxe::ExtractAttributes)]
421//! #[deluxe(attributes(my_tuple))]
422//! struct MyTuple(u64, String);
423//!
424//! #[derive(deluxe::ExtractAttributes)]
425//! #[deluxe(attributes(my_idents))]
426//! struct MyIdents {
427//! id: u64,
428//! names: (String, String),
429//! idents: Vec<syn::Ident>
430//! }
431//! ```
432//!
433//! The standard attribute syntax with parenthesis can be used when specifying a [`Vec`] type. The
434//! alternative syntax `key = [...]` can also be used to have an appearance similar to an array
435//! literal.
436//!
437//! ```ignore
438//! #[derive(MyTuple)]
439//! #[my_tuple(123, "object")]
440//! struct Object;
441//!
442//! #[derive(MyIdents)]
443//! #[my_idents(id = 7, names("hello", "world"), idents(a, b, c))]
444//! struct ABC;
445//!
446//! // `idents` contains same values as above
447//! #[derive(MyIdents)]
448//! #[my_idents(id = 7, names("hello", "world"), idents = [a, b, c])]
449//! struct ABC2;
450//! ```
451//!
452//! #### C#-styled Attributes
453//!
454//! Attributes in C# can support positional arguments first with the named
455//! arguments afterwards. This style can be emulated by using a tuple struct with a
456//! normal struct flattened at the end. Placing
457//! [`#[deluxe(default)]`](macro@ParseMetaItem#deluxedefault) on the struct behaves the same as
458//! Serde, by filling in all fields with values from [`Default`], allowing every named argument to
459//! be optional.
460//!
461//! ```
462//! #[derive(deluxe::ParseMetaItem, Default)]
463//! #[deluxe(default)]
464//! struct Flags {
465//! native: bool,
466//! }
467//!
468//! #[derive(deluxe::ExtractAttributes)]
469//! #[deluxe(attributes(a))]
470//! struct A(u64, String, #[deluxe(flatten)] Flags);
471//! ```
472//!
473//! ```ignore
474//! #[derive(A)]
475//! #[a(123, "object")]
476//! struct Object;
477//!
478//! #[derive(A)]
479//! #[a(123, "native-object", native = true)]
480//! struct NativeObject;
481//! ```
482//!
483//! #### Enums
484//!
485//! Enums are supported by using the variant name as a single key, in snake-case. Variants can be
486//! renamed, aliased and skipped in the same way as fields.
487//!
488//! ```
489//! #[derive(deluxe::ExtractAttributes)]
490//! #[deluxe(attributes(my_enum))]
491//! enum MyEnum {
492//! A,
493//! B,
494//! C,
495//! #[deluxe(alias = d)]
496//! AnotherOne,
497//! #[deluxe(rename = e)]
498//! AnotherTwo,
499//! #[deluxe(skip)]
500//! SkipMe
501//! }
502//! ```
503//!
504//! ```ignore
505//! #[derive(MyEnum)]
506//! #[my_enum(b)]
507//! struct ObjectB;
508//!
509//! #[derive(MyEnum)]
510//! #[my_enum(another_one)]
511//! struct ObjectD;
512//! ```
513//!
514//! #### Complex Enums
515//!
516//! Enums with struct and tuple variants are also supported. The data inside is used as arguments
517//! to the attribute. All field attributes from structs are also supported inside variants.
518//!
519//! Additionally, enum variants with named fields can be flattened. The behavior of a flattened
520//! variant is similar to Serde's `untagged` mode. In a flattened variant, the name of the variant
521//! will be ignored. Instead, Deluxe will attempt to use the unique keys in each variant to
522//! determine if that variant was specified. A compile error will be thrown if it is not possible
523//! to determine a unique, unambiguous key between two variants.
524//!
525//! ```
526//! #[derive(deluxe::ExtractAttributes)]
527//! #[deluxe(attributes(my_enum))]
528//! enum MyEnum {
529//! A,
530//! B(u64, String),
531//! C { id: u64, name: String },
532//! #[deluxe(flatten)]
533//! D { d: u64, name: String },
534//! }
535//! ```
536//!
537//! ```ignore
538//! #[derive(MyEnum)]
539//! #[my_enum(a)]
540//! struct ObjectA;
541//!
542//! #[derive(MyEnum)]
543//! #[my_enum(b(1, "hello"))]
544//! struct ObjectB;
545//!
546//! #[derive(MyEnum)]
547//! #[my_enum(c(id = 2, name = "world"))]
548//! struct ObjectC;
549//!
550//! // No inner parenthesis needed here due to flattening
551//! #[derive(MyEnum)]
552//! #[my_enum(d = 3, name = "moon")]
553//! struct ObjectD;
554//! ```
555//!
556//! #### Storing Containers
557//!
558//! During parsing, Deluxe can store references to the container type holding the attributes for
559//! easier access. Container fields are skipped during attribute parsing.
560//!
561//! ```
562//! #[derive(deluxe::ParseAttributes)]
563//! #[deluxe(attributes(my_object))]
564//! struct MyObject<'t> {
565//! id: u64,
566//! // Fill `container` in using the parsed type. Note this restricts the
567//! // derived `ParseAttributes` impl so it can only be used on `DeriveInput`.
568//! #[deluxe(container)]
569//! container: &'t syn::DeriveInput,
570//! }
571//!
572//! fn my_object(item: proc_macro2::TokenStream) -> deluxe::Result<proc_macro2::TokenStream> {
573//! let input = syn::parse2::<syn::DeriveInput>(item)?;
574//!
575//! // `obj.container` now holds a reference to `input`
576//! let obj: MyObject = deluxe::parse_attributes(&input)?;
577//!
578//! Ok(quote::quote! { /* ... generate some code here ... */ })
579//! }
580//! ```
581//!
582//! To support both extracting and parsing, a container field can also be a value type. In that
583//! case, the container will be cloned into the structure.
584
585#![deny(missing_docs)]
586#![deny(unsafe_code)]
587
588#[doc(hidden)]
589pub mod ____private {
590 pub use deluxe_core::parse_helpers::{self, FieldStatus, SmallString};
591 pub use once_cell::sync::OnceCell as SyncOnceCell;
592 pub use proc_macro2::Span;
593 pub use std::{
594 borrow::{Borrow, Cow, ToOwned},
595 clone::Clone,
596 collections::HashMap,
597 convert::{AsRef, From},
598 default::Default,
599 format, format_args,
600 iter::IntoIterator,
601 option::Option,
602 primitive::{bool, str, usize},
603 string::{String, ToString},
604 unreachable,
605 vec::Vec,
606 };
607 pub use syn::{
608 parse::{ParseBuffer, ParseStream},
609 Error, Ident, Path,
610 };
611}
612
613pub use deluxe_core::{
614 define_with_collection, define_with_map, define_with_optional, parse_named_meta_item_with,
615 with, Error, Errors, ExtractAttributes, Flag, HasAttributes, ParseAttributes, ParseMetaItem,
616 ParseMode, Result, SpannedValue,
617};
618#[doc(hidden)]
619pub use deluxe_core::{
620 ContainerFrom, ParseMetaAppend, ParseMetaFlatNamed, ParseMetaFlatUnnamed, ParseMetaRest,
621 ToKeyString,
622};
623pub use deluxe_macros::*;
624
625/// Additional helper functions for validating after parsing.
626pub mod validations {
627 pub use deluxe_core::validations::*;
628 pub use deluxe_core::{all_or_none, only_one};
629}
630
631#[cfg(feature = "proc-macro")]
632extern crate proc_macro;
633
634/// Parses a required Rust type out of a token stream.
635///
636/// Intended for use with [attribute
637/// macros](https://doc.rust-lang.org/stable/reference/procedural-macros.html#attribute-macros).
638/// This is a small wrapper around [`syn::parse::Parser::parse`] and
639/// [`ParseMetaItem::parse_meta_item_inline`].
640#[cfg(feature = "proc-macro")]
641#[inline]
642pub fn parse<T: ParseMetaItem>(attr: proc_macro::TokenStream) -> Result<T> {
643 syn::parse::Parser::parse(
644 |stream: syn::parse::ParseStream<'_>| {
645 T::parse_meta_item_inline(&[stream], ParseMode::Named(proc_macro2::Span::call_site()))
646 },
647 attr,
648 )
649}
650
651/// Parses a required Rust type out of a token stream.
652///
653/// Intended for use with [attribute
654/// macros](https://doc.rust-lang.org/stable/reference/procedural-macros.html#attribute-macros).
655/// This is a small wrapper around [`syn::parse::Parser::parse2`] and
656/// [`ParseMetaItem::parse_meta_item_inline`].
657#[inline]
658pub fn parse2<T: ParseMetaItem>(attr: proc_macro2::TokenStream) -> Result<T> {
659 syn::parse::Parser::parse2(
660 |stream: syn::parse::ParseStream<'_>| {
661 T::parse_meta_item_inline(&[stream], ParseMode::Named(proc_macro2::Span::call_site()))
662 },
663 attr,
664 )
665}
666
667/// Parses a required Rust type out of another type holding a list of [`syn::Attribute`].
668///
669/// Intended for use with [derive
670/// macros](https://doc.rust-lang.org/stable/reference/procedural-macros.html#derive-macros). This
671/// is a small wrapper around [`ParseAttributes::parse_attributes`].
672#[inline]
673pub fn parse_attributes<'t, T, R>(obj: &'t T) -> Result<R>
674where
675 T: HasAttributes,
676 R: ParseAttributes<'t, T>,
677{
678 R::parse_attributes(obj)
679}
680
681/// Extracts attributes out of another type holding a list of [`syn::Attribute`], then parses them
682/// into a required Rust type.
683///
684/// Intended for use with [derive
685/// macros](https://doc.rust-lang.org/stable/reference/procedural-macros.html#derive-macros). This
686/// is a small wrapper around [`ExtractAttributes::extract_attributes`].
687#[inline]
688pub fn extract_attributes<T, R>(obj: &mut T) -> Result<R>
689where
690 T: HasAttributes,
691 R: ExtractAttributes<T>,
692{
693 R::extract_attributes(obj)
694}
695
696/// Parses a Rust type out of a token stream, returning a default value on failure.
697///
698/// Calls [`parse`] and returns the result. Upon failure, [`Default::default`] will be returned and
699/// any errors will be appended to `errors`. This function should be preferred when parsing
700/// multiple attributes, so the errors from all of them can be accumulated instead of returning
701/// early.
702#[cfg(feature = "proc-macro")]
703#[inline]
704pub fn parse_optional<T: ParseMetaItem + Default>(
705 attr: proc_macro::TokenStream,
706 errors: &Errors,
707) -> T {
708 match parse(attr) {
709 Ok(t) => t,
710 Err(e) => {
711 errors.push_syn(e);
712 Default::default()
713 }
714 }
715}
716
717/// Parses a Rust type out of a token stream, returning a default value on failure.
718///
719/// Calls [`parse2`] and returns the result. Upon failure, [`Default::default`] will be returned
720/// and any errors will be appended to `errors`. This function should be preferred when parsing
721/// multiple attributes, so the errors from all of them can be accumulated instead of returning
722/// early.
723#[inline]
724pub fn parse2_optional<T: ParseMetaItem + Default>(
725 attr: proc_macro2::TokenStream,
726 errors: &Errors,
727) -> T {
728 match parse2(attr) {
729 Ok(t) => t,
730 Err(e) => {
731 errors.push_syn(e);
732 Default::default()
733 }
734 }
735}
736
737/// Parses a Rust type out of another type holding a list of [`syn::Attribute`], returning a default value on failure.
738///
739/// Calls [`parse_attributes`] and returns the result. Upon failure, [`Default::default`] will be
740/// returned and any errors will be appended to `errors`. This function should be preferred when
741/// parsing multiple attributes, so the errors from all of them can be accumulated instead of
742/// returning early.
743#[inline]
744pub fn parse_attributes_optional<'t, T, R>(obj: &'t T, errors: &Errors) -> R
745where
746 T: HasAttributes,
747 R: ParseAttributes<'t, T> + Default,
748{
749 match parse_attributes(obj) {
750 Ok(t) => t,
751 Err(e) => {
752 errors.push_syn(e);
753 Default::default()
754 }
755 }
756}
757
758/// Extracts attributes out of another type holding a list of [`syn::Attribute`], then parses them
759/// into a Rust type, returning a default value on failure.
760///
761/// Calls [`extract_attributes`] and returns the result. Upon failure, [`Default::default`] will be
762/// returned and any errors will be appended to `errors`. This function should be preferred when
763/// parsing multiple attributes, so the errors from all of them can be accumulated instead of
764/// returning early.
765#[inline]
766pub fn extract_attributes_optional<T, R>(obj: &mut T, errors: &Errors) -> R
767where
768 T: HasAttributes,
769 R: ExtractAttributes<T> + Default,
770{
771 match extract_attributes(obj) {
772 Ok(t) => t,
773 Err(e) => {
774 errors.push_syn(e);
775 Default::default()
776 }
777 }
778}