bon_macros/builder/builder_gen/top_level_config/
generics.rs1use crate::parsing::{ItemSigConfig, ItemSigConfigParsing};
2use crate::util::prelude::*;
3use darling::FromMeta;
4
5#[derive(Debug, Clone, Default)]
6pub(crate) struct GenericsConfig {
7 pub(crate) setters: Option<ItemSigConfig<String>>,
8}
9
10impl FromMeta for GenericsConfig {
11 fn from_meta(meta: &syn::Meta) -> Result<Self> {
12 meta.require_list()?.require_parens_delim()?;
13
14 #[derive(FromMeta)]
15 struct Parsed {
16 #[darling(default, with = parse_setters_config, map = Some)]
17 setters: Option<ItemSigConfig<String>>,
18 }
19
20 let parsed = Parsed::from_meta(meta)?;
21
22 Ok(Self {
23 setters: parsed.setters,
24 })
25 }
26}
27
28fn parse_setters_config(meta: &syn::Meta) -> Result<ItemSigConfig<String>> {
29 if !cfg!(feature = "experimental-generics-setters") {
30 bail!(
31 meta,
32 "🔬 `generics(setters(...))` attribute is experimental and requires \
33 \"experimental-generics-setters\" cargo feature to be enabled",
34 );
35 }
36
37 const DOCS_CONTEXT: &str = "builder struct's impl block";
38 let config: ItemSigConfig<String> =
39 ItemSigConfigParsing::new(meta, Some(DOCS_CONTEXT)).parse()?;
40
41 let name_pattern = config.name.as_ref().ok_or_else(|| {
43 err!(
44 meta,
45 "`name` parameter is required for `generics(setters(...))`; \
46 specify a pattern like `name = \"conv_{{}}\"` where `{{}}` will be \
47 replaced with the snake_case name of each generic parameter"
48 )
49 })?;
50
51 if !name_pattern.value.contains("{}") {
52 bail!(
53 &name_pattern.key,
54 "the `name` pattern must contain the `{{}}` placeholder, \
55 which will be replaced with the snake_case name of each generic parameter"
56 );
57 }
58
59 Ok(config)
60}