bon_macros/builder/builder_gen/builder_derives/
mod.rs

1mod clone;
2mod debug;
3mod into;
4mod into_future;
5
6use super::top_level_config::{DeriveConfig, DerivesConfig};
7use super::BuilderGenCtx;
8use crate::util::prelude::*;
9use darling::ast::GenericParamExt;
10
11impl BuilderGenCtx {
12    pub(crate) fn builder_derives(&self) -> Result<TokenStream> {
13        let DerivesConfig {
14            clone,
15            debug,
16            into,
17            into_future,
18        } = &self.builder_type.derives;
19
20        let mut tokens = TokenStream::new();
21
22        if let Some(derive) = clone {
23            tokens.extend(self.derive_clone(derive));
24        }
25
26        if let Some(derive) = debug {
27            tokens.extend(self.derive_debug(derive));
28        }
29
30        if into.is_present() {
31            tokens.extend(self.derive_into()?);
32        }
33
34        if let Some(derive) = into_future {
35            tokens.extend(self.derive_into_future(derive)?);
36        }
37
38        Ok(tokens)
39    }
40
41    /// We follow the logic of the standard `#[derive(...)]` macros such as `Clone` and `Debug`.
42    /// They add bounds of their respective traits to every generic type parameter on the struct
43    /// without trying to analyze if that bound is actually required for the derive to work, so
44    /// it's a conservative approach.
45    ///
46    /// However, the user can also override these bounds using the `bounds(...)` attribute for
47    /// the specific derive.
48    fn where_clause_for_derive(
49        &self,
50        target_trait_bounds: &TokenStream,
51        derive: &DeriveConfig,
52    ) -> TokenStream {
53        let derive_specific_predicates = derive
54            .bounds
55            .as_ref()
56            .map(ToTokens::to_token_stream)
57            .unwrap_or_else(|| {
58                let bounds = self
59                    .generics
60                    .decl_without_defaults
61                    .iter()
62                    .filter_map(syn::GenericParam::as_type_param)
63                    .map(|param| {
64                        let ident = &param.ident;
65                        quote! {
66                            #ident: #target_trait_bounds
67                        }
68                    });
69
70                quote! {
71                    #( #bounds, )*
72                }
73            });
74
75        let inherent_item_predicates = self.generics.where_clause_predicates();
76
77        quote! {
78            where
79                #( #inherent_item_predicates, )*
80                #derive_specific_predicates
81        }
82    }
83}