Skip to main content

bon_macros/parsing/
item_sig.rs

1use super::SpannedKey;
2use crate::util::prelude::*;
3use darling::FromMeta;
4
5/// "Item signature" is a set of parameters that configures some aspects of
6/// an item like a function, struct, struct field, module, trait. All of them
7/// have configurable properties that are specified here.
8///
9/// The generic parameter `N` specifies the type used for the name field:
10/// - `syn::Ident` (default): For regular identifiers
11/// - `String`: For pattern strings (e.g., "conv_{}")
12#[derive(Debug, Clone)]
13pub(crate) struct ItemSigConfig<N = syn::Ident> {
14    pub(crate) name: Option<SpannedKey<N>>,
15    pub(crate) vis: Option<SpannedKey<syn::Visibility>>,
16    pub(crate) docs: Option<SpannedKey<Vec<syn::Attribute>>>,
17}
18
19impl<N> Default for ItemSigConfig<N> {
20    fn default() -> Self {
21        Self {
22            name: None,
23            vis: None,
24            docs: None,
25        }
26    }
27}
28
29impl ItemSigConfig<syn::Ident> {
30    pub(crate) fn name(&self) -> Option<&syn::Ident> {
31        self.name.as_ref().map(|name| &name.value)
32    }
33}
34
35impl<N> ItemSigConfig<N> {
36    pub(crate) fn vis(&self) -> Option<&syn::Visibility> {
37        self.vis.as_ref().map(|vis| &vis.value)
38    }
39
40    pub(crate) fn docs(&self) -> Option<&[syn::Attribute]> {
41        self.docs.as_ref().map(|docs| docs.value.as_slice())
42    }
43}
44
45pub(crate) struct ItemSigConfigParsing<'a> {
46    pub(crate) meta: &'a syn::Meta,
47    pub(crate) reject_self_mentions: Option<&'static str>,
48}
49
50impl<'a> ItemSigConfigParsing<'a> {
51    pub(crate) fn new(meta: &'a syn::Meta, reject_self_mentions: Option<&'static str>) -> Self {
52        ItemSigConfigParsing {
53            meta,
54            reject_self_mentions,
55        }
56    }
57
58    pub(crate) fn parse<N>(self) -> Result<ItemSigConfig<N>>
59    where
60        N: FromMeta,
61    {
62        let meta = self.meta;
63
64        if let syn::Meta::NameValue(_) = meta {
65            let name = SpannedKey::from_meta(meta)?;
66            return Ok(ItemSigConfig {
67                name: Some(name),
68                vis: None,
69                docs: None,
70            });
71        }
72
73        #[derive(Debug, FromMeta)]
74        struct Full<N> {
75            name: Option<SpannedKey<N>>,
76            vis: Option<SpannedKey<syn::Visibility>>,
77
78            #[darling(default, with = super::parse_docs, map = Some)]
79            doc: Option<SpannedKey<Vec<syn::Attribute>>>,
80        }
81
82        let full: Full<N> = crate::parsing::parse_non_empty_paren_meta_list(meta)?;
83
84        if let Some(context) = self.reject_self_mentions {
85            if let Some(docs) = &full.doc {
86                crate::parsing::reject_self_mentions_in_docs(context, docs)?;
87            }
88        }
89
90        let config = ItemSigConfig {
91            name: full.name,
92            vis: full.vis,
93            docs: full.doc,
94        };
95
96        Ok(config)
97    }
98}