Skip to content

campeis/type_safe_builder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

type_safe_builder

A typesafe builder macro in Rust

The generated builder will make sure a struct can't be built if any of the required fields has not been set. The check will be done at compile time, so there will be no need to handle any error in the code.

use type_safe_builder_macro::Builder;

#[derive(Builder)]
struct Struct {
    field: String,
    a_field_that_has_not_been_set: String,
}

fn main() {
    let build = StructBuilder::builder()
        .field("value".into())
        .build(); // this will not compile
}

How to use

Basic usage

use type_safe_builder_macro::Builder;

#[derive(Builder)]
struct Struct {
    field: String,
}

fn main() {
    let build = StructBuilder::builder()
        .field("value".into())
        .build();
}

Default fields

If a field is of a type that implemets the Default trait it could be configured so the default() provided value could be used automatically whithout the need to call the field's setter method.

use type_safe_builder_macro::Builder;

#[derive(Builder)]
struct Struct {
    field: String,
    #[builder(default)]
    default_field: Option<&'static str>,
}

fn main() {
    let build = StructBuilder::builder()
        .field("value".into())
        .build();
}

Default fields value override

If the field type does't implement Default, or the wanted value is different from the one provided by default(), a specific value could be configured to be used without the need to explicitly call the setter.

use type_safe_builder_macro::Builder;

#[derive(Builder)]
struct Struct {
    field: String,
    #[builder(default=Some("default value"))]
    default_field: Option<&'static str>,
}

fn main() {
    let build = StructBuilder::builder()
        .field("value".into())
        .build();
}

All Default fields in the struct

If all fields of the struct to be built have valid Default implementwtion, the use of default() for all the fields could be set at struct level.

use type_safe_builder_macro::Builder;

#[derive(Builder)]
#[builder(default)]
struct Struct {
    field: Option<String>,
    other_field: Option<String>,
}

fn main() {
    let build = StructBuilder::builder()
        .build();
}

If default values is set a specific field can be set to require a value

use type_safe_builder_macro::Builder;

#[derive(Builder)]
#[builder(default)]
struct Struct {
    #[builder(mandatory)]
    field: String,
    default_field: Option<String>,
}

fn main() {
    let build = StructBuilder::builder()
        .field("value".into())
        .build();
}

Custom builder name

By default the name of the builder will be the word "Builder" prefixed with the name of struct that will be built. In the case this generated name would clash with the one of an existing struct, a different one could be configured.

use type_safe_builder_macro::Builder;

#[derive(Builder)]
#[builder(name=CustomBuilder)]
struct Struct {}

fn main() {
    let build = CustomBuilder::builder()
        .build();
}

Custom setter name

By default the builder has a setter method with the same name as the property it will set. This could be configured on a field basis so the generated setter method has a specific name.

use type_safe_builder_macro::Builder;

#[derive(Builder)]
struct Struct {
    #[builder(setter_name=custom_setter)]
    field: String,
}

fn main() {
    let build = StructBuilder::builder()
        .custom_setter("value".into())
        .build();
}

Allow field value to be set multiple times

By default the builder will not allow a field to be set multiple times.

Because of this the following code would not compile.

use type_safe_builder_macro::Builder;

#[derive(Builder)]
struct Struct {
    field: String,
}

fn main() {
    let build = StructBuilder::builder()
        .field("value".into())
        .field("another value".into()) //this will mot compile
        .build();
}

This behaviour could be changed on a field by field basis.

use type_safe_builder_macro::Builder;

#[derive(Builder)]
struct Struct {
    #[builder(multi)]
    field: String,
}

fn main() {
    let build = StructBuilder::builder()
        .field("value".into())
        .field("value that will override the previous one".into())
        .build();
}

Allow field value to be set multiple times can be configured for all fields

If convenient this could be made the default behaviour for all the fields.

use type_safe_builder_macro::Builder;

#[derive(Builder)]
#[builder(multi)]
struct Struct {
    field: String,
    other_field: String,
}

fn main() {
    let build = StructBuilder::builder()
        .field("value for field".into())
        .field("value that will override the value of field".into())
        .other_field("value for other field".into())
        .other_field("value that will override the value of other_field".into())
        .build();
}

Allow field value to be set multiple times set at the struct level can be disabled for specific fields

If the possibility to assign a value to a field multiple times is made the default for a structure, individual fields could be configure so they could be assigned just once.

use type_safe_builder_macro::Builder;

#[derive(Builder)]
#[builder(multi)]
struct Struct {
    field: String,
    #[builder(single)]
    other_field: String,
}

fn main() {
    let build = StructBuilder::builder()
        .field("value for field".into())
        .field("value that will override the value of field".into())
        .other_field("this can't be overridden".into())
        .build(); // this will work
    
    let build = StructBuilder::builder()
        .field("value for field".into())
        .field("value that will override the value of field".into())
        .other_field("this can't be overridden".into())
        .other_field("trying to overrid the value".into()) // this will not compile
        .build();
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages