bon_macros/builder/builder_gen/member/config/
getter.rs

1use crate::parsing::SpannedKey;
2use crate::util::prelude::*;
3use darling::FromMeta;
4
5#[derive(Debug, Default)]
6pub(crate) struct GetterConfig {
7    pub(crate) name: Option<SpannedKey<syn::Ident>>,
8    pub(crate) vis: Option<SpannedKey<syn::Visibility>>,
9    pub(crate) docs: Option<SpannedKey<Vec<syn::Attribute>>>,
10
11    /// Returns `&T` if [`None`]
12    pub(crate) kind: Option<SpannedKey<GetterKind>>,
13}
14
15#[derive(Debug)]
16pub(crate) enum GetterKind {
17    /// Returns `T` via [`Copy`]
18    Copy,
19
20    /// Returns `T` via [`Clone`]
21    Clone,
22
23    /// Returns `&<T as Deref>::Target`.
24    /// If the type is `None`, it will be inferred from the member's type.
25    Deref(Option<syn::Type>),
26}
27
28impl FromMeta for GetterConfig {
29    fn from_meta(meta: &syn::Meta) -> Result<Self> {
30        if let syn::Meta::Path(_) = meta {
31            return Ok(Self::default());
32        }
33
34        // Reject empty parens such as `#[builder(getter())]`
35        crate::parsing::require_non_empty_paren_meta_list_or_name_value(meta)?;
36
37        // Nested `Parsed` struct used as a helper for parsing the verbose form
38        #[derive(FromMeta)]
39        struct Parsed {
40            name: Option<SpannedKey<syn::Ident>>,
41            vis: Option<SpannedKey<syn::Visibility>>,
42
43            #[darling(rename = "doc", default, with = parse_docs, map = Some)]
44            docs: Option<SpannedKey<Vec<syn::Attribute>>>,
45
46            copy: Option<SpannedKey<()>>,
47            clone: Option<SpannedKey<()>>,
48
49            #[darling(default, map = Some, with = parse_deref)]
50            deref: Option<SpannedKey<Option<syn::Type>>>,
51        }
52
53        let Parsed {
54            name,
55            vis,
56            docs,
57            copy,
58            clone,
59            deref,
60        } = Parsed::from_meta(meta)?;
61
62        let kinds = [
63            copy.map(|cfg| cfg.with_value(GetterKind::Copy)),
64            clone.map(|cfg| cfg.with_value(GetterKind::Clone)),
65            deref.map(|ty| ty.map_value(GetterKind::Deref)),
66        ];
67
68        let kinds = kinds.into_iter().flatten().collect::<Vec<_>>();
69
70        if let [kind1, kind2, ..] = kinds.as_slice() {
71            bail!(
72                &kind1.key,
73                "`{}` can't be specified together with `{}`",
74                kind1.key,
75                kind2.key
76            );
77        }
78
79        let kind = kinds.into_iter().next();
80
81        Ok(Self {
82            name,
83            vis,
84            docs,
85            kind,
86        })
87    }
88}
89
90fn parse_deref(meta: &syn::Meta) -> Result<SpannedKey<Option<syn::Type>>> {
91    let value = match meta {
92        syn::Meta::NameValue(_) => bail!(
93            meta,
94            "expected `getter(deref)` or `getter(deref(...))` syntax"
95        ),
96        syn::Meta::Path(_) => None,
97        syn::Meta::List(meta) => Some(syn::parse2(meta.tokens.clone())?),
98    };
99
100    SpannedKey::new(meta.path(), value)
101}
102
103fn parse_docs(meta: &syn::Meta) -> Result<SpannedKey<Vec<syn::Attribute>>> {
104    crate::parsing::parse_docs_without_self_mentions("builder struct's impl block", meta)
105}