mlx_internal_macros/
derive_builder.rs

1use darling::FromDeriveInput;
2use quote::quote;
3use syn::{DeriveInput, Ident};
4
5use crate::shared::{
6    parse_fields_from_derive_input, BuilderStructAnalyzer, BuilderStructProperty, PathOrIdent,
7    Result,
8};
9
10pub(crate) fn expand_derive_builder(input: DeriveInput) -> Result<proc_macro2::TokenStream> {
11    let builder_struct_prop = BuilderStructProperty::from_derive_input(&input)?;
12    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
13
14    let builder_ident = &builder_struct_prop.ident;
15    if !is_builder_struct_end_with_builder(builder_ident) {
16        return Err("Builder struct must end with 'Builder'".into());
17    }
18    let builder_ident_str = builder_ident.to_string();
19    let struct_ident = Ident::new(
20        // We have already checked that the builder struct ends with 'Builder'
21        &builder_ident_str[..builder_ident_str.len() - "Builder".len()],
22        builder_ident.span(),
23    );
24    let root = match builder_struct_prop.root {
25        Some(path) => path,
26        None => syn::parse_quote!(::mlx_rs),
27    };
28
29    let builder_struct_ident = PathOrIdent::Ident(builder_ident.clone());
30    let (mandatory_fields, optional_fields) = parse_fields_from_derive_input(&input)?;
31    let is_default_infallible = builder_struct_prop
32        .default_infallible
33        .unwrap_or_else(|| builder_struct_prop.err.is_none());
34
35    let builder_struct_analyzer = BuilderStructAnalyzer {
36        struct_ident: &struct_ident,
37        builder_struct_ident: &builder_struct_ident,
38        root: &root,
39        impl_generics: &impl_generics,
40        type_generics: &type_generics,
41        where_clause,
42        mandatory_fields: &mandatory_fields,
43        optional_fields: &optional_fields,
44        build_with: builder_struct_prop.build_with.as_ref(),
45        err: builder_struct_prop.err.as_ref(),
46    };
47
48    let impl_builder = builder_struct_analyzer.impl_builder();
49    let impl_struct_new = builder_struct_analyzer.impl_struct_new(is_default_infallible);
50
51    Ok(quote! {
52        #impl_builder
53        #impl_struct_new
54    })
55}
56
57fn is_builder_struct_end_with_builder(ident: &Ident) -> bool {
58    ident.to_string().ends_with("Builder")
59}