bon_macros/builder/builder_gen/member/config/
setters.rs1use crate::parsing::{ItemSigConfig, ItemSigConfigParsing, SpannedKey};
2use crate::util::prelude::*;
3use darling::ast::NestedMeta;
4use darling::FromMeta;
5use syn::punctuated::Punctuated;
6
7const DOCS_CONTEXT: &str = "builder struct's impl block";
8
9fn parse_setter_fn(meta: &syn::Meta) -> Result<SpannedKey<ItemSigConfig>> {
10 let params = ItemSigConfigParsing {
11 meta,
12 reject_self_mentions: Some(DOCS_CONTEXT),
13 }
14 .parse()?;
15
16 SpannedKey::new(meta.path(), params)
17}
18
19fn parse_docs(meta: &syn::Meta) -> Result<SpannedKey<Vec<syn::Attribute>>> {
20 crate::parsing::parse_docs_without_self_mentions(DOCS_CONTEXT, meta)
21}
22
23#[derive(Debug, Default)]
24pub(crate) struct SettersConfig {
25 pub(crate) name: Option<SpannedKey<syn::Ident>>,
26 pub(crate) vis: Option<SpannedKey<syn::Visibility>>,
27 pub(crate) doc: SettersDocConfig,
28 pub(crate) fns: SettersFnsConfig,
29}
30
31impl FromMeta for SettersConfig {
32 fn from_meta(meta: &syn::Meta) -> Result<Self> {
33 let meta: Punctuated<syn::Meta, syn::Token![,]> =
34 crate::parsing::parse_paren_meta_list_with_terminated(meta)?;
35
36 let (docs, remaining_meta): (Vec<_>, Vec<_>) = meta
37 .into_iter()
38 .partition(|meta| meta.path().is_ident("doc"));
39
40 let doc = SettersDocConfig::from_docs_entries(docs)?;
41
42 #[derive(FromMeta)]
43 struct Parsed {
44 name: Option<SpannedKey<syn::Ident>>,
45 vis: Option<SpannedKey<syn::Visibility>>,
46
47 #[darling(flatten)]
48 fns: SettersFnsConfig,
49 }
50
51 let remaining_meta = remaining_meta
52 .into_iter()
53 .map(NestedMeta::Meta)
54 .collect::<Vec<_>>();
55
56 let parsed: Parsed = Parsed::from_list(&remaining_meta)?;
57
58 Ok(Self {
59 name: parsed.name,
60 vis: parsed.vis,
61 fns: parsed.fns,
62 doc,
63 })
64 }
65}
66
67#[derive(Debug, Default, FromMeta)]
68pub(crate) struct SettersFnsConfig {
69 #[darling(default, with = parse_setter_fn, map = Some)]
74 pub(crate) some_fn: Option<SpannedKey<ItemSigConfig>>,
75
76 #[darling(default, with = parse_setter_fn, map = Some)]
81 pub(crate) option_fn: Option<SpannedKey<ItemSigConfig>>,
82}
83
84#[derive(Debug, Default)]
85pub(crate) struct SettersDocConfig {
86 pub(crate) content: Option<SpannedKey<Vec<syn::Attribute>>>,
88
89 pub(crate) default: Option<SpannedKey<SettersDocDefaultConfig>>,
91}
92
93impl SettersDocConfig {
94 fn from_docs_entries(docs: Vec<syn::Meta>) -> Result<Self> {
95 let mut doc_config = None;
96 let mut doc_content = None;
97
98 for doc in docs {
99 match doc.require_list()?.delimiter {
100 syn::MacroDelimiter::Paren(_) => {
101 if doc_config.is_some() {
102 bail!(&doc, "repeated `doc(...)` attribute is not allowed");
103 }
104 doc_config = Some(doc);
105 }
106 syn::MacroDelimiter::Brace(_) => {
107 if doc_content.is_some() {
108 bail!(&doc, "repeated `doc {{...}}` attribute is not allowed");
109 }
110 doc_content = Some(doc);
111 }
112 syn::MacroDelimiter::Bracket(_) => {
113 bail!(&doc, "wrong delimiter, expected doc(...) or doc {{...}}",);
114 }
115 }
116 }
117
118 #[derive(FromMeta)]
119 struct Parsed {
120 #[darling(with = crate::parsing::parse_non_empty_paren_meta_list)]
121 default: Option<SpannedKey<SettersDocDefaultConfig>>,
122 }
123
124 let config = doc_config
125 .as_ref()
126 .map(crate::parsing::parse_non_empty_paren_meta_list::<Parsed>)
127 .transpose()?;
128
129 let content = doc_content.as_ref().map(parse_docs).transpose()?;
130
131 let mut me = Self {
132 content,
133 default: None,
134 };
135
136 if let Some(Parsed { default }) = config {
137 me.default = default;
138 }
140
141 Ok(me)
142 }
143}
144
145#[derive(Debug, Default, FromMeta)]
146pub(crate) struct SettersDocDefaultConfig {
147 pub(crate) skip: darling::util::Flag,
149}