attribute_derive/
lib.rs

1#![warn(missing_docs)]
2//! Basically clap for attribute macros:
3//! ```
4//! use attribute_derive::FromAttr;
5//! #[derive(FromAttr)]
6//! #[from_attr(ident = attr_name)]
7//! // overriding the builtin error messages
8//! #[from_attr(error(missing_field = "`{field}` was not specified"))]
9//! struct MyAttribute {
10//!     // Positional values need to be specified before any named ones
11//!     #[from_attr(positional)]
12//!     positional: u8,
13//!     // Options are optional by default (will be set to None if not specified)
14//!     optional: Option<String>,
15//!     required: String,
16//!     // Any type implementing default can be flagged as default
17//!     // This will be set to Vec::default() when not specified
18//!     #[from_attr(optional)]
19//!     list: Vec<syn::Type>,
20//!     // Booleans can be used without assigning a value, i.e., as a flag.
21//!     // If omitted they are set to false
22//!     some_flag: bool,
23//! }
24//! ```
25//!
26//! Will be able to parse an attribute like this:
27//! ```rust
28//! # #[cfg(no)]
29//! #[attr_name(5, optional="some", required = r#"string"#, some_flag, list = [Option, ()])]
30//! // or
31//! #[attr_name(5, required = "string", list(Option, ()))]
32//! # struct Placeholder;
33//! ```
34//!
35//! Any type that for [`AttributeNamed`] or [`AttributePositional`] are
36//! implemented respectively are supported. These should be the general types
37//! that [`syn`] supports like [`LitStr`](struct@LitStr) or [`Type`] or that
38//! have a direct equivalent in those like [`String`], [`char`] or [`f32`]. A
39//! special treatment have [`Vecs`](Vec) which are parsed as either `name = [a,
40//! b, c]` or `name(a, b, c)` and [`Options`](Option) that will be [`None`] if
41//! not specified and [`Some`] when the value is specified via the attribute. It
42//! is not specified via `Some(value)` but as just `value`. [`Bools`](bool) are
43//! used for flags, i.e., without a value. Most should just behave as expected,
44//! see [`parsing`] for details.
45//!
46//! Tuple structs can derive [`FromAttr`] as well, but all fields will be
47//! positional. Tuples with a single field
48//! ([new types](https://rust-unofficial.github.io/patterns/patterns/behavioural/newtype.html))
49//! will copy the behavior of the contained field, e.g. for [`bool`]:
50//!
51//! ```
52//! use syn::{Attribute, parse_quote};
53//! use attribute_derive::FromAttr;
54//!
55//! #[derive(FromAttr, PartialEq, Debug)]    
56//! #[attribute(ident = flag)]
57//! struct Flag(bool);
58//!
59//! let attr: Attribute = parse_quote!(#[flag]);
60//! assert_eq!(Flag::from_attribute(attr).unwrap(), Flag(true));
61//!
62//! let attr: Attribute = parse_quote!(#[flag = true]);
63//! assert_eq!(Flag::from_attribute(attr).unwrap(), Flag(true));
64//!
65//! let attr: Attribute = parse_quote!(#[flag(false)]);
66//! assert_eq!(Flag::from_attribute(attr).unwrap(), Flag(false));
67//! ```
68//!
69//! # Attributes
70//!
71//! The parsing of attributes can be modified with the following parameters via
72//! the `#[attribute(<params>)]` attribute. All of them are optional. Error
73//! messages are formatted using [interpolator], and only support display and
74//! lists `i` formatting. See [interpolator] docs for details.
75//!
76//! ### Struct
77//!
78//! - `ident = <ident>` The attribute ident. Improves error messages and enables
79//!   the [`from_attributes`](FromAttr::from_attributes) and
80//!   [`remove_attributes`](FromAttr::remove_attributes) functions.
81//! - `aliases = [<alias>, ...]` Aliases for the attribute ident.
82//! - `error = "<error message>"` Overrides default error message.
83//! - `error(`
84//!     - ``unknown_field = "supported fields are {expected_fields:i..-1(`{}`)(,
85//!       )} and `{expected_fields:i-1}`",`` Custom error message printed if an
86//!       unknown property is specified and attribute has more than one field.
87//!       Placeholders: `{expected_fields:i}`.
88//!     - ``unknown_field_single = "expected supported field
89//!       `{expected_field}`",`` Custom error message printed if an unknown
90//!       property is specified, and attribute only has a single field.
91//!       Placeholders: `{expected_field}`.
92//!     - ``unknown_field_empty = "expected empty attribute",`` Custom error
93//!       message printed if a property is specified, and attribute has no
94//!       fields.
95//!     - ``duplicate_field = "`{field}` is specified multiple times",`` Custom
96//!       error message printed if a property is specified multiple times.
97//!       Placeholders: `{field}`.
98//!     - ``missing_field = "required `{field}` is not specified",`` Custom
99//!       error message printed if a required property is not specified.
100//!       Placeholders: `{field}`.
101//!     - ``field_help = "try `#[{attribute}({field}={example})]`",`` Additional
102//!       help message printed if a required property is not specified or has an
103//!       error. Placeholders: `{attribute}`, `{field}` and `{example}`.
104//!     - ``conflict = "`{first}` conflicts with mutually exclusive
105//!       `{second}`"`` Custom error message printed when conflicting properties
106//!       are specified. Placeholders: `{first}` and `{second}`.
107//!
108//!   `)`
109// //! - `duplicate = AggregateOrError` Change the behavior for duplicate arguments
110// //!   (also across multiple attributes).
111// //!   - `AggregateOrError` Aggregate multiple [`Vec`], error on everything else.
112// //!   - `Error` Disables aggregation, errors on all duplicates.
113// //!   - `AggregateOrOverride`  Aggregate multiple [`Vec`], take the last
114// //!     specified for everything else.
115// //!   - `Override` Disables aggregation, always take the last value.
116//! ### Fields
117//!
118//! - `optional` If field is not specified, the default value is used instead.
119//! - `default = <default expr>` provides a default to be used instead of
120//!   [`Default::default()`]. Enables `optional`.
121//! - `conflicts(<field>, ...)` Conflicting fields
122//! - `example = "<example>"`
123//!
124//! # Parse methods
125//!
126//! There are multiple ways of parsing a struct deriving [`FromAttr`].
127//!
128//! For helper attributes there is:
129//! - [`FromAttr::from_attributes`] which takes in an [`IntoIterator<Item = &'a
130//!   syn::Attribute`](syn::Attribute) (e.g. a
131//!   [`&Vec<syn::Attribute>`](syn::Attribute)). Most useful for derive macros.
132//! - [`FromAttr::remove_attributes`] which takes a [`&mut
133//!   Vec<syn::Attribute>`](syn::Attribute) and does not only parse the
134//!   attributes, but also removes those matching. Useful for helper attributes
135//!   for attribute macros, where the helper attributes need to be removed.
136//!
137//! For parsing a single [`TokenStream`] e.g. for parsing the proc macro input
138//! there are two ways:
139//!
140//! - [`FromAttr::from_args`] taking in a [`TokenStream`]
141//! - As `derive(FromAttr)` also derives [`Parse`] so you can use the
142//!   [parse](mod@syn::parse) API, e.g. with [`parse_macro_input!(tokens as
143//!   Attribute)`](syn::parse_macro_input!).
144//!
145//! [interpolator]: https://docs.rs/interpolator/latest/interpolator/
146use std::borrow::Borrow;
147use std::fmt::Debug;
148use std::iter;
149
150#[doc(hidden)]
151pub use attribute_derive_macro::Attribute;
152pub use attribute_derive_macro::FromAttr;
153use manyhow::SpanRanged;
154#[cfg(doc)]
155use parsing::*;
156use parsing::{AttributeBase, SpannedValue};
157use proc_macro2::{Span, TokenStream};
158use syn::parse::{ParseStream, Parser, Result};
159#[cfg(doc)]
160use syn::{parse::Parse, LitStr, Type};
161use syn::{Error, Path};
162#[doc(hidden)]
163pub use tmp::FromAttr as Attribute;
164pub use tmp::FromAttr;
165
166#[doc(hidden)]
167pub mod __private {
168    pub use {proc_macro2, quote, syn};
169}
170
171mod std_impls;
172
173mod syn_impls;
174
175pub mod utils;
176pub use utils::FlagOrValue;
177
178pub mod parsing;
179
180pub mod from_partial;
181pub use from_partial::FromPartial;
182
183mod tmp {
184    use quote::ToTokens;
185    use syn::Meta;
186
187    use super::*;
188    /// The trait you actually derive on your attribute struct.
189    ///
190    /// Basic gist is a struct like this:
191    /// ```
192    /// # use attribute_derive::FromAttr;
193    /// # use syn::Type;
194    /// #[derive(FromAttr)]
195    /// #[attribute(ident = collection)]
196    /// #[attribute(error(missing_field = "`{field}` was not specified"))]
197    /// struct CollectionAttribute {
198    ///     // Options are optional by default (will be set to None if not specified)
199    ///     authority: Option<String>,
200    ///     name: String,
201    ///     // Any type implementing default can be flagged as optional
202    ///     // This will be set to Vec::default() when not specified
203    ///     #[attribute(optional)]
204    ///     views: Vec<Type>,
205    ///     // Booleans can be used without assiging a value. as a flag.
206    ///     // If omitted they are set to false
207    ///     some_flag: bool,
208    /// }
209    /// ```
210    ///
211    /// Will be able to parse an attribute like this:
212    /// ```text
213    /// #[collection(authority="Some String", name = r#"Another string"#, views = [Option, ()], some_flag)]
214    /// ```
215    pub trait FromAttr: Sized + AttributeBase {
216        /// Parses an [`IntoIterator`] of [`syn::Attributes`](syn::Attribute)
217        /// e.g. [`Vec<Attribute>`](Vec). Only available if you specify
218        /// the attribute ident: `#[attribute(ident="<ident>")]` when
219        /// using the derive macro.
220        ///
221        /// It can therefore parse fields set over multiple attributes like:
222        /// ```text
223        /// #[collection(authority = "Authority", name = "Name")]
224        /// #[collection(views = [A, B])]
225        /// ```
226        /// And also catch duplicate/conflicting settings over those.
227        ///
228        /// This is best used for derive macros, where you don't need to remove
229        /// your attributes.
230        ///
231        /// # Errors
232        /// Fails with a [`syn::Error`] so you can conveniently return that as a
233        /// compiler error in a proc macro in the following cases
234        ///
235        /// - A required parameter is omitted
236        /// - Invalid input is given for a parameter
237        /// - A non aggregating parameter is specified multiple times
238        /// - An attribute called [`IDENTS`](const@AttributeIdent::IDENTS) has
239        ///   invalid syntax (e.g. `#attr(a: "a")`)
240        fn from_attributes<A: Borrow<syn::Attribute>>(
241            attrs: impl IntoIterator<Item = A>,
242        ) -> Result<Self>
243        where
244            Self: AttributeIdent,
245        {
246            attrs
247                .into_iter()
248                .filter(|attr| Self::is_ident(attr.borrow().path()))
249                .map(Self::from_attribute_partial)
250                .try_fold(None, |acc, item| {
251                    Self::join(
252                        acc,
253                        SpannedValue::call_site(item?),
254                        &format!("`{}` was specified twice", Self::ident()),
255                    )
256                })
257                .and_then(|o| {
258                    Self::from_option(
259                        o.map(SpannedValue::value),
260                        &format!("`{}` is not set", Self::ident()),
261                    )
262                })
263        }
264
265        /// Parses a [`&mut Vec<syn::Attributes>`](syn::Attribute). Removing
266        /// matching attributes. Only available if you specify an ident:
267        /// `#[attribute(ident="<ident>")]` when using the derive macro.
268        ///
269        /// It can therefore parse fields set over multiple attributes like:
270        /// ```text
271        /// #[collection(authority = "Authority", name = "Name")]
272        /// #[collection(views = [A, B])]
273        /// ```
274        /// And also catch duplicate/conflicting settings over those.
275        ///
276        /// Use this if you are implementing an attribute macro, and need to
277        /// remove your helper attributes.
278        ///
279        /// ```
280        /// use syn::parse_quote;
281        /// use attribute_derive::FromAttr;
282        /// let mut attrs = vec![
283        ///     parse_quote!(#[ignored]), parse_quote!(#[test]),
284        ///     parse_quote!(#[also_ignored]), parse_quote!(#[test])
285        /// ];
286        /// #[derive(FromAttr)]
287        /// #[attribute(ident = test)]
288        /// struct Test {}
289        /// assert!(Test::remove_attributes(&mut attrs).is_ok());
290        ///
291        /// assert_eq!(attrs, vec![parse_quote!(#[ignored]), parse_quote!(#[also_ignored])]);
292        /// ```
293        ///
294        /// # Errors
295        /// Fails with a [`syn::Error`], so you can conveniently return that as
296        /// a compiler error in a proc macro in the following cases
297        ///
298        /// - A necessary parameter is omitted
299        /// - Invalid input is given for a parameter
300        /// - A non aggregating parameter is specified multiple times
301        /// - An attribute called [`IDENTS`](const@AttributeIdent::IDENTS) has
302        ///   invalid syntax (e.g. `#attr(a: "a")`)
303        fn remove_attributes(attrs: &mut Vec<syn::Attribute>) -> Result<Self>
304        where
305            Self: AttributeIdent,
306        {
307            let mut i = 0;
308            Self::from_attributes(iter::from_fn(|| {
309                while i < attrs.len() {
310                    if Self::is_ident(attrs[i].path()) {
311                        return Some(attrs.remove(i));
312                    }
313                    i += 1;
314                }
315                None
316            }))
317        }
318
319        /// Parses from a single attribute. Ignoring the name.
320        ///  
321        /// This is available even without `#[attribute(ident = ...)]`, because
322        /// it ignores the attribute's path, allowing to use it to parse e.g.
323        /// literals:
324        /// ```
325        /// use attribute_derive::FromAttr;
326        ///
327        /// let attr: syn::Attribute = syn::parse_quote!(#[test = "hello"]);
328        /// assert_eq!(String::from_attribute(attr).unwrap(), "hello");
329        ///
330        /// let attr: syn::Attribute = syn::parse_quote!(#[test]);
331        /// assert_eq!(bool::from_attribute(attr).unwrap(), true);
332        /// ```
333        fn from_attribute(attr: impl Borrow<syn::Attribute>) -> Result<Self> {
334            Self::from_attribute_partial(attr).and_then(Self::from)
335        }
336
337        #[doc(hidden)]
338        #[deprecated = "use `from_input` instead"]
339        fn from_args(tokens: TokenStream) -> Result<Self> {
340            Self::from_input(tokens)
341        }
342
343        /// Parses a [`TokenStream`](proc_macro2::TokenStream).
344        ///
345        /// Useful for implementing general proc macros to parse the input of
346        /// your macro.
347        ///
348        /// This is a convenience over [`parse_input`](Self::parse_input). More
349        /// details are documented there.
350        fn from_input(input: impl Into<TokenStream>) -> Result<Self> {
351            Self::parse_input.parse2(input.into())
352        }
353
354        /// Parses input as the complete attribute.
355        ///
356        /// Due to this only parsing the input for a single attribute it is not
357        /// able to aggregate input spread over multiple attributes.
358        ///
359        /// # Errors
360        /// Fails with a [`syn::Error`], so you can conveniently return that as
361        /// a compiler error in a proc macro in the following cases
362        ///
363        /// - A necessary parameter is omitted
364        /// - Invalid input is given for a parameter
365        /// - A non aggregating parameter is specified multiple times
366        fn parse_input(input: ParseStream) -> Result<Self> {
367            Self::parse_partial(input).and_then(Self::from)
368        }
369
370        /// Like [`parse_partial`](Self::parse_partial) but instead takes an
371        /// [`Attribute`](syn::Attribute).
372        ///
373        /// This allows it to support all three, `#[flag]`, `#[function(like)]`
374        /// and `#[name = value]` attributes.
375        fn from_attribute_partial(attr: impl Borrow<syn::Attribute>) -> Result<Self::Partial> {
376            let tokens = match attr.borrow().meta {
377                Meta::Path(_) => TokenStream::new(),
378                Meta::List(ref list) => list.tokens.clone(),
379                Meta::NameValue(ref nv) => nv.value.to_token_stream(),
380            };
381            Self::parse_partial.parse2(tokens)
382        }
383
384        /// Actual implementation for parsing the attribute. This is the only
385        /// function required to implement in this trait and derived by the
386        /// [`FromAttr`](macro@FromAttr) derive macro.
387        fn parse_partial(input: ParseStream) -> Result<Self::Partial>;
388    }
389}
390
391/// Helper trait providing the path for an attribute.
392///
393/// Automatically derived with [`FromAttr`], if `#[attribute(ident =
394/// "some_ident")]` is provided.
395pub trait AttributeIdent {
396    /// List of idents, must contain at least one ident.
397    const IDENTS: &'static [&'static str];
398
399    /// Tests if Attribute matches one of the idents.
400    fn is_ident(path: &Path) -> bool {
401        Self::IDENTS.iter().any(|ident| path.is_ident(ident))
402    }
403
404    /// Returns default ident.
405    ///
406    /// # Panics
407    /// The default implementation panics if `IDENTS` is empty. Implementors
408    /// should ensure this is not the case.
409    fn ident() -> &'static str {
410        Self::IDENTS
411            .first()
412            .expect("`AttributeIdent::IDENTS` should not be empty")
413    }
414}