Skip to content
Open
3 changes: 3 additions & 0 deletions derive_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
- Allow default values that access `self` in combination with the "owned" pattern. #298

## [0.20.0] - 2024-02-14
- Bump `syn` to version 2 #308
- Bump `darling` to version 0.20.6 #308
Expand Down
36 changes: 18 additions & 18 deletions derive_builder/tests/compile-fail/crate_root.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,6 @@ help: consider importing one of these items
5 | use std::option::Option;
|

error[E0433]: failed to resolve: could not find `export` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
7 | #[derive(Builder)]
| ^^^^^^^ not found in `empty::export::core::clone`
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
|
5 | use core::clone::Clone;
|
5 | use derive_builder::export::core::clone::Clone;
|
5 | use serde::__private::Clone;
|
5 | use std::clone::Clone;
|

error[E0433]: failed to resolve: could not find `export` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
Expand Down Expand Up @@ -91,6 +73,24 @@ help: consider importing this struct
5 | use derive_builder::UninitializedFieldError;
|

error[E0433]: failed to resolve: could not find `export` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
7 | #[derive(Builder)]
| ^^^^^^^ not found in `empty::export::core::clone`
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
|
5 | use core::clone::Clone;
|
5 | use derive_builder::export::core::clone::Clone;
|
5 | use serde::__private::Clone;
|
5 | use std::clone::Clone;
|

error[E0433]: failed to resolve: could not find `export` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
Expand Down
50 changes: 50 additions & 0 deletions derive_builder/tests/custom_default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,53 @@ mod struct_level {
assert_eq!(ipsum.not_type_default, None);
}
}

mod owned_field {

#[derive(Debug, Clone, PartialEq, Eq, Builder)]
#[builder(pattern = "owned")]
struct Lorem {
#[builder(default = "self.ipsum_default()")]
ipsum: String,

#[builder(setter(skip), default = "self.dolor_default()")]
dolor: String,
}

impl LoremBuilder {
fn ipsum_default(&self) -> String {
"ipsum".to_string()
}
fn dolor_default(&self) -> String {
"dolor".to_string()
}
}

#[test]
fn builder_test() {
let x = LoremBuilder::create_empty()
.ipsum("Ipsum".to_string())
.build()
.unwrap();

assert_eq!(
x,
Lorem {
ipsum: "Ipsum".to_string(),
dolor: "dolor".to_string(),
}
);
}
#[test]
fn defaults_test() {
let x = LoremBuilder::create_empty().build().unwrap();

assert_eq!(
x,
Lorem {
ipsum: "ipsum".to_string(),
dolor: "dolor".to_string(),
}
);
}
}
18 changes: 17 additions & 1 deletion derive_builder_core/src/build_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use quote::{ToTokens, TokenStreamExt};
use syn::spanned::Spanned;

use crate::{
doc_comment_from, BuilderPattern, DefaultExpression, Initializer, DEFAULT_STRUCT_NAME,
doc_comment_from, BuilderPattern, DefaultExpression, FieldDefaultValue, Initializer,
DEFAULT_STRUCT_NAME,
};

/// Initializer for the struct fields in the build method, implementing
Expand Down Expand Up @@ -57,6 +58,8 @@ pub struct BuildMethod<'a> {
pub error_ty: syn::Path,
/// Field initializers for the target type.
pub initializers: Vec<TokenStream>,
/// Default values for the target type
pub defaults: Vec<TokenStream>,
/// Doc-comment of the builder struct.
pub doc_comment: Option<syn::Attribute>,
/// Default value for the whole struct.
Expand All @@ -74,6 +77,7 @@ impl<'a> ToTokens for BuildMethod<'a> {
let vis = &self.visibility;
let target_ty = &self.target_ty;
let target_ty_generics = &self.target_ty_generics;
let defaults = &self.defaults;
let initializers = &self.initializers;
let self_param = match self.pattern {
BuilderPattern::Owned => quote!(self),
Expand All @@ -100,6 +104,7 @@ impl<'a> ToTokens for BuildMethod<'a> {
{
#validate_fn
#default_struct
#(#defaults)*
Ok(#target_ty {
#(#initializers)*
})
Expand All @@ -125,6 +130,16 @@ impl<'a> BuildMethod<'a> {
self.initializers.push(quote!(#init));
self
}

/// Populate the `BuildMethod` with appropiate default values of
/// the underlying struct.
///
/// For each struct field this must be called with the appropriate
/// default value.
pub fn push_default(&mut self, default: FieldDefaultValue) -> &mut Self {
self.defaults.push(quote!(#default));
self
}
}

// pub struct BuildMethodError {
Expand All @@ -150,6 +165,7 @@ macro_rules! default_build_method {
target_ty_generics: None,
error_ty: syn::parse_quote!(FooBuilderError),
initializers: vec![quote!(foo: self.foo,)],
defaults: vec![quote!()],
doc_comment: None,
default_struct: None,
validate_fn: None,
Expand Down
Loading