diff options
| author | Mica White <botahamec@outlook.com> | 2026-08-19 19:22:32 -0400 |
|---|---|---|
| committer | Mica White <botahamec@outlook.com> | 2026-08-19 19:22:32 -0400 |
| commit | bda071150154b953a42cbf6743ac1b79f8bf0668 (patch) | |
| tree | cf4605cea9537aca9be4512e0996b58db45b9762 /src/lib.rs | |
| parent | 2573cbc9622da4c74429b4f6bb9c640b95dc4c04 (diff) | |
Support custom fields and methods
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 39 |
1 files changed, 25 insertions, 14 deletions
@@ -8,7 +8,7 @@ //! use feluments::*; //! //! #[derive(Debug, PartialEq, Eq, Builder)] -//! #[builder(vis = pub)] +//! #[builder(vis = pub, makro)] //! struct Foo { //! #[builder(default = 45)] //! x: i32, @@ -20,13 +20,13 @@ //! //! # fn main() { //! assert_eq!( -//! build!(Foo { x: 32, y: "baz" }), +//! Foo! { x: 32, y: "baz" }, //! Foo { x: 32, y: "baz".into(), z: () }, //! ); //! # } //! ``` //! -//! The above call to the [`build`] macro expands to the following: +//! The above call to the `Foo` macro expands to the following: //! //! ``` //! # use feluments::*; @@ -92,6 +92,7 @@ struct BuilderFieldOptions { #[from_attr(ident = builder)] struct BuilderOptions { vis: Option<Visibility>, + name: Option<String>, makro: bool, } @@ -101,6 +102,7 @@ struct BuilderOptions { /// When the `builder` attribute is applied to the struct, it may take the /// following arguments: /// - `vis`: The visibility of the `builder` method. +/// - `name`: Sets the name of the builder struct. /// - `makro`: Creates a macro to construct an instance of the struct. /// /// When the `builder` attribute is applied to a field of the struct, there are @@ -111,7 +113,8 @@ struct BuilderOptions { /// provided, then the default value will be the one provided. Otherwise, it /// will be [`Default::default`]. /// - `default`: The default value of the field. Setting this parameter also -/// implies `optional` +/// implies `optional`. The value may be an expression, and it may even +/// reference previous fields. /// - `into`: Arguments to the setter may be of any type that implements `Into` /// for the type of the field. /// @@ -125,7 +128,7 @@ struct BuilderOptions { /// struct Foo { /// #[builder(default = 45)] /// x: i32, -/// #[builder(into)] +/// #[builder(into, default = x.to_string())] /// y: String, /// #[builder(optional)] /// z: () @@ -133,11 +136,11 @@ struct BuilderOptions { /// /// # fn main() { /// assert_eq!( -/// Foo::builder().y("bar").z(()).build(), -/// Foo { x: 45, y: "bar".into(), z: () }, +/// Foo::builder().x(2).z(()).build(), +/// Foo { x: 2, y: "2".into(), z: () }, /// ); /// assert_eq!( -/// Foo! { y: "bar", z: () }, +/// Foo! { y: "bar" }, /// Foo { x: 45, y: "bar".into(), z: () }, /// ) /// # } @@ -148,7 +151,6 @@ struct BuilderOptions { pub fn derive_builder(input: TokenStream) -> TokenStream { let structure = parse_macro_input!(input as ItemStruct); let struct_name = &structure.ident; - let builder_name = format_ident!("{}Builder", structure.ident); let fields = structure .fields .into_iter() @@ -173,6 +175,11 @@ pub fn derive_builder(input: TokenStream) -> TokenStream { || fields .iter() .all(|field| matches!(field.visibility, Visibility::Public(_))); + let builder_name = if let Some(builder_name) = builder_options.name { + format_ident!("{builder_name}") + } else { + format_ident!("{}Builder", structure.ident) + }; let builder_macro_vis = is_builder_visible.then(|| quote! { #[macro_export]}); let builder_macro = builder_options.makro.then(|| { quote! { @@ -266,14 +273,16 @@ pub fn derive_builder(input: TokenStream) -> TokenStream { } }) .collect::<Box<_>>(); - let build_fields = fields.iter().map(|field| { + let build_field_assignments = fields.iter().map(|field| { let field_name = &field.name; match &field.default { Default::Value(default_value) => { - quote! { #field_name: self.#field_name.unwrap_or_else(|| #default_value) } + quote! { let #field_name = self.#field_name.unwrap_or_else(|| #default_value); } + } + Default::Impl => quote! { let #field_name = self.#field_name.unwrap_or_default(); }, + Default::None => { + quote! { let #field_name = unsafe { self.#field_name.unwrap_unchecked() }; } } - Default::Impl => quote! { #field_name: self.#field_name.unwrap_or_default() }, - Default::None => quote! { #field_name: unsafe { self.#field_name.unwrap_unchecked() } }, } }); @@ -302,10 +311,12 @@ pub fn derive_builder(input: TokenStream) -> TokenStream { #(#setters)* } + #[allow(all)] impl #builder_name<#(#trues),*> { #builder_visibility fn build(self) -> #struct_name { + #(#build_field_assignments)* #struct_name { - #(#build_fields,)* + #(#field_names,)* } } } |
