Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for custom default fuction with owned pattern #315

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
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