infallible-builder

Crates.ioinfallible-builder
lib.rsinfallible-builder
version0.0.1
created_at2025-07-23 06:58:26.252059+00
updated_at2025-07-23 08:34:26.78987+00
descriptionDerive macro for infallible implementation of the builder pattern.
homepage
repositoryhttps://github.com/agirardeau/agpublic/rust/infallible-builder
max_upload_size
id1764419
size10,495
(agirardeau)

documentation

README

infallible-builder

Macro crate for generating infallible Builder interfaces.

Example Usage

[dependencies]
infallible-builder = "0.0"
use infallible_builder::Builder;

#[derive(Default)]
#[Builder]
struct Person {
    name: String,
    age: i64,
    birthday: Option<String>,
}

let person = Person::builder()
    .name("Alice")
    .age(30)
    .build();
assert_eq!(person.name, "Alice");
assert_eq!(person.age, 30);
assert_eq!(person.birthday, None);

The base type must implement Default. To implement Default for structs with non-Default fields, consider a crate like [smart-default] (https://docs.rs/smart-default/latest/smart_default/):

use smart_default::SmartDefault;

// Non-Default type
pub enum Color { Red, Blue }

#[derive(SmartDefault)]
#[Builder]
pub struct Line {
    length: i64,
    #[default(Color::Red)]
    color: Color,
}

Design Philosophy

Compared to other crates (e.g. [derive_builder] (https://docs.rs/derive_builder/latest/derive_builder/index.html), [typed-builder] (https://docs.rs/typed-builder/latest/typed_builder/index.html)), infallible-builder is more opinionated. It generates builder types only with the following restrictions:

  • Builders do not require fields, i.e. MyType::builder().build() is always allowed
  • Builder methods are thin setters, at most calling .into()
  • Builders do not contain additional logic or functionality, such as validation or serialization

This has some direct benefits:

  • The build() method is always infallible, improving ergonomics
  • The builder interface is self apparent from the base struct

infallible-builder makes other opinionated choices with the goal of builders for different base structs having consistent interfaces:

  • setter(into, strip_option) is configured by default
  • The "owned" pattern is used rather than the "mutable" pattern, since "mutable" disallows structs with non-Clone fields

It is this crate author's opinion that builder customizability is ultimately detrimental, mostly enabling use cases where builders are not an ideal fit.

Implementation Notes

As of 0.0, this is implemented as attribute proc macro that adds derive_builder::Builder to the annotated struct. As a result, some #[builder()] annotations supported by derive_builder are respected, however this behavior may change in the future.

Commit count: 17

cargo fmt