better_bae/
lib.rs

1//! This crate is a fork of [`bae`](https://docs.rs/bae).
2//!
3//! `better-bae` is a crate for proc macro authors, which simplifies parsing of attributes. It is
4//! heavily inspired by [`darling`](https://crates.io/crates/darling) but has a significantly
5//! simpler API.
6//!
7//! ```rust
8//! use better_bae::FromAttributes;
9//!
10//! #[derive(
11//!     Debug,
12//!     Eq,
13//!     PartialEq,
14//!
15//!     // This will add two functions:
16//!     // ```
17//!     // fn from_attributes(attrs: &[syn::Attribute]) -> Result<MyAttr, syn::Error>
18//!     // fn try_from_attributes(attrs: &[syn::Attribute]) -> Result<Option<MyAttr>, syn::Error>
19//!     // ```
20//!     //
21//!     // `try_from_attributes` returns `Ok(None)` if the attribute is missing, `Ok(Some(_))` if
22//!     // its there and is valid, `Err(_)` otherwise.
23//!     FromAttributes,
24//! )]
25//! pub struct MyAttr {
26//!     // Anything that implements `syn::parse::Parse` is supported.
27//!     mandatory_type: syn::Type,
28//!     mandatory_ident: syn::Ident,
29//!
30//!     // Fields wrapped in `Option` are optional and default to `None` if
31//!     // not specified in the attribute.
32//!     optional_missing: Option<syn::Type>,
33//!     optional_given: Option<syn::Type>,
34//!
35//!     // A "switch" is something that doesn't take arguments.
36//!     // All fields with type `Option<()>` are considered swiches.
37//!     // They default to `None`.
38//!     switch: Option<()>,
39//! }
40//!
41//! // `MyAttr` is now equipped to parse attributes named `my_attr`. For example:
42//! //
43//! //     #[my_attr(
44//! //         switch,
45//! //         mandatory_ident = foo,
46//! //         mandatory_type = SomeType,
47//! //         optional_given = OtherType,
48//! //     )]
49//! //     struct Foo {
50//! //         ...
51//! //     }
52//!
53//! // the input and output type would normally be `proc_macro::TokenStream` but those
54//! // types cannot be used outside the compiler itself.
55//! fn my_proc_macro(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
56//!     let item_struct = syn::parse2::<syn::ItemStruct>(input).unwrap();
57//!
58//!     let my_attr = MyAttr::from_attributes(&item_struct.attrs).unwrap();
59//!
60//!     assert_eq!(
61//!         my_attr.mandatory_type,
62//!         syn::parse_str::<syn::Type>("SomeType").unwrap()
63//!     );
64//!
65//!     assert_eq!(my_attr.optional_missing, None);
66//!
67//!     assert_eq!(
68//!         my_attr.optional_given,
69//!         Some(syn::parse_str::<syn::Type>("OtherType").unwrap())
70//!     );
71//!
72//!     assert_eq!(my_attr.mandatory_ident, syn::parse_str::<syn::Ident>("foo").unwrap());
73//!
74//!     assert_eq!(my_attr.switch.is_some(), true);
75//!
76//!     // ...
77//!     #
78//!     # quote::quote! {}
79//! }
80//! #
81//! # fn main() {
82//! #     let code = quote::quote! {
83//! #         #[other_random_attr]
84//! #         #[my_attr(
85//! #             switch,
86//! #             mandatory_ident = foo,
87//! #             mandatory_type = SomeType,
88//! #             optional_given = OtherType,
89//! #         )]
90//! #         struct Foo;
91//! #     };
92//! #     my_proc_macro(code);
93//! # }
94//! ```
95
96pub use better_bae_macros::FromAttributes;
97
98pub trait TryFromAttributes
99where
100    Self: Sized,
101{
102    fn attr_name() -> &'static str;
103
104    fn try_from_attributes(attrs: &[syn::Attribute]) -> syn::Result<Option<Self>>;
105
106    fn from_attributes(attrs: &[syn::Attribute]) -> syn::Result<Self> {
107        if let Some(attr) = Self::try_from_attributes(attrs)? {
108            Ok(attr)
109        } else {
110            Err(syn::Error::new(
111                proc_macro2::Span::call_site(),
112                &format!("missing attribute `#[{}]`", Self::attr_name()),
113            ))
114        }
115    }
116}