Skip to main content

attribute_derive/
lib.rs

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