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}