summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2026-08-19 19:22:32 -0400
committerMica White <botahamec@outlook.com>2026-08-19 19:22:32 -0400
commitbda071150154b953a42cbf6743ac1b79f8bf0668 (patch)
treecf4605cea9537aca9be4512e0996b58db45b9762 /src
parent2573cbc9622da4c74429b4f6bb9c640b95dc4c04 (diff)
Support custom fields and methods
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs39
1 files changed, 25 insertions, 14 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 315dd73..314f813 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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,)*
}
}
}