colin-kiegel / rust-derive-builder

derive builder implementation for rust structs
https://colin-kiegel.github.io/rust-derive-builder/
Apache License 2.0
1.28k stars 82 forks source link

Update documentation to describe new errors #190

Closed TedDriggs closed 2 years ago

TedDriggs commented 3 years ago

The crate-level docs need to be updated:

andy128k commented 3 years ago

I am experimenting with custom errors and here are some observations.

Box\

Works like a charm, but declaration looks a bit noisy.

// Error is still a `String` here
fn validate_age(builder: &ExampleBuilder) -> Result<(), String> {
    match builder.age {
        Some(age) if age > 150 => Err(format!("Nobody is {} years old", age)),
        _ => Ok(()),
    }
}

#[derive(Debug, Builder)]
#[builder(setter(into), build_fn(validate = "validate_age", error = "Box<dyn std::error::Error>"))]
struct Example {
    name: String,
    age: usize,
}

Anyhow

anyhow::Error cannot convert a String to anyhow::Error, so custom validator needs to be adjusted.

fn validate_age(builder: &ExampleBuilder) -> Result<(), anyhow::Error> {
    match builder.age {
        Some(age) if age > 150 => Err(anyhow!("Nobody is {} years old", age)),
        _ => Ok(()),
    }
}

#[derive(Debug, Builder)]
#[builder(setter(into), build_fn(validate = "validate_age", error = "anyhow::Error"))]
struct Example {
    name: String,
    age: usize,
}

Infallible (nightly)

This doesn't compile

#![feature(never_type, unwrap_infallible)]

#[macro_use]
extern crate derive_builder;

#[derive(Debug, Builder)]
#[builder(setter(into), build_fn(error = "!"))]
struct Example {
    #[builder(default = "\"John Doe\".to_string()")]
    name: String,
    #[builder(default = "17")]
    age: usize,
}

fn main() {
    let person = ExampleBuilder::default()
        .name("Jane Doe")
        .age(200usize)
        .build()
        .into_ok();
    println!("{:?}", person);
}

Compile error is

error: Unknown literal value `!`
 --> derive_builder/examples/infallible.rs:9:42
  |
9 | #[builder(setter(into), build_fn(error = "!"))]
  |                                          ^^^

But the trick with type alias makes it work

#![feature(never_type, unwrap_infallible)]

#[macro_use]
extern crate derive_builder;

type Never = !; // alias

#[derive(Debug, Builder)]
#[builder(setter(into), build_fn(error = "Never"))]
struct Example {
    #[builder(default = "\"John Doe\".to_string()")]
    name: String,
    #[builder(default = "17")]
    age: usize,
}

fn main() {
    let person = ExampleBuilder::default()
        .name("Jane Doe")
        .age(200usize)
        .build()
        .into_ok();
    println!("{:?}", person);
}