Skip to content

Instantly share code, notes, and snippets.

@nesteruk
Created July 24, 2017 12:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nesteruk/8b6e967affbd27e6c099f20be18d157a to your computer and use it in GitHub Desktop.
Save nesteruk/8b6e967affbd27e6c099f20be18d157a to your computer and use it in GitHub Desktop.
Lifetime chaos when defining faceted builders for a simple type
use std::marker::PhantomData;
struct Person
{
street_address: String,
postcode: String,
city: String,
company_name: String,
position: String,
annual_income: usize
}
impl<'z> ToString for Person
{
fn to_string(&self) -> String
{
format!("I live at {}, {}, {} and work as a {} at {} earning {}",
self.street_address, self.city, self.postcode,
self.company_name, self.position, self.annual_income)
}
}
struct PersonBuilder<'z>
{
person: &'z Person
}
impl<'z> PersonBuilder<'z>
{
fn new() -> PersonBuilder<'z>
{
PersonBuilder {
person: &Person {
street_address: String::new(),
postcode: String::new(),
city: String::new(),
company_name: String::new(),
position: String::new(),
annual_income: 0
}
}
}
}
trait Builder<'z>
{
fn lives(&self) -> PersonAddressBuilder<'z>;
fn works(&self) -> PersonJobBuilder<'z>;
}
macro_rules! impl_Builder
{
($T:ty, $L:tt) =>
{
impl<$L> Builder<$L> for $T
{
fn lives(&self) -> PersonAddressBuilder<$L>
{
PersonAddressBuilder::new(self.person)
}
fn works(&self) -> PersonJobBuilder<$L>
{
PersonJobBuilder::new(self.person)
}
}
//
// impl<$L> Into<Person<$L>> for $T
// {
// fn into(self) -> $T
// {
// self.person
// }
// }
}
}
struct PersonAddressBuilder<'z>
{
person: &'z Person
}
impl<'z> PersonAddressBuilder<'z>
{
fn new(person: &Person) -> PersonAddressBuilder<'z>
{
PersonAddressBuilder { person: person }
}
fn at(&self, street_address: &str) -> &PersonAddressBuilder<'z>
{
self.person.street_address = street_address.to_string();
self
}
fn with_postcode(&self, postcode: &str) -> &PersonAddressBuilder<'z>
{
self.person.postcode = postcode.to_string();
self
}
fn in_city(&self, city: &str) -> &PersonAddressBuilder
{
self.person.city = city.to_string();
self
}
}
struct PersonJobBuilder<'z>
{
person: &'z Person
}
impl<'z> PersonJobBuilder<'z>
{
fn new(person: &Person) -> PersonJobBuilder<'z>
{
PersonJobBuilder { person: person }
}
fn at(&self, company_name: &str) -> PersonJobBuilder<'z>
{
self.person.company_name = company_name.to_string();
self
}
fn as_a(&self, position: &str) -> PersonJobBuilder<'z>
{
self.person.position = position.to_string();
self
}
fn earning(&self, annual_income: usize) -> PersonJobBuilder<'z>
{
self.person.annual_income = annual_income;
self
}
}
impl_Builder!(PersonBuilder<'z>, 'z);
impl_Builder!(PersonJobBuilder<'z>, 'z);
impl_Builder!(PersonAddressBuilder<'z>, 'z);
fn main()
{
let pb = PersonBuilder::new();
let p = pb
.lives()
.at("123 London Road")
.in_city("London")
.with_postcode()
.works()
.at("Fabrikam")
.as_a("Developer")
.earning(123000);
println!("{}", p.to_string());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment