///|
pub fn quantity_text(quantity : Quantity) -> String {
quantity.amount.to_string() + " " + unit_text(quantity.unit)
}
///|
pub fn canonical_amount(quantity : Quantity) -> Int {
quantity.amount * canonical_factor(quantity.unit)
}
///|
pub fn same_measure_kind(left : Quantity, right : Quantity) -> Bool {
unit_kind(left.unit) == unit_kind(right.unit)
}
///|
pub fn convert_quantity(quantity : Quantity, unit : MeasureUnit) -> Quantity {
if unit_kind(quantity.unit) != unit_kind(unit) {
return Quantity(amount=quantity.amount, unit=quantity.unit)
}
let base = canonical_amount(quantity)
Quantity(amount=base / canonical_factor(unit), unit~)
}
///|
pub fn add_quantity(left : Quantity, right : Quantity) -> Quantity {
if !same_measure_kind(left, right) {
return left
}
let base = canonical_amount(left) + canonical_amount(right)
Quantity(amount=base / canonical_factor(left.unit), unit=left.unit)
}
///|
pub fn subtract_quantity(left : Quantity, right : Quantity) -> Quantity {
if !same_measure_kind(left, right) {
return left
}
let base = canonical_amount(left) - canonical_amount(right)
let safe = if base < 0 { 0 } else { base }
Quantity(amount=safe / canonical_factor(left.unit), unit=left.unit)
}
///|
pub fn quantity_missing(needed : Quantity, available : Quantity) -> Quantity {
if !same_measure_kind(needed, available) {
return needed
}
let missing = canonical_amount(needed) - canonical_amount(available)
if missing <= 0 {
Quantity(amount=0, unit=needed.unit)
} else {
Quantity(amount=missing / canonical_factor(needed.unit), unit=needed.unit)
}
}
///|
pub fn has_enough(available : Quantity, needed : Quantity) -> Bool {
same_measure_kind(available, needed) &&
canonical_amount(available) >= canonical_amount(needed)
}
///|
pub fn scale_quantity(
quantity : Quantity,
from_servings : Int,
to_servings : Int,
) -> Quantity {
if from_servings <= 0 {
return quantity
}
Quantity(
amount=quantity.amount * to_servings / from_servings,
unit=quantity.unit,
)
}
///|
pub fn scale_nutrition(
nutrition : Nutrition,
from_servings : Int,
to_servings : Int,
) -> Nutrition {
if from_servings <= 0 {
return nutrition
}
Nutrition(
kcal=nutrition.kcal * to_servings / from_servings,
protein_g=nutrition.protein_g * to_servings / from_servings,
fat_g=nutrition.fat_g * to_servings / from_servings,
carb_g=nutrition.carb_g * to_servings / from_servings,
fiber_g=nutrition.fiber_g * to_servings / from_servings,
sodium_mg=nutrition.sodium_mg * to_servings / from_servings,
)
}
///|
pub fn scale_ingredient(
ingredient : Ingredient,
from_servings : Int,
to_servings : Int,
) -> Ingredient {
let divisor = if from_servings <= 0 { 1 } else { from_servings }
Ingredient(
name=ingredient.name,
group=ingredient.group,
quantity=scale_quantity(ingredient.quantity, from_servings, to_servings),
nutrition=scale_nutrition(ingredient.nutrition, from_servings, to_servings),
cost_cents=ingredient.cost_cents * to_servings / divisor,
allergens=ingredient.allergens,
tags=ingredient.tags,
)
}
///|
pub fn scale_recipe(recipe : Recipe, servings : Int) -> Recipe {
let scaled = Array::new(capacity=recipe.ingredients.length())
for ingredient in recipe.ingredients {
scaled.push(scale_ingredient(ingredient, recipe.servings, servings))
}
Recipe(
title=recipe.title,
servings~,
ingredients=scaled,
steps=recipe.steps,
notes=recipe.notes,
)
}
///|
pub fn nutrition_add(left : Nutrition, right : Nutrition) -> Nutrition {
Nutrition(
kcal=left.kcal + right.kcal,
protein_g=left.protein_g + right.protein_g,
fat_g=left.fat_g + right.fat_g,
carb_g=left.carb_g + right.carb_g,
fiber_g=left.fiber_g + right.fiber_g,
sodium_mg=left.sodium_mg + right.sodium_mg,
)
}
///|
pub fn total_nutrition(recipe : Recipe) -> Nutrition {
let mut total = Nutrition()
for ingredient in recipe.ingredients {
total = nutrition_add(total, ingredient.nutrition)
}
total
}
///|
pub fn total_cost(recipe : Recipe) -> Int {
let mut total = 0
for ingredient in recipe.ingredients {
total += ingredient.cost_cents
}
total
}