Skip to content

derive

Applies to: structs functions methods

⚠️ Do not confuse this with #[derive(bon::Builder)]⚠️

Generates additional derives for the builder struct itself. The syntax is similar to the regular #[derive(...)] attribute, but it must be wrapped in #[builder(derive(...))]. Expects one or more of the supported derives separated by a comma.

The following derives are supported: Clone, Debug.

WARNING

The format of the Debug output of the builder is not stable, and it may change between patch versions of bon.

Example:

rust
use bon::Builder;

#[derive(Builder)]
#[builder(derive(Clone, Debug))] 
struct Example {
    name: String,
    is_admin: bool,
    level: Option<u32>,
}

let builder = Example::builder().name("Bon".to_owned());

// We can clone the builder
let builder = builder.clone(); 

// We can debug-format the builder
let builder_debug = format!("{builder:?}"); 

assert_eq!(
    builder_debug,
    // Only the fields that were set will be output
    r#"ExampleBuilder { name: "Bon" }"#
);

// Finish building
let example = builder.is_admin(true).build();
rust
use bon::builder;

#[builder(derive(Clone, Debug))] 
fn example(
    name: String,
    is_admin: bool,
    level: Option<u32>,
) {}

let builder = example().name("Bon".to_owned());

// We can clone the builder
let builder = builder.clone(); 

// We can debug-format the builder
let builder_debug = format!("{builder:?}"); 

assert_eq!(
    builder_debug,
    // Only the fields that were set will be output
    r#"ExampleBuilder { name: "Bon" }"#
);

// Finish building
builder.is_admin(true).call();
rust
use bon::bon;

#[derive(Debug)]
struct Example;

#[bon]
impl Example {
    #[builder(derive(Clone, Debug))] 
    fn method(
        name: String,
        is_admin: bool,
        level: Option<u32>,
    ) {}

    #[builder(derive(Debug))]
    fn method_with_self(&self) {}
}

let builder = Example::method().name("Bon".to_owned());

// We can clone the builder
let builder = builder.clone(); 

// We can debug-format the builder
let builder_debug = format!("{builder:?}"); 

assert_eq!(
    builder_debug,
    // Only the fields that were set will be output
    r#"ExampleMethodBuilder { name: "Bon" }"#
);

// Finish building
builder.is_admin(true).call();

// The debug output of the builder for methods with `self` includes
// the special `self` field with the receiver.
assert_eq!(
    format!("{:?}", Example.method_with_self()),
    "ExampleMethodWithSelfBuilder { self: Example }"
)

Generic types handling

If the underlying struct or fn contains generic type parameters, then the generated impl block will include a where bound requiring the respective trait (Clone or Debug) to be implemented by all of them. This follows the behaviour of the standard derive macros.

This works fine in most cases, but sometimes the generated bounds may be overly restrictive. To fix that, you can manually specify the bounds using the syntax #[builder(derive(Trait(bounds(...))))], where ... is a comma-separated list of where bounds.

See the example of this problem, and how it can be fixed (click on the tab Fixed in the code snippet):

rust
use bon::Builder;
use std::rc::Rc;

#[derive(Builder)]
#[builder(derive(Clone))]
struct Example<T, U> {
    x: Rc<T>,
    y: U,
}

struct NonCloneable;

let builder = Example::<_, ()>::builder().x(Rc::new(NonCloneable));

// `Rc` can be cloned even if `T` is not `Clone`, but this code
// doesn't compile, because the `Clone` impl for `ExampleBuilder`
// conservatively requires `T: Clone`
builder.clone(); 
rust
use bon::Builder;
use std::rc::Rc;

#[derive(Builder)]
// Only a bound `U: Clone` is needed in this case
#[builder(derive(Clone(bounds(U: Clone))))] 
struct Example<T, U> {
    x: Rc<T>,
    y: U,
}

struct NonCloneable;

let builder = Example::<_, ()>::builder().x(Rc::new(NonCloneable));

// Now this works, because there is no bound `T: Clone`
builder.clone();

TIP

If you'd like to know why this attribute is this dumb and doesn't just add a where Rc<T>: Clone bound instead, then check this article about the "Implied bounds and perfect derive" by Niko Matsakis 📖.

Compile errors

Requires that all members of the builder including the receiver (if this is a builder for an associated method) implement the target trait. For example, this doesn't compile because not all members implement Clone:

Example:

rust
use bon::Builder;

struct NonClone;

#[derive(Builder)]
#[builder(Clone)]
struct Example {
    // Doesn't derive `Clone`, so this code doesn't compile
    non_clone NonClone,                                     
    cloneable: u32
}