Scenario
Imagine you're a baker. You bake different cakes using different recipes.
Goal
You're trying to plan how many ingredients you'll need over the next 6m using your upcoming list of orders.
The challenge is, your orders aren't certain. They're based on a probability.
Problem
I've started hallo – a library to run these kind of simulations. I'm stuck on how to implement the ergonomics of the API I've imagined. Here's what I have in mind:
struct Sugar(f32);
struct Chocolate(f32);
struct Vanilla(f32);
let brownieRecipe = RecipeBuilder::default()
.add(Sugar(200.0))
.add(Chocolate(10.0))
.build();
let vanillaSponge = RecipeBuilder::default()
.add(Sugar(300.0))
.add(Vanilla(2.0))
.build();
let p1 = AllocationBuilder::default()
.recipe(brownieRecipe)
.duration_weeks(5)
.start_date(&(today Duration::weeks(8)))
.build();
let p2 = AllocationBuilder::default()
.recipe(vanillaSponge)
.duration_weeks(2)
.start_date(&(today Duration::weeks(2)))
.build();
The RecipeBuilder
builds a recipe from any number of ingredients. The AllocationBuilder
takes a recipe and plans when it's needed.
The next step is to implement a simulation engine to plot 10k outcomes (but that's out of scope of this question).
The ingredient structs might eventually implement some trait so that they can be summed (std::Add
?).
CodePudding user response:
You'll need to have some trait for using the ingredients. What trait - that depends on what you need to do with them. It can be a builtin trait or a custom trait, but it is important that all ingredients (Sugar
, Chocolate
etc.) will implement it (I'd go with a custom trait).
Assuming you have a trait Ingredient
, store a list of Vec<Box<dyn Ingredient>>
. For the API to be what you described, you need the add()
method to be defined like:
pub fn add<I: Ingredient>(&mut self, ingredient: I) {
self.ingredients.push(Box::new(ingredient));
}
This is a convenience method: instead of needing to pass Box<dyn Ingredient>
, you pass impl Ingredient
and the method creates the Box<dyn Ingredient>
. This is a very common pattern in Rust.
CodePudding user response:
Combining details from @chayim-friedman and @blackbeans, we've got it!
pub fn add<I: Ingredient>(&mut self, ingredient: I) -> Self {
self.ingredients.push(Box::new(ingredient));
self
}