Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

using

Crates.io Version docs.rs Crates.io License

The using macro allows simplified implementation and usage of the builder pattern without having to return &mut Self or Self from the builder methods:

let vec3 = using!(Vec3Builder::default() => {
    .x(4.27);
    .y(9.71);
    .z(13.37);
    .build()
});

#[derive(Default, Debug, Copy, Clone)]
struct Vec3Builder {
    x: Option<f32>,
    y: Option<f32>,
    z: Option<f32>,
}

impl Vec3Builder {
    pub fn x(&mut self, x: f32) {
        self.x = Some(x);
    }

    pub fn y(&mut self, y: f32) {
        self.y = Some(y);
    }

    pub fn z(&mut self, z: f32) {
        self.z = Some(z);
    }

    //this also works with `self` instead of `&mut self`
    pub fn build(&mut self) -> Vec3 {
        Vec3 {
            x: self.x.unwrap(),
            y: self.y.unwrap(),
            z: self.z.unwrap(),
        }
    }
}

#[derive(Debug, Copy, Clone)]
struct Vec3 {
    x: f32,
    y: f32,
    z: f32,
}

The using macro allows calling multiple methods on the same object, which is also known as method cascading. In the example above, the following code is generated:

let vec3 = {
    let mut target = Vec3Builder::default();
    target.x(4.27);
    target.y(9.71);
    target.z(13.37);
    target.build()
};

This allows more flexibility for implementing and using builders and also makes more complicated use-cases more ergonomic:

// "Conventional" builder with method chaining:

let mut builder = SomeBuilder::new()
    .x(...)
    .y(...);
if some_condition {
    builder.z(...);
}
if some_other_condition {
    some_function(&mut builder);
}
let thing = builder.build();



// Using Builder with `using`:

let thing = using!(builder @ SomeBuilder::new() => {
    .x(...);
    .y(...);
    if some_condition {
        .z(...);
    }
    if some_other_condition {
        some_function(&mut builder);
    }
    .build()
});

Although using was primarily designed for the builder pattern, it is not limited to that as it can be used on basically every type:

let hello_world = using!(Vec::new() => {
    .push("Hello");
    .push("World!");
    .join(", ")
});
assert_eq!(hello_world, "Hello, World!");

About

A Rust macro for simpler builders with method cascading

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages