Type Safe Builder Pattern

Infallible compile-time checked builders for your structs.

License: GPL v3

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. # Example ```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); } ``` # Known Downside 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::*; #[derive(Builder)] struct Point { x: u8, y: u8, z: u8, } // Ugly type name here... and it only gets worse for const-generics etc. fn preset() -> GenericPointBuilder { Point::builder().z(0) } 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. ## Field Attributes Attributes can be combined. Ones that do not work together will throw an explicit error at compile time. Duplicates always error. ### Optional A field can be set, but does not have to be. Requires the field type to be `Default`. ```rust use typesafe_builders::prelude::*; #[derive(Builder)] pub struct Struct { #[builder(optional)] x: u8, } fn main() { // without x Struct::builder().build(); // with x Struct::builder().x(4).build(); } ``` ### Constructor Require a field to be set upon builder construction. ```rust use typesafe_builders::prelude::*; #[derive(Builder)] pub struct Struct { #[builder(constructor)] x: u8, } fn main() { Struct::builder(4).build(); // does not work: // Struct::builder(4).x(5).build(); } ``` ### Decay 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::*; #[derive(Builder)] pub struct Struct { #[builder(decay)] x: Option, } fn main() { // Use `4` of `Some(4)` Struct::builder().x(4).build(); } ``` # How does it work? Const generic one-hot bitfields. What you get is similar to this: ```rust pub struct Builder { x: Option, y: Option, } impl Builder { fn set_x(self, x: u8) -> Builder { unimplemented!() } } impl Builder { fn set_y(self, y: u8) -> Builder { unimplemented!() } } // The build function is only available once all fields are set: impl Builder { fn build() { } } ``` # More Examples ### Lifetimes They work as expected ```rust use typesafe_builders::prelude::*; #[derive(Builder)] pub struct Struct<'a, 'b, 'c> { x: &'a Box<&'b Option<&'c str>>, // yikes } fn main() { Struct::builder().x(&Box::new(&Some("hi"))).build(); } ``` ### Generics Works as expected, but does not yet support defaults. ```rust mod other { use typesafe_builders::prelude::*; #[derive(Builder)] pub struct Struct { y: Option, } } fn main() { other::Struct::::builder().y(Some(4)).build(); } ``` ### Const Generics Works as expected, but does not yet support defaults. ```rust mod other { use typesafe_builders::prelude::*; #[derive(Builder)] pub struct Struct { x: [u8; LEN], } } fn main() { other::Struct::<1>::builder().x([1]).build(); } ``` # TODOs - [x] Lifetimes - [x] Generics - [x] Bounds - [ ] With default - [x] Const generics - [ ] With default - [x] Add `optional` fields. - [ ] Add `rename` field attribute. - [x] Add `constructor` or something like this to have mandatory args directly in the `builder` function. - [ ] Add `Into` or whatever to cast types. - [ ] Add way to pass options as `Some` automatically. - [ ] Cleanup