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}