derive_attribute/
lib.rs

1
2//! # Derive-Attribute   [![Latest Version]][crates.io] [![Documentation]][docs.rs]
3//!
4//! [Latest Version]: https://img.shields.io/crates/v/derive-attribute.svg
5//! [crates.io]: https://crates.io/crates/derive-attribute
6//!
7//! [Documentation]: https://docs.rs/derive-attribute/badge.svg
8//! [docs.rs]: https://docs.rs/derive-attribute
9//!
10//! ### **A set of macros to automatically deserialize standard attributes**
11//! - #### Compatible with all major versions of [Syn](https://crates.io/crates/syn)
12//! - #### Supports custom deserialization
13//! - #### Can return multiple errors at once
14//! - #### Allows for flexible attribute syntax
15//!
16//! ## Syn Compatibility
17//! This crate is meant to be used in conjunction with Syn within a procedural macro crate.<br/>
18//! A major version of Syn can be selected as a feature like: `features = ["syn_2"]`.
19//!
20//! Note: A Syn version must be selected
21//!
22//!
23//! ## Flexible Attribute Syntax
24//!
25//! #### **Implicit Booleans**
26//! ` #[some_attr(is_bool)] ` *can also be written as* ` #[some_attr(is_bool = true)] ` <br/>
27//! #### **Seperated Lists**
28//! ` #[some_attr(list(key_a = "value", key_b = 123))] `
29//! <br/>
30//! *can also be written as*
31//! <br/>
32//! ` #[some_attr(list(key_a = "value"))] ` <br/>
33//! ` #[some_attr(list(key_b = 123))] `
34//!
35//!
36//! ## Multiple Errors
37//! Most macros will only return one attribute error at a time. </br>
38//! This crate's macros can return multiple errors at once resulting in a better developer experience.
39//!
40//! ## Custom Deserialization
41//! Any type that implements `TryFromMeta` can be used as a valid attribute type. </br>
42//! Although Its recommended that you use `CustomArgFromMeta` instead in order to simplify the implementation.
43//!
44//! See [example](#custom-deserialization-1)
45//! <br/>
46//!
47//! ## Attr Arguments
48//! The `#[attr()]` attribute can be added to the attribute struct or its fields to add additional options.
49//!
50//! **The full list of arguments are:**
51//!
52//! **name [<span style = "color: lightblue">str</span>]** - Renames the field.
53//!
54//! **default [<span style = "color: lightblue">bool/str</span>]** - Uses a default value if the argument isn't found.
55//! <span style = "font-size: 10px"> </span><br/>
56//! If its a boolean, the type's implementation of Default::default will be used. \
57//! If its a string, it must be a path to a function that returns the type. 
58//!
59//! # Usage
60//! Our attribute type is declared in a procedural macro crate:
61//! ```rust
62//! #[derive(Attribute)]
63//! #[attr(name = "my_attr")] // We set the attribute name to 'my_attr'
64//! struct MyAttribute {      // Note: The attribute name will be the struct name in snake_case by default
65//!     name: String,
66//!     // wrapping a type in an option will make it optional
67//!     list: Option<NestedList>, // deserializes a meta list named list i.e. list(num = 1)
68//!
69//!     // booleans are always optional
70//!     is_selected: bool,
71//! }
72//!     #[derive(List)]
73//!     pub struct NestedList {
74//!         num: Option<u8>
75//!     }
76//! ```
77//! It can then be used to parse the following attribute using the from_attrs method:
78//!
79//! ```rust
80//! #[my_attr(name = "some_name", is_selected)]
81//! ```
82//! <br/>
83//!
84//! ***lets look at the same attribute used in a derive macro***
85//!
86//! ## Basic derive
87//!
88//! procedural macro crate:
89//! ```rust
90//!
91//! use derive_attribute::{Attribute, List};
92//! use proc_macro2::TokenStream as TokenStream2;
93//! use quote::quote;
94//! use syn::{parse_macro_input, DeriveInput};
95//!
96//!
97//! #[derive(Attribute)]
98//! #[attr(name = "my_attr")]
99//! struct MyAttribute {
100//!     name: String,
101//!     // wrapping a type in an option will make it optional
102//!     // deserializes a meta list named list i.e. list(num = 1) 
103//!     list: Option<NestedList>,
104//!     // booleans are always optional
105//!     is_selected: bool,
106//! }
107//!     #[derive(List)]
108//!     pub struct NestedList {
109//!         num: Option<u8>
110//!     }
111//!
112//!
113//! #[proc_macro_derive(YOUR_MACRO_NAME, attributes(my_attr))]
114//! pub fn derive_my_trait(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
115//!     let ast = parse_macro_input!(tokens as DeriveInput);
116//!
117//!     fn attempt_derive(ast: DeriveInput) -> Result<TokenStream2, Vec<syn::Error>> {
118//!         // Wrapping an attribute in an option makes it optional
119//!         // A missing error won't be returnwd
120//!         let maybe_attribute = <Option<MyAttribute>>::from_attrs(ast.ident.span(), &ast.attrs)?;
121//!
122//!         let output: TokenStream2 = {
123//!             // Your Macro Generation Code
124//!         };
125//!
126//!         Ok(output)
127//!     }
128//!
129//!
130//!     let generated_tokens = 
131//!         match attempt_derive(ast) {
132//!             Ok(tokens) => tokens,
133//!             Err(errors) => {
134//!                 let compile_errors = errors.into_iter().map(|e| e.to_compile_error());
135//!                 quote!(#(#compile_errors)*)
136//!             }
137//!         };
138//!
139//!     generated_tokens.into()
140//! }
141//! ```
142//!
143//! Another crate using our macro
144//!
145//! ```rust
146//! #[derive(YOUR_MACRO_NAME)]
147//! #[my_attr(name = "some_name", is_selected)]
148//! struct SomeStruct;
149//! ```
150//!
151//! <br/>
152//!
153//! ***Now lets add our own argument type***
154//!
155//! ## Custom Deserialization
156//!
157//! proc-macro crate:
158//! ```rust
159//! use derive_attribute::{CustomArg, CustomArgFromMeta};
160//!
161//! struct ErrorType {
162//!     Warning,
163//!     Severe
164//! }
165//!
166//! // Any type that implements 'TryFromMeta' can be deserialized however its a bit verbose
167//! // In order to simplify the implementation we can implement 'CustomArgFromMeta' instead and wrap our type in the 'CustomArg' struct
168//! impl<V: SynVersion> CustomArgFromMeta<V> for ErrorType {
169//!     fn try_from_meta(meta: Self::Metadata) -> Result<Self, ErrorMsg> {
170//!         let maybe_error_kind = 
171//!             match V::deserialize_string(meta) {
172//!                 Some(string) => {
173//!                     match string.to_string().as_str() {
174//!                         "warning" => Some(Self::Warning),
175//!                         "severe" => Some(Self::Severe),
176//!                         _ => None
177//!                     }
178//!                 }
179//!                 None => None
180//!             };
181//!
182//!         match maybe_error_kind {
183//!             Some(error_kind) => Ok(error_kind),
184//!             None => Err(InvalidType { expected: r#" "warning" or "severe" "# })
185//!         }
186//!     }
187//! }
188//!
189//! ```
190//!
191//! Our attribute struct now looks like this: 
192//! ```rust
193//! #[derive(Attribute)]
194//! #[attr(name = "my_attr")]
195//! struct MyAttribute {
196//!     // In order to use the simplified trait(CustomArgFromMeta) we need to wrap our struct in 'CustomArg'
197//!     error_type: CustomArg<ErrorType>,
198//!
199//!     name: String,
200//!     list: Option<u32>,
201//!     is_selected: bool,
202//! }
203//! ```
204//! Another crate using our macro:
205//! ```rust
206//! #[derive(YOUR_MACRO_NAME)]
207//! #[error(error_type = "warning", name = "some_name", is_selected)]
208//! struct Test;
209//! ```
210
211
212
213pub use derive_attribute_utils::*;
214pub use derive_attribute_macros::*;
215
216mod prelude {
217    pub use derive_attribute_utils::{GetSpan, Attribute, TryFromMeta};
218}