2 unstable releases

new 0.2.0 Nov 3, 2024
0.1.0 Sep 8, 2024

#73 in Procedural macros

MIT/Apache

12KB
136 lines

bon home

github crates.io docs.rs docs.rs

bon is a Rust crate for generating compile-time-checked builders for functions and structs. It also provides idiomatic partial application with optional and named parameters for functions and methods.

Visit the guide for a complete overview of the crate.

Quick examples

Builder for a free function

You can turn a function with positional parameters into a function with named parameters just by placing the #[builder] attribute on top of it.

use bon::builder;

#[builder]
fn greet(name: &str, level: Option<u32>) -> String {
    let level = level.unwrap_or(0);

    format!("Hello {name}! Your level is {level}")
}

let greeting = greet()
    .name("Bon")
    .level(24) // <- setting `level` is optional, we could omit it
    .call();

assert_eq!(greeting, "Hello Bon! Your level is 24");

Builder for an associated method

For associated methods you also need to add the #[bon] macro on top of the impl block.

use bon::bon;

struct User {
    id: u32,
    name: String,
}

#[bon] // <- this attribute is required on impl blocks that contain `#[builder]`
impl User {
    #[builder]
    fn new(id: u32, name: String) -> Self {
        Self { id, name }
    }

    #[builder]
    fn greet(&self, target: &str, level: Option<&str>) -> String {
        let level = level.unwrap_or("INFO");
        let name = &self.name;

        format!("[{level}] {name} says hello to {target}")
    }
}

// The method named `new` generates `builder()/build()` methods
let user = User::builder()
    .id(1)
    .name("Bon".to_owned())
    .build();

// All other methods generate `method_name()/call()` methods
let greeting = user
    .greet()
    .target("the world")
    // `level` is optional, we can omit it here
    .call();

assert_eq!(user.id, 1);
assert_eq!(user.name, "Bon");
assert_eq!(greeting, "[INFO] Bon says hello to the world");

Builder for a struct

The #[derive(Builder)] macro generates a builder for a struct.

use bon::Builder;

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

let user = User::builder()
    .name("Bon".to_owned())
    // `level` is optional, we could omit it here
    .level(24)
    // call setters in any order
    .is_admin(true)
    .build();

assert_eq!(user.name, "Bon");
assert_eq!(user.level, Some(24));
assert!(user.is_admin);

See the guide for more.


If you like the idea of this crate and want to say "thank you" or "keep doing this" consider giving us a star ⭐ on Github. Any support and contribution are appreciated 🐱!

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~4–11MB
~119K SLoC