amplify_syn/
attr.rs

1// Rust language amplification derive library providing multiple generic trait
2// implementations, type wrappers, derive macros and other language enhancements
3//
4// Written in 2019-2021 by
5//     Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
6//
7// To the extent possible under law, the author(s) have dedicated all
8// copyright and related and neighboring rights to this software to
9// the public domain worldwide. This software is distributed without
10// any warranty.
11//
12// You should have received a copy of the MIT License
13// along with this software.
14// If not, see <https://opensource.org/licenses/MIT>.
15
16use std::collections::{HashMap, HashSet};
17use std::fmt::{self, Debug, Formatter};
18
19use syn::parse::Parser;
20use syn::parse_quote::ParseQuote;
21use syn::{
22    Attribute, Lit, LitBool, LitByteStr, LitChar, LitFloat, LitInt, LitStr, Meta, MetaNameValue,
23    Path, Type,
24};
25
26use crate::{ArgValue, ArgValueReq, AttrReq, Error, MetaArg, MetaArgList, MetaArgNameValue};
27
28/// Internal structure representation of a proc macro attribute collected
29/// instances having some specific name (accessible via [`Attr::name()`]).
30#[derive(Clone, Debug)]
31pub enum Attr {
32    /// Attribute of `#[attr]` or `#[attr = value]` form, which, aside from the
33    /// case where `value` is a string literal, may have only a single
34    /// occurrence (string literals are concatenated into a single value like
35    /// rust compiler does for `#[doc = "..."]` attributes).
36    Singular(SingularAttr),
37
38    /// Parametrized attribute in form of `#[attr(...)]`, where parameters are
39    /// gathered from all attribute occurrences.
40    Parametrized(ParametrizedAttr),
41}
42
43/// Structure describing a procedural macro attribute with an optional value.
44/// The means that if one has something like `#[name1]`, `#[name2 = "value"]`,
45/// `#[name3 = ::std::path::PathBuf)]` than `name1`, `name2 = "value"`, and
46/// `name3 = ::std::path::PathBuf` are three different attributes  which can be
47/// parsed and represented by the [`SingularAttr`] structure.
48///
49/// NB: For `#[attr(arg1, arg2 = value)]` style of proc macros use
50/// [`ParametrizedAttr`] structure. If you need to support both use [`Attr`]
51/// enum.
52///
53/// Internally the structure is composed of the `name` and `value` fields,
54/// where name is always a [`struct@syn::Ident`] (corresponding `name1`,
55/// `name2`, `name3` from the sample above) and `value` is an optional literal
56/// [`enum@Lit`], with corresponding cases of `None`,
57/// `Some(`[`ArgValue::Literal`]`(`[`Lit::Str`]`(`[`struct@LitStr`]`)))`, and
58/// `Some(`[`ArgValue::Type`]`(`[`Type::Path`]`(`[`Path`]`)))`.
59#[derive(Clone, Debug)]
60pub struct SingularAttr {
61    /// Optional attribute argument path part; for instance in
62    /// `#[my(name = value)]` or in `#[name = value]` this is a `name` part
63    pub name: String,
64
65    /// Attribute argument value part; for instance in `#[name = value]` this is
66    /// the `value` part
67    pub value: ArgValue,
68}
69
70/// Representation for all allowed forms of `#[attr(...)]` attribute.
71/// If attribute has a multiple occurrences they are all assembled into a single
72/// list. Repeated named arguments are not allowed and result in errors.
73///
74/// For situations like in `#[attr("string literal")]`, [`ParametrizedAttr`]
75/// will have a `name` field set to `attr`, `literal` field set to
76/// `Lit::LitStr(LitStr("string literal"))`, `args` will be an empty `HashSet`
77/// and `paths` will be represented by an empty vector.
78#[derive(Clone)]
79pub struct ParametrizedAttr {
80    /// Attribute name - `attr` part of `#[attr(...)]`
81    pub name: String,
82
83    /// All attribute arguments that have form of `#[attr(ident = "literal")]`
84    /// or `#[attr(ident = TypeName)]` mapped to their name identifiers.
85    pub args: HashMap<String, ArgValue>,
86
87    /// All attribute arguments that are paths or identifiers without any
88    /// specific value, like `#[attr(std::io::Error, crate, super::SomeType)]`.
89    ///
90    /// NB: All named arguments without the value assigned are getting into this
91    /// field by default, even if they do not represent any known rust path or
92    /// type name, like `#[attr(some_id, other)]`. However, with
93    /// [`ParametrizedAttr::check`] and [`ParametrizedAttr::checked`] those
94    /// values matching ones specified in [`AttrReq::arg_req`] with values set
95    /// to [`crate::ListReq::Predefined::default`] are moved into
96    /// [`ParametrizedAttr::args`].
97    pub paths: Vec<Path>,
98
99    /// Unnamed string literal found within attribute arguments.
100    ///
101    /// If multiple string literals are present they are concatenated into a
102    /// single value, like it is done by the rust compiler for
103    /// `#[doc = "..."]` attributes
104    pub string: Option<LitStr>,
105
106    /// Unnamed byte string literal found within attribute arguments.
107    ///
108    /// If multiple byte string literals are present they are concatenated into
109    /// a single value, like it is done by the rust compiler for
110    /// `#[doc = "..."]` attributes
111    pub bytes: Option<LitByteStr>,
112
113    /// Unnamed char literals found within attribute arguments
114    pub chars: Vec<LitChar>,
115
116    /// Unnamed integer literals found within attribute arguments
117    pub integers: Vec<LitInt>,
118
119    /// Unnamed float literals found within attribute arguments
120    pub floats: Vec<LitFloat>,
121
122    /// Unnamed bool literal found within attribute arguments.
123    ///
124    /// If multiple bool literals are present this will generate an error.
125    pub bool: Option<LitBool>,
126}
127
128impl Attr {
129    /// Constructs [`Attr`] from a vector of all syn-parsed attributes,
130    /// selecting attributes matching the provided name.
131    pub fn with(name: impl ToString + AsRef<str>, attrs: &[Attribute]) -> Result<Self, Error> {
132        SingularAttr::with(name.to_string(), attrs)
133            .map(Attr::Singular)
134            .or_else(|_| ParametrizedAttr::with(name, attrs).map(Attr::Parametrized))
135    }
136
137    /// Constructor parsing [`Attribute`] value and returning either
138    /// [`SingularAttr`] or [`ParametrizedAttr`] packed in form of [`Attr`]
139    /// enum.
140    ///
141    /// If the attribute does not match either of forms, a [`Error`] is
142    /// returned. Currently, only single type of error may occur in practice:
143    /// - [`Error::ArgNameMustBeIdent`], which happens if the attribute name is
144    ///   not an [`struct@syn::Ident`] but is a complex path value
145    pub fn from_attribute(attr: &Attribute) -> Result<Self, Error> {
146        SingularAttr::from_attribute(attr)
147            .map(Attr::Singular)
148            .or_else(|_| ParametrizedAttr::from_attribute(attr).map(Attr::Parametrized))
149    }
150
151    /// Returns inner value \in form of [`SingularAttr`] for [`Attr::Singular`]
152    /// variant, or fails with [`Error::SingularAttrRequired`] otherwise
153    #[inline]
154    pub fn try_singular(self) -> Result<SingularAttr, Error> {
155        match self {
156            Attr::Singular(attr) => Ok(attr),
157            Attr::Parametrized(attr) => Err(Error::SingularAttrRequired(attr.name)),
158        }
159    }
160
161    /// Returns inner value \in form of [`ParametrizedAttr`] for
162    /// [`Attr::Parametrized`] variant, or fails with
163    /// [`Error::ParametrizedAttrRequired`] otherwise
164    #[inline]
165    pub fn try_parametrized(self) -> Result<ParametrizedAttr, Error> {
166        match self {
167            Attr::Singular(attr) => Err(Error::ParametrizedAttrRequired(attr.name)),
168            Attr::Parametrized(attr) => Ok(attr),
169        }
170    }
171
172    /// Returns string reference to the argument name
173    #[inline]
174    pub fn name(&self) -> &str {
175        match self {
176            Attr::Singular(attr) => &attr.name,
177            Attr::Parametrized(attr) => &attr.name,
178        }
179    }
180
181    /// Returns [`ArgValue`] for the [`Attr::Singular`] variant or fails with
182    /// [`Error::ParametrizedAttrHasNoValue`]
183    #[inline]
184    pub fn arg_value(&self) -> Result<ArgValue, Error> {
185        match self {
186            Attr::Singular(attr) => Ok(attr.value.clone()),
187            Attr::Parametrized(attr) => Err(Error::ParametrizedAttrHasNoValue(attr.name.clone())),
188        }
189    }
190
191    /// Returns literal value for the [`Attr::Singular`] variant or fails with
192    /// [`Error::ParametrizedAttrHasNoValue`]. See
193    /// [`ArgValue::to_literal_value`] for more details.
194    #[inline]
195    pub fn literal_value(&self) -> Result<Lit, Error> { self.arg_value()?.to_literal_value() }
196
197    /// Returns type value for the [`Attr::Singular`] variant or fails with
198    /// [`Error::ParametrizedAttrHasNoValue`]. See
199    /// [`ArgValue::to_literal_value`] for more details.
200    #[inline]
201    pub fn type_value(&self) -> Result<Type, Error> { self.arg_value()?.to_type_value() }
202}
203
204impl SingularAttr {
205    /// Constructs named [`SingularAttr`] without value
206    #[inline]
207    pub fn new(name: impl ToString) -> Self {
208        Self {
209            name: name.to_string(),
210            value: ArgValue::None,
211        }
212    }
213
214    /// Constructs [`SingularAttr`] from a vector of all syn-parsed attributes,
215    /// selecting single attribute matching the provided name. If there are
216    /// multiple instances of the same attribute, fails with
217    /// [`Error::SingularAttrRequired`]
218    pub fn with(name: impl ToString, attrs: &[Attribute]) -> Result<Self, Error> {
219        let name = name.to_string();
220        let mut filtered_attrs = attrs.iter().filter(|attr| attr.path.is_ident(&name));
221        let res = if let Some(attr) = filtered_attrs.next() {
222            SingularAttr::from_attribute(attr)
223        } else {
224            return Err(Error::SingularAttrRequired(name));
225        };
226        if filtered_attrs.count() > 0 {
227            return Err(Error::SingularAttrRequired(name));
228        }
229        res
230    }
231
232    /// Constructs named [`SingularAttr`] setting its value to the provided
233    /// literal
234    #[inline]
235    pub fn with_literal(name: impl ToString, lit: Lit) -> Self {
236        Self {
237            name: name.to_string(),
238            value: ArgValue::Literal(lit),
239        }
240    }
241
242    /// Constructs named [`SingularAttr`] setting its value to the provided
243    /// rust type value
244    #[inline]
245    pub fn with_type(name: impl ToString, ty: Type) -> Self {
246        Self {
247            name: name.to_string(),
248            value: ArgValue::Type(ty),
249        }
250    }
251
252    /// Constructs [`SingularAttr`] from a given [`syn::Attribute`] by parsing
253    /// its data. Accepts only attributes having form `#[attr(name = value)]`
254    /// and errors for other attribute types with [`Error::ArgNameMustBeIdent`]
255    /// and [`Error::SingularAttrRequired`]
256    pub fn from_attribute(attr: &Attribute) -> Result<Self, Error> {
257        let ident = attr
258            .path
259            .get_ident()
260            .ok_or(Error::ArgNameMustBeIdent)?
261            .to_string();
262        match attr.parse_meta()? {
263            // `#[attr::path]` - unreachable: filtered in the code above
264            Meta::Path(_) => unreachable!(),
265            // `#[ident = lit]`
266            Meta::NameValue(MetaNameValue { lit, .. }) => {
267                Ok(SingularAttr::with_literal(ident, lit))
268            }
269            // `#[ident(...)]`
270            Meta::List(_) => Err(Error::SingularAttrRequired(ident)),
271        }
272    }
273
274    /// Returns literal value, if any, or fails with
275    /// [`Error::ArgValueRequired`]. See [`ArgValue::to_literal_value`] for the
276    /// details.
277    #[inline]
278    pub fn literal_value(&self) -> Result<Lit, Error> { self.value.to_literal_value() }
279
280    /// Returns type value, if any, or fails with [`Error::ArgValueRequired`].
281    /// See [`ArgValue::to_literal_value`] for the details.
282    #[inline]
283    pub fn type_value(&self) -> Result<Type, Error> { self.value.to_type_value() }
284
285    /// Merges data from the `other` into the self.
286    ///
287    /// # Errors
288    ///
289    /// - Fails with [`Error::NamesDontMatch`] if the names of the self and the
290    ///   `other` do not match
291    /// - Fails with [`Error::MultipleSingularValues`] if both self and the
292    ///   `other` has a named argument with the same name but different values.
293    pub fn merge(&mut self, other: Self) -> Result<(), Error> {
294        if self.name != other.name {
295            return Err(Error::NamesDontMatch(self.name.clone(), other.name));
296        }
297        match (&self.value, &other.value) {
298            (_, ArgValue::None) => {}
299            (ArgValue::None, _) => self.value = other.value,
300            (_, _) => return Err(Error::MultipleSingularValues(self.name.clone())),
301        }
302        Ok(())
303    }
304
305    /// Does merging as in [`SingularAttr::merge`], but unlike it consumes
306    /// the self and returns a merged structure in case of the successful
307    /// operation. Useful in operation chains.
308    #[inline]
309    pub fn merged(mut self, other: Self) -> Result<Self, Error> {
310        self.merge(other)?;
311        Ok(self)
312    }
313
314    /// Enriches current attribute data by adding information from the provided
315    /// [`syn::Attribute`].
316    ///
317    /// # Errors
318    ///
319    /// - Fails with [`Error::NamesDontMatch`] if the names of the self and the
320    ///   provided attribute do not match
321    /// - Fails with [`Error::MultipleSingularValues`] if both self and the
322    ///   provided attribute has a named argument with the same name but
323    ///   different values.
324    #[inline]
325    pub fn enrich(&mut self, attr: &Attribute) -> Result<(), Error> {
326        self.merge(SingularAttr::from_attribute(attr)?)
327    }
328
329    /// Performs enrich operation as in [`SingularAttr::enrich`], but unlike it
330    /// consumes the self and returns an enriched structure in case of the
331    /// successful operation. Useful in operation chains.
332    #[inline]
333    pub fn enriched(mut self, attr: &Attribute) -> Result<Self, Error> {
334        self.enrich(attr)?;
335        Ok(self)
336    }
337
338    /// Checks that the structure meets provided value requirements (see
339    /// [`ArgValueReq`]), generating [`Error`] if the requirements are not met.
340    pub fn check(&mut self, req: ArgValueReq) -> Result<(), Error> {
341        req.check(&mut self.value, &self.name, &self.name)?;
342        Ok(())
343    }
344
345    /// Performs check as in [`SingularAttr::check`], but unlike it consumes the
346    /// self and returns a itself in case of the successful operation.
347    /// Useful in operation chains.
348    #[inline]
349    pub fn checked(mut self, req: ArgValueReq) -> Result<Self, Error> {
350        self.check(req)?;
351        Ok(self)
352    }
353}
354
355impl ParametrizedAttr {
356    /// Constructs named [`SingularAttr`] with empty internal data
357    #[inline]
358    pub fn new(name: impl ToString) -> Self {
359        Self {
360            name: name.to_string(),
361            args: Default::default(),
362            paths: vec![],
363            string: None,
364            bytes: None,
365            chars: vec![],
366            integers: vec![],
367            floats: vec![],
368            bool: None,
369        }
370    }
371
372    /// Constructs [`ParametrizedAttr`] from a vector of all syn-parsed
373    /// attributes, selecting attributes matching the provided name.
374    pub fn with(name: impl ToString + AsRef<str>, attrs: &[Attribute]) -> Result<Self, Error> {
375        let mut me = ParametrizedAttr::new(name.to_string());
376        for attr in attrs.iter().filter(|attr| attr.path.is_ident(&name)) {
377            me.fuse(attr)?;
378        }
379        Ok(me)
380    }
381
382    /// Constructs [`ParametrizedAttr`] from a given [`syn::Attribute`]
383    pub fn from_attribute(attr: &Attribute) -> Result<Self, Error> {
384        let name = attr
385            .path
386            .get_ident()
387            .ok_or(Error::ArgNameMustBeIdent)?
388            .to_string();
389        ParametrizedAttr::new(name).fused(attr)
390    }
391
392    /// Returns value for a given argument with name `name`, if it is defined,
393    /// or fails with [`Error::ArgValueRequired`].
394    pub fn arg_value<T>(&self, name: &str) -> Result<T, Error>
395    where T: TryFrom<ArgValue, Error = Error> {
396        self.args
397            .get(name)
398            .ok_or(Error::ArgRequired {
399                attr: self.name.clone(),
400                arg: name.to_owned(),
401            })
402            .and_then(|a| a.clone().try_into())
403    }
404
405    /// Returns value for a given argument with name `name`, if it is defined,
406    /// or panics otherwise.
407    pub fn unwrap_arg_value<T>(&self, name: &str) -> T
408    where T: TryFrom<ArgValue, Error = Error> {
409        self.args
410            .get(name)
411            .ok_or(Error::ArgRequired {
412                attr: self.name.clone(),
413                arg: name.to_owned(),
414            })
415            .and_then(|a| a.clone().try_into())
416            .expect("required attribute value is not present or has an invalid type")
417    }
418
419    /// Returns literal value for a given argument with name `name`, if it is
420    /// defined, or fails with [`Error::ArgValueRequired`]. See
421    /// [`ArgValue::to_literal_value`] for the details.
422    #[deprecated(note = "use ArgValue::arg_value")]
423    pub fn arg_literal_value(&self, name: &str) -> Result<Lit, Error> {
424        self.args
425            .get(name)
426            .ok_or(Error::ArgRequired {
427                attr: self.name.clone(),
428                arg: name.to_owned(),
429            })?
430            .to_literal_value()
431    }
432
433    /// Checks if the attribute has a verbatim argument matching the provided
434    /// `verbatim` string.
435    ///
436    /// Verbatim arguments are arguments in form of `#[attr(verbatim1,
437    /// verbatim2]`, i.e. path arguments containing single path segment and no
438    /// value or nested arguments.
439    pub fn has_verbatim(&self, verbatim: &str) -> bool {
440        self.paths.iter().any(|path| path.is_ident(verbatim))
441    }
442
443    /// Returns set of verbatim attribute arguments.
444    ///
445    /// Verbatim arguments are arguments in form of `#[attr(verbatim1,
446    /// verbatim2]`, i.e. path arguments containing single path segment and no
447    /// value or nested arguments.
448    pub fn verbatim(&self) -> HashSet<String> {
449        self.paths
450            .iter()
451            .filter_map(Path::get_ident)
452            .map(|ident| ident.to_string())
453            .collect()
454    }
455
456    /// Merges data from the `other` into the self.
457    ///
458    /// # Errors
459    ///
460    /// - Fails with [`Error::NamesDontMatch`] if the names of the self and the
461    ///   `other` do not match
462    /// - Fails with [`Error::MultipleLiteralValues`] if both self and the
463    ///   `other` has a literals which values are not equal.
464    pub fn merge(&mut self, other: Self) -> Result<(), Error> {
465        if self.name != other.name {
466            return Err(Error::NamesDontMatch(self.name.clone(), other.name));
467        }
468
469        self.args.extend(other.args);
470        self.paths.extend(other.paths);
471
472        self.integers.extend(other.integers);
473        self.floats.extend(other.floats);
474        self.chars.extend(other.chars);
475
476        match (&mut self.string, &other.string) {
477            (_, None) => {}
478            (None, Some(_)) => self.string = other.string.clone(),
479            (Some(str1), Some(str2)) => {
480                *str1 = LitStr::new(&format!("{} {}", str1.value(), str2.value()), str1.span());
481            }
482        }
483        match (&mut self.bytes, &other.bytes) {
484            (_, None) => {}
485            (None, Some(_)) => self.bytes = other.bytes.clone(),
486            (Some(bytes1), Some(bytes2)) => {
487                let mut joined = bytes1.value();
488                joined.extend(bytes2.value());
489                *bytes1 = LitByteStr::new(&joined, bytes1.span());
490            }
491        }
492        match (&mut self.bool, &other.bool) {
493            (_, None) => {}
494            (None, Some(_)) => self.bool = other.bool.clone(),
495            (Some(_), Some(_)) => return Err(Error::MultipleLiteralValues(self.name.clone())),
496        }
497
498        Ok(())
499    }
500
501    /// Does merging as in [`ParametrizedAttr::merge`], but unlike it consumes
502    /// the self and returns a merged structure in case of the successful
503    /// operation. Useful in operation chains.
504    #[inline]
505    pub fn merged(mut self, other: Self) -> Result<Self, Error> {
506        self.merge(other)?;
507        Ok(self)
508    }
509
510    /// Enriches current attribute data by adding information from the provided
511    /// [`syn::Attribute`].
512    ///
513    /// # Errors
514    ///
515    /// - Fails with [`Error::NamesDontMatch`] if the names of the self and the
516    ///   provided attribute do not match
517    /// - Fails with [`Error::MultipleLiteralValues`] if both self and the
518    ///   provided attribute has a literals which values are not equal.
519    #[inline]
520    pub fn enrich(&mut self, attr: &Attribute) -> Result<(), Error> {
521        self.merge(ParametrizedAttr::from_attribute(attr)?)
522    }
523
524    /// Performs enrich operation as in [`ParametrizedAttr::enrich`], but unlike
525    /// it consumes the self and returns an enriched structure in case of
526    /// the successful operation. Useful in operation chains.
527    #[inline]
528    pub fn enriched(mut self, attr: &Attribute) -> Result<Self, Error> {
529        self.enrich(attr)?;
530        Ok(self)
531    }
532
533    /// Fuses data from a nested attribute arguments (see [`Attribute`]) into
534    /// the attribute parameters.
535    ///
536    /// The operation is similar to the [`ParametrizedAttr::enrich`] with the
537    /// only difference that enrichment operation takes the whole attribute, and
538    /// fusion takes a nested meta data.
539    #[inline]
540    pub fn fuse(&mut self, attr: &Attribute) -> Result<(), Error> {
541        let args = MetaArgList::parse.parse2(attr.tokens.clone().into())?;
542        for arg in args.list {
543            match arg {
544                // `#[ident("literal", ...)]`
545                MetaArg::Literal(Lit::Str(s)) => {
546                    let span = s.span();
547                    match self.string {
548                        None => self.string = Some(s),
549                        Some(ref mut str1) => {
550                            let mut joined = str1.value();
551                            joined.push_str(&s.value());
552                            *str1 = LitStr::new(&joined, span);
553                        }
554                    }
555                }
556
557                // `#[ident(b"literal", ...)]`
558                MetaArg::Literal(Lit::ByteStr(s)) => {
559                    let span = s.span();
560                    match self.bytes {
561                        None => self.bytes = Some(s),
562                        Some(ref mut str1) => {
563                            let mut joined = str1.value();
564                            joined.extend(&s.value());
565                            *str1 = LitByteStr::new(&joined, span);
566                        }
567                    }
568                }
569
570                // `#[ident(3, ...)]`
571                MetaArg::Literal(Lit::Int(lit)) => self.integers.push(lit),
572
573                // `#[ident(2.3, ...)]`
574                MetaArg::Literal(Lit::Float(lit)) => self.floats.push(lit),
575
576                // `#[ident('a', ...)]`
577                MetaArg::Literal(Lit::Char(lit)) => self.chars.push(lit),
578
579                // `#[ident(true, ...)]`
580                MetaArg::Literal(Lit::Bool(_)) if self.bool.is_some() => {
581                    return Err(Error::MultipleLiteralValues(self.name.clone()));
582                }
583                MetaArg::Literal(Lit::Bool(ref lit)) if self.bool.is_none() => {
584                    self.bool = Some(lit.clone())
585                }
586
587                // `#[ident(true, ...)]`
588                MetaArg::Literal(_) => return Err(Error::UnsupportedLiteral(self.name.clone())),
589
590                // `#[ident(arg::path)]`
591                MetaArg::Path(path) => self.paths.push(path),
592
593                // `#[ident(name = value, ...)]`
594                MetaArg::NameValue(MetaArgNameValue { name, value, .. }) => {
595                    let id = name.to_string();
596                    if self.args.insert(id.clone(), value).is_some() {
597                        return Err(Error::ArgNameMustBeUnique {
598                            attr: self.name.clone(),
599                            arg: id,
600                        });
601                    }
602                }
603            }
604        }
605        Ok(())
606    }
607
608    /// Performs enrich operation as in [`ParametrizedAttr::fuse`], but unlike
609    /// it consumes the self and returns an enriched structure in case of
610    /// the successful operation. Useful in operation chains.
611    #[inline]
612    pub fn fused(mut self, attr: &Attribute) -> Result<Self, Error> {
613        self.fuse(attr)?;
614        Ok(self)
615    }
616
617    /// Checks that the structure meets provided value requirements (see
618    /// [`AttrReq`]), generating [`Error`] if the requirements are not met.
619    ///
620    /// The procedure modifies the [`ParametrizedAttr`] data in the following
621    /// ways:
622    /// 1. First, it fills in [`ParametrizedAttr::paths`],
623    ///    [`ParametrizedAttr::integers`], [`ParametrizedAttr::floats`],
624    ///    [`ParametrizedAttr::chars`], [`ParametrizedAttr::bytes`],
625    ///    [`ParametrizedAttr::string`] with default values from
626    ///    [`AttrReq::path_req`], [`AttrReq::integer_req`],
627    ///    [`AttrReq::float_req`], [`AttrReq::char_req`],
628    ///    [`AttrReq::bytes_req`], [`AttrReq::string_req`] correspondingly.
629    /// 2. [`ParametrizedAttr::paths`] values
630    ///    matching ones specified in [`AttrReq::arg_req`] with values set to
631    ///    [`crate::ListReq::Predefined::default`] are moved into
632    ///    [`ParametrizedAttr::args`] field.
633    pub fn check(&mut self, req: AttrReq) -> Result<(), Error> {
634        for (name, req) in &req.arg_req {
635            if let Some(pos) = self.paths.iter().position(|path| path.is_ident(name)) {
636                self.paths.remove(pos);
637                self.args
638                    .entry(name.clone())
639                    .or_insert_with(|| req.default_value());
640            }
641
642            if !self.args.contains_key(name) && req.is_required() {
643                return Err(Error::ArgRequired {
644                    attr: self.name.clone(),
645                    arg: name.clone(),
646                });
647            }
648        }
649
650        for (name, value) in &mut self.args {
651            let req = if let Some(req) = req.arg_req.get(name) {
652                req
653            } else {
654                return Err(Error::AttributeUnknownArgument {
655                    attr: self.name.clone(),
656                    arg: name.clone(),
657                });
658            };
659
660            req.check(value, &self.name, name)?;
661        }
662
663        req.path_req.check(&mut self.paths, &self.name, "path")?;
664
665        req.integer_req
666            .check(&mut self.integers, &self.name, "integer literal")?;
667        req.float_req
668            .check(&mut self.floats, &self.name, "float literal")?;
669        req.char_req
670            .check(&mut self.chars, &self.name, "char literal")?;
671
672        req.string_req
673            .check(&mut self.string, &self.name, "string literal")?;
674        req.bool_req
675            .check(&mut self.bool, &self.name, "bool literal")?;
676        req.bytes_req
677            .check(&mut self.bytes, &self.name, "byte string literal")?;
678
679        Ok(())
680    }
681
682    /// Performs check as in [`ParametrizedAttr::check`], but unlike it
683    /// consumes the self and returns a itself in case of the successful
684    /// operation. Useful in operation chains.
685    #[inline]
686    pub fn checked(mut self, req: AttrReq) -> Result<Self, Error> {
687        self.check(req)?;
688        Ok(self)
689    }
690}
691
692// This trait should not be implemented for the types outside of this crate
693#[doc(hidden)]
694pub trait ExtractAttr {
695    #[doc(hidden)]
696    fn singular_attr(
697        self,
698        name: impl ToString + AsRef<str>,
699        req: ArgValueReq,
700    ) -> Result<Option<SingularAttr>, Error>;
701
702    #[doc(hidden)]
703    fn parametrized_attr(
704        self,
705        name: impl ToString + AsRef<str>,
706        req: AttrReq,
707    ) -> Result<Option<ParametrizedAttr>, Error>;
708}
709
710impl<'a, T> ExtractAttr for T
711where T: IntoIterator<Item = &'a Attribute>
712{
713    /// Returns a [`SingularAttr`] which structure must fulfill the provided
714    /// requirements - or fails with a [`Error`] otherwise. For more information
715    /// check [`ValueReq`] requirements info.
716    fn singular_attr(
717        self,
718        name: impl ToString + AsRef<str>,
719        req: ArgValueReq,
720    ) -> Result<Option<SingularAttr>, Error> {
721        let mut attr = SingularAttr::new(name.to_string());
722
723        let filtered = self
724            .into_iter()
725            .filter(|attr| attr.path.is_ident(&name))
726            .collect::<Vec<_>>();
727
728        if filtered.is_empty() {
729            return Ok(None);
730        }
731
732        for entries in filtered {
733            attr.enrich(entries)?;
734        }
735
736        Some(attr.checked(req)).transpose()
737    }
738
739    /// Returns a [`ParametrizedAttr`] which structure must fulfill the provided
740    /// requirements - or fails with a [`Error`] otherwise. For more information
741    /// check [`AttrReq`] requirements info.
742    fn parametrized_attr(
743        self,
744        name: impl ToString + AsRef<str>,
745        req: AttrReq,
746    ) -> Result<Option<ParametrizedAttr>, Error> {
747        let mut attr = ParametrizedAttr::new(name.to_string());
748
749        let filtered = self
750            .into_iter()
751            .filter(|attr| attr.path.is_ident(&name))
752            .collect::<Vec<_>>();
753
754        if filtered.is_empty() {
755            return Ok(None);
756        }
757
758        for entries in filtered {
759            attr.enrich(entries)?;
760        }
761
762        Some(attr.checked(req)).transpose()
763    }
764}
765
766impl Debug for ParametrizedAttr {
767    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
768        f.write_str("ParametrizedAttr({")?;
769        if f.alternate() {
770            f.write_str("\n\t")?;
771        }
772
773        write!(f, "name: {:?}, ", self.name)?;
774        if f.alternate() {
775            f.write_str("\n\t")?;
776        }
777
778        f.write_str("args: {")?;
779        if !self.args.is_empty() {
780            if f.alternate() {
781                f.write_str("\n")?;
782            }
783            for (name, val) in &self.args {
784                if f.alternate() {
785                    f.write_str("\t\t")?;
786                }
787                write!(f, "{} => {:?}, ", name, val)?;
788                if f.alternate() {
789                    f.write_str("\n")?;
790                }
791            }
792            if f.alternate() {
793                f.write_str("\t")?;
794            }
795        }
796        f.write_str("}, ")?;
797        if f.alternate() {
798            f.write_str("\n\t")?;
799        }
800
801        f.write_str("paths: [")?;
802        if !self.paths.is_empty() {
803            if f.alternate() {
804                f.write_str("\n")?;
805            }
806            for path in &self.paths {
807                if f.alternate() {
808                    f.write_str("\t\t")?;
809                }
810                write!(f, "{}, ", quote! { #path })?;
811                if f.alternate() {
812                    f.write_str("\n")?;
813                }
814            }
815            if f.alternate() {
816                f.write_str("\t")?;
817            }
818        }
819        f.write_str("], ")?;
820        if f.alternate() {
821            f.write_str("\n\t")?;
822        }
823
824        write!(
825            f,
826            "bool: {:?}, ",
827            self.bool
828                .as_ref()
829                .map(|b| format!("Some({:?})", b.value))
830                .unwrap_or_else(|| "None".to_owned())
831        )?;
832        if f.alternate() {
833            f.write_str("\n\t")?;
834        }
835
836        write!(
837            f,
838            "string: {:?}, ",
839            self.string
840                .as_ref()
841                .map(|s| format!("Some({:?})", s.value()))
842                .unwrap_or_else(|| "None".to_owned())
843        )?;
844        if f.alternate() {
845            f.write_str("\n\t")?;
846        }
847
848        write!(
849            f,
850            "bytes: {:?}, ",
851            self.bytes
852                .as_ref()
853                .map(|s| format!("Some({:?})", s.value()))
854                .unwrap_or_else(|| "None".to_owned())
855        )?;
856        if f.alternate() {
857            f.write_str("\n\t")?;
858        }
859
860        f.write_str("chars: [")?;
861        if !self.chars.is_empty() {
862            if f.alternate() {
863                f.write_str("\n")?;
864            }
865            for c in &self.chars {
866                if f.alternate() {
867                    f.write_str("\t\t")?;
868                }
869                write!(f, "{}, ", quote! { #c })?;
870                if f.alternate() {
871                    f.write_str("\n")?;
872                }
873            }
874            if f.alternate() {
875                f.write_str("\t")?;
876            }
877        }
878        f.write_str("], ")?;
879        if f.alternate() {
880            f.write_str("\n\t")?;
881        }
882
883        f.write_str("integers: [")?;
884        if !self.integers.is_empty() {
885            if f.alternate() {
886                f.write_str("\n")?;
887            }
888            for c in &self.integers {
889                if f.alternate() {
890                    f.write_str("\t\t")?;
891                }
892                write!(f, "{}, ", quote! { #c })?;
893                if f.alternate() {
894                    f.write_str("\n")?;
895                }
896            }
897            if f.alternate() {
898                f.write_str("\t")?;
899            }
900        }
901        f.write_str("], ")?;
902        if f.alternate() {
903            f.write_str("\n\t")?;
904        }
905
906        f.write_str("floats: [")?;
907        if !self.floats.is_empty() {
908            if f.alternate() {
909                f.write_str("\n")?;
910            }
911            for c in &self.floats {
912                if f.alternate() {
913                    f.write_str("\t\t")?;
914                }
915                write!(f, "{}, ", quote! { #c })?;
916                if f.alternate() {
917                    f.write_str("\n")?;
918                }
919            }
920            if f.alternate() {
921                f.write_str("\t")?;
922            }
923        }
924        f.write_str("], ")?;
925
926        if f.alternate() {
927            f.write_str("\n")?;
928        }
929        f.write_str("})")?;
930        if f.alternate() {
931            f.write_str("\n")?;
932        }
933        Ok(())
934    }
935}