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}