No more worrying whether the build
call on your builder will return Ok
or not. Maybe you forgot to set a field? typesafe-builders
solves this by using the Rust type-system to ensure correct usage.
```rust use typesafe_builders::prelude::*;
fn main() {
#[derive(Builder)]
struct Point {
#[builder(constructor)]
x: u8,
y: u8,
#[builder(optional)]
z: Option
// `builder` requires `x` since it is marked as `constructor`.
let builder = Point::builder(1);
// These do not compile:
// partial.x(6); // `x` is already set
// partial.build(); // `y` is not set
// `build` is only available once all required fields are set:
let result = builder.y(2).build();
assert_eq!(result.x, 1);
assert_eq!(result.y, 2);
assert_eq!(result.z, None);
} ```
I can recommend this only for internal use. It is best to not expose these builder types as an API of your crate, since they look extremely ugly and verbose. For example:
```rust use typesafe_builders::prelude::*;
struct Point { x: u8, y: u8, z: u8, }
// Ugly type name here... and it only gets worse for const-generics etc.
fn preset() -> GenericPointBuilder
fn main() { let partial = preset(); let point = partial.x(1).y(2).build(); } ```
Please open an MR/Issue if you know how to improve this.
Attributes can be combined. Ones that do not work together will throw an explicit error at compile time. Duplicates always error.
A field can be set, but does not have to be. Requires the field type to be Default
.
```rust use typesafe_builders::prelude::*;
pub struct Struct { #[builder(optional)] x: u8, }
fn main() { // without x Struct::builder().build(); // with x Struct::builder().x(4).build(); } ```
Require a field to be set upon builder construction.
```rust use typesafe_builders::prelude::*;
pub struct Struct { #[builder(constructor)] x: u8, }
fn main() { Struct::builder(4).build(); // does not work: // Struct::builder(4).x(5).build(); } ```
Decay the type to its first generic. Eases use for Option
, Box
etc. Requires that the decayed type can be into
ed its original. Works on all types with one generic arg.
```rust use typesafe_builders::prelude::*;
pub struct Struct {
#[builder(decay)]
x: Option
fn main() {
// Use 4
of Some(4)
Struct::builder().x(4).build();
}
```
Const generic one-hot bitfields. What you get is similar to this:
```rust
pub struct Builder
impl impl // The build function is only available once all fields are set:
impl Builder }
``` They work as expected ```rust
use typesafe_builders::prelude::*; pub struct Struct<'a, 'b, 'c> {
x: &'a Box<&'b Option<&'c str>>, // yikes
} fn main() {
Struct::builder().x(&Box::new(&Some("hi"))).build();
}
``` Works as expected, but does not yet support defaults. ```rust
mod other {
use typesafe_builders::prelude::*; } fn main() {
other::Struct:: Works as expected, but does not yet support defaults. ```rust
mod other {
use typesafe_builders::prelude::*; } fn main() {
other::Struct::<1>::builder().x([1]).build();
}
```}
More Examples
Lifetimes
[derive(Builder)]
Generics
#[derive(Builder)]
pub struct Struct<T: Clone> {
y: Option<T>,
}
Const Generics
#[derive(Builder)]
pub struct Struct<const LEN: usize> {
x: [u8; LEN],
}
TODOs
optional
fields.rename
field attribute.constructor
or something like this to have mandatory args directly in the builder
function.Into
or whatever to cast types.Some
automatically.