A Recipe Manager is a software application designed to help users organize, store, and access their collection of culinary recipes. Its primary purpose is to move away from physical recipe cards or scattered digital files, providing a centralized and structured way to manage cooking instructions and ingredients.
Key functionalities typically include:
* Recipe Creation/Addition: Users can input new recipes, specifying details like the recipe name, a list of ingredients (with quantities), step-by-step instructions, preparation time, cooking time, serving size, and often categories (e.g., "Breakfast," "Dinner," "Dessert").
* Viewing and Listing: The ability to display all stored recipes or view a specific recipe's full details.
* Searching and Filtering: Users should be able to find recipes based on various criteria, such as recipe name, key ingredients, category, or even dietary restrictions.
* Editing: Modifying existing recipes to correct errors, update ingredients, or refine instructions.
* Deletion: Removing recipes from the manager.
* Optional Advanced Features: Some recipe managers might offer ingredient scaling (adjusting quantities based on desired serving size), meal planning tools, automatic shopping list generation from selected recipes, or even integration with cooking timers.
The benefits of using a Recipe Manager include improved organization, easy access to recipes, the ability to discover new cooking ideas, and consistency in meal preparation. From a technical standpoint, implementing a Recipe Manager involves designing appropriate data structures to represent recipes, choosing a storage mechanism (in-memory, file-based, or database), and creating a user interface (command-line, graphical, or web-based) for interaction.
Example Code
use std::io::{self, Write}; // For input/output
use std::fmt; // For Display trait
// --- Data Structures ---
#[derive(Debug, Clone, PartialEq)]
enum RecipeCategory {
Appetizer,
MainCourse,
Dessert,
Breakfast,
Beverage,
Snack,
Other(String),
}
impl fmt::Display for RecipeCategory {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RecipeCategory::Appetizer => write!(f, "Appetizer"),
RecipeCategory::MainCourse => write!(f, "Main Course"),
RecipeCategory::Dessert => write!(f, "Dessert"),
RecipeCategory::Breakfast => write!(f, "Breakfast"),
RecipeCategory::Beverage => write!(f, "Beverage"),
RecipeCategory::Snack => write!(f, "Snack"),
RecipeCategory::Other(s) => write!(f, "Other: {}", s),
}
}
}
#[derive(Debug, Clone)]
struct Recipe {
name: String,
ingredients: Vec<String>,
instructions: Vec<String>,
prep_time_minutes: u32,
cook_time_minutes: u32,
category: RecipeCategory,
}
impl fmt::Display for Recipe {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "--- {} ---", self.name)?;
writeln!(f, "Category: {}", self.category)?;
writeln!(f, "Prep Time: {} min", self.prep_time_minutes)?;
writeln!(f, "Cook Time: {} min", self.cook_time_minutes)?;
writeln!(f, "\nIngredients:")?;
for ingredient in &self.ingredients {
writeln!(f, "- {}", ingredient)?;
}
writeln!(f, "\nInstructions:")?;
for (i, instruction) in self.instructions.iter().enumerate() {
writeln!(f, "{}. {}", i + 1, instruction)?;
}
Ok(())
}
}
// --- Recipe Manager ---
struct RecipeManager {
recipes: Vec<Recipe>,
}
impl RecipeManager {
fn new() -> Self {
RecipeManager { recipes: Vec::new() }
}
fn add_recipe(&mut self, recipe: Recipe) {
self.recipes.push(recipe);
println!("Recipe '{}' added successfully!", recipe.name);
}
fn list_recipes(&self) {
if self.recipes.is_empty() {
println!("No recipes in the manager yet.");
return;
}
println!("\n--- All Recipes ---");
for (i, recipe) in self.recipes.iter().enumerate() {
println!("{}. {}", i + 1, recipe.name);
}
println!("---------------------\n");
}
fn view_recipe_details(&self, recipe_name: &str) {
if let Some(recipe) = self.recipes.iter().find(|r| r.name.eq_ignore_ascii_case(recipe_name)) {
println!("\n{}", recipe);
} else {
println!("Recipe '{}' not found.", recipe_name);
}
}
fn search_by_name(&self, query: &str) -> Vec<&Recipe> {
self.recipes
.iter()
.filter(|r| r.name.to_lowercase().contains(&query.to_lowercase()))
.collect()
}
fn search_by_ingredient(&self, query: &str) -> Vec<&Recipe> {
self.recipes
.iter()
.filter(|r| {
r.ingredients
.iter()
.any(|i| i.to_lowercase().contains(&query.to_lowercase()))
})
.collect()
}
}
// --- CLI Helper Functions ---
fn read_input(prompt: &str) -> String {
print!("{}", prompt);
io::stdout().flush().expect("Failed to flush stdout");
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read line");
input.trim().to_string()
}
fn read_multiline_input(prompt: &str, stop_word: &str) -> Vec<String> {
println!("{}", prompt);
println!("(Enter '{}' on a new line to finish)", stop_word);
let mut lines = Vec::new();
loop {
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read line");
let trimmed = input.trim().to_string();
if trimmed.eq_ignore_ascii_case(stop_word) {
break;
}
if !trimmed.is_empty() {
lines.push(trimmed);
}
}
lines
}
fn parse_category(category_str: &str) -> RecipeCategory {
match category_str.to_lowercase().as_str() {
"appetizer" => RecipeCategory::Appetizer,
"main course" | "maincourse" => RecipeCategory::MainCourse,
"dessert" => RecipeCategory::Dessert,
"breakfast" => RecipeCategory::Breakfast,
"beverage" => RecipeCategory::Beverage,
"snack" => RecipeCategory::Snack,
_ => RecipeCategory::Other(category_str.to_string()),
}
}
// --- Main Application Logic ---
fn main() {
let mut manager = RecipeManager::new();
println!("Welcome to the Rust Recipe Manager!");
loop {
println!("\n--- Menu ---");
println!("1. Add New Recipe");
println!("2. List All Recipes");
println!("3. View Recipe Details");
println!("4. Search by Name");
println!("5. Search by Ingredient");
println!("6. Exit");
print!("Enter your choice: ");
io::stdout().flush().expect("Failed to flush stdout");
let mut choice = String::new();
io::stdin().read_line(&mut choice).expect("Failed to read line");
let choice = choice.trim();
match choice {
"1" => {
let name = read_input("Enter recipe name: ");
let ingredients = read_multiline_input("Enter ingredients (one per line, type 'done' to finish):", "done");
let instructions = read_multiline_input("Enter instructions (one per line, type 'done' to finish):", "done");
let prep_time_str = read_input("Enter preparation time in minutes: ");
let prep_time_minutes: u32 = match prep_time_str.parse() {
Ok(num) => num,
Err(_) => {
println!("Invalid input for preparation time. Using 0 minutes.");
0
}
};
let cook_time_str = read_input("Enter cooking time in minutes: ");
let cook_time_minutes: u32 = match cook_time_str.parse() {
Ok(num) => num,
Err(_) => {
println!("Invalid input for cooking time. Using 0 minutes.");
0
}
};
let category_str = read_input("Enter category (e.g., Main Course, Dessert, or custom): ");
let category = parse_category(&category_str);
if name.is_empty() || ingredients.is_empty() || instructions.is_empty() {
println!("Recipe name, ingredients, and instructions cannot be empty. Recipe not added.");
continue;
}
let new_recipe = Recipe {
name,
ingredients,
instructions,
prep_time_minutes,
cook_time_minutes,
category,
};
manager.add_recipe(new_recipe);
}
"2" => manager.list_recipes(),
"3" => {
let name_to_view = read_input("Enter the name of the recipe to view: ");
manager.view_recipe_details(&name_to_view);
}
"4" => {
let query = read_input("Enter name to search: ");
let results = manager.search_by_name(&query);
if results.is_empty() {
println!("No recipes found matching '{}'.", query);
} else {
println!("\n--- Search Results (by Name) ---");
for recipe in results {
println!("{}", recipe.name);
}
println!("-------------------------------\n");
}
}
"5" => {
let query = read_input("Enter ingredient to search: ");
let results = manager.search_by_ingredient(&query);
if results.is_empty() {
println!("No recipes found with ingredient '{}'.", query);
} else {
println!("\n--- Search Results (by Ingredient) ---");
for recipe in results {
println!("{}", recipe.name);
}
println!("------------------------------------\n");
}
}
"6" => {
println!("Exiting Recipe Manager. Goodbye!");
break;
}
_ => println!("Invalid choice. Please try again."),
}
}
}








Recipe Manager