-
Notifications
You must be signed in to change notification settings - Fork 15
Week 2 day 3 #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Week 2 day 3 #7
Changes from 4 commits
a4a6319
ad4803b
670e60b
3dd245f
4b78e21
ab3e200
3805672
fee035c
aba54cb
3aae61b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /target |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| [package] | ||
| name = "Stephen-Ngozi-User-Input" | ||
| version = "0.1.0" | ||
| edition = "2024" | ||
|
|
||
| [dependencies] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
|
|
||
| use std::io; | ||
| enum PowerStatus { | ||
| Off, | ||
| Sleep, | ||
| Reboot, | ||
| Shutdown, | ||
| Hibernate, | ||
| } | ||
|
|
||
| fn format_power_status(input: &str) -> Option<PowerStatus> { | ||
| match input.to_lowercase().as_str() { | ||
| "off" => Some(PowerStatus::Off), | ||
| "sleep" => Some(PowerStatus::Sleep), | ||
| "reboot" => Some(PowerStatus::Reboot), | ||
| "shutdown" => Some(PowerStatus::Shutdown), | ||
| "hibernate" => Some(PowerStatus::Hibernate), | ||
| _ => None, | ||
| } | ||
| } | ||
|
|
||
|
|
||
| fn handle_power_status(status: PowerStatus) { | ||
| match status { | ||
| PowerStatus::Off => println!("Turning off the computer"), | ||
| PowerStatus::Sleep => println!("Putting the computer to sleep"), | ||
| PowerStatus::Reboot => println!("Rebooting the computer"), | ||
| PowerStatus::Shutdown => println!("Shutting down the computer"), | ||
| PowerStatus::Hibernate => println!("Hibernating the computer"), | ||
| } | ||
| } | ||
|
|
||
|
|
||
|
|
||
| fn main() { | ||
| println!("Enter power option (off, sleep, reboot, shutdown, hibernate):"); | ||
|
|
||
| let mut input = String::new(); | ||
| io::stdin() | ||
| .read_line(&mut input) | ||
| .expect("Failed to read input"); | ||
|
|
||
| let input = input.trim(); | ||
|
|
||
| match format_power_status(input) { | ||
| Some(status) => handle_power_status(status), | ||
| None => println!("Error: Invalid power option"), | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /target |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,6 @@ | ||||||
| [package] | ||||||
| name = "Stephen-Ngozi-Merkle-Tree" | ||||||
|
||||||
| name = "Stephen-Ngozi-Merkle-Tree" | |
| name = "stephen-ngozi-merkle-tree" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
|
|
||
|
|
||
| #[derive(Debug, Clone)] | ||
| pub enum TransactionType { | ||
| Credit, | ||
| Debit, | ||
| } | ||
|
|
||
|
|
||
|
|
||
| #[derive(Debug, Clone)] | ||
| pub struct Expense { | ||
| pub id: u8, | ||
| pub name: String, | ||
| pub amount: f64, | ||
| pub tx_type: TransactionType, | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,141 @@ | ||||||||||||||||||||||||||||||||
| mod expense; | ||||||||||||||||||||||||||||||||
| mod tracker; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+3
|
||||||||||||||||||||||||||||||||
| use std::io; | ||||||||||||||||||||||||||||||||
| use expense::TransactionType; | ||||||||||||||||||||||||||||||||
| use tracker::ExpenseTracker; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| fn print_menu() { | ||||||||||||||||||||||||||||||||
| println!("\n=== Expense Tracker ==="); | ||||||||||||||||||||||||||||||||
| println!("1 - Add Expense"); | ||||||||||||||||||||||||||||||||
| println!("2 - View Expenses"); | ||||||||||||||||||||||||||||||||
| println!("3 - Update Expense"); | ||||||||||||||||||||||||||||||||
| println!("4 - Delete Expense"); | ||||||||||||||||||||||||||||||||
| println!("q - Quit"); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| fn main() { | ||||||||||||||||||||||||||||||||
| // println!("Hello, world!"); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| let mut tracker = ExpenseTracker::new(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| loop { | ||||||||||||||||||||||||||||||||
| print_menu(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| let mut input = String::new(); | ||||||||||||||||||||||||||||||||
| io::stdin().read_line(&mut input).expect("Failed"); | ||||||||||||||||||||||||||||||||
| let input = input.trim(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if input == "q" { | ||||||||||||||||||||||||||||||||
| println!("Are you sure you want to quit? (y/n)"); | ||||||||||||||||||||||||||||||||
| let mut confirm = String::new(); | ||||||||||||||||||||||||||||||||
| io::stdin().read_line(&mut confirm).expect("Failed "); | ||||||||||||||||||||||||||||||||
| let confirm = confirm.trim(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if confirm == "y" { | ||||||||||||||||||||||||||||||||
| tracker.save_to_file("stephen_expences.txt"); | ||||||||||||||||||||||||||||||||
| println!("Data saved to stephen_expences.txt"); | ||||||||||||||||||||||||||||||||
|
Comment on lines
+39
to
+40
|
||||||||||||||||||||||||||||||||
| tracker.save_to_file("stephen_expences.txt"); | |
| println!("Data saved to stephen_expences.txt"); | |
| tracker.save_to_file("stephen_expenses.txt"); | |
| println!("Data saved to stephen_expenses.txt"); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User input parsing uses .parse().expect(...) (e.g., for amount/ID), which will terminate the program on invalid input. For an interactive CLI, consider looping until valid input is provided (or handling the Err case with a friendly message and retry).
| println!("Enter amount:"); | |
| let mut amount_input = String::new(); | |
| io::stdin().read_line(&mut amount_input).expect("Failed to read input"); | |
| let amount: f64 = amount_input.trim().parse().expect("Please enter a valid number"); | |
| let amount: f64 = loop { | |
| println!("Enter amount:"); | |
| let mut amount_input = String::new(); | |
| io::stdin().read_line(&mut amount_input).expect("Failed to read input"); | |
| match amount_input.trim().parse::<f64>() { | |
| Ok(value) => break value, | |
| Err(_) => { | |
| println!("Invalid amount. Please enter a valid number (e.g., 123.45)."); | |
| } | |
| } | |
| }; |
Ngozistephen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Outdated
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This prints amount with $ here, but other flows (view/update) print Naria... for the amount. Pick one currency/format and keep it consistent across commands.
| println!("ID: {}, Name: {}, Amount: ${:.2}, Type: {:?}", | |
| println!("ID: {}, Name: {}, Amount: Naria{:.2}, Type: {:?}", |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This prints amount with Naria..., but the add flow prints $.... Pick one currency/format and keep it consistent across commands.
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in currency label: Naria should be Naira (if referring to Nigerian Naira).
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in prompt: Expence should be Expense.
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in success message: Successfu should be Successful.
| println!("Expense Updated Successfu"); | |
| println!("Expense Updated Successful"); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If tracker.update(...) returns false (ID not found), nothing is printed, so the user gets no feedback. Add an else branch to print a “not found” message.
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After tracker.update(...) succeeds, the follow-up tracker.values.get(&id) should always return Some, making the else branch effectively unreachable. Consider having update return the updated expense (or Option<&Expense>) to avoid a second lookup and dead code.
| }else { | |
| println!("Expense with ID {} not found!", id); | |
| } | |
| } | |
| } else { | |
| println!("Expense with ID {} not found!", id); |
Ngozistephen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| use std::{collections::HashMap,fs::File,io::Write}; | ||
| use crate::expense::{Expense, TransactionType}; | ||
|
|
||
|
|
||
| // Expense tracker | ||
| // Add the expenses | ||
| // Remove | ||
| // Update | ||
| // View | ||
|
|
||
| // Hashmaps | ||
| // structs | ||
| // enums | ||
| // Hashmaps | ||
|
|
||
|
|
||
|
|
||
|
|
||
| pub struct ExpenseTracker { | ||
| pub values: HashMap<u8, Expense>, | ||
| pub next_id: u8, | ||
| } | ||
|
Comment on lines
+19
to
+22
|
||
|
|
||
| impl ExpenseTracker { | ||
| pub fn new() -> Self { | ||
| Self { | ||
| values: HashMap::new(), | ||
| next_id: 1, | ||
| } | ||
| } | ||
|
|
||
| pub fn add(&mut self, name: String, amount: f64, tx_type: TransactionType) -> Expense { | ||
| let current_id = self.next_id; | ||
| let new_expense = Expense { | ||
| id: current_id, | ||
| name, | ||
| amount, | ||
| tx_type, | ||
| }; | ||
| self.values.insert(current_id, new_expense.clone()); | ||
| self.next_id += 1; | ||
| new_expense | ||
| } | ||
|
|
||
| pub fn view_all(&self) -> Vec<&Expense> { | ||
| let mut expenses: Vec<&Expense> = self.values.values().collect(); | ||
|
|
||
| expenses.sort_by(|a, b|{a.id.cmp(&b.id)}); | ||
| expenses | ||
|
|
||
| } | ||
|
|
||
| pub fn update(&mut self, id: u8, amount: f64, tx_type: TransactionType) -> bool { | ||
| match self.values.get_mut(&id) { | ||
| Some(exp) => { | ||
| exp.amount = amount; | ||
| exp.tx_type = tx_type; | ||
| true | ||
| } | ||
| None => false, | ||
| } | ||
| // let updated_expense = Expense { | ||
| // id, | ||
| // amount, | ||
| // tx_type, | ||
| // }; | ||
| // self.values.put(id) | ||
| } | ||
|
|
||
| pub fn delete(&mut self, id: u8) -> bool { | ||
| self.values.remove(&id).is_some() | ||
| } | ||
|
|
||
|
|
||
| pub fn save_to_file(&self, filename: &str) { | ||
| let mut file = File::create(filename).expect("Could not create file"); | ||
|
|
||
| for expense in self.values.values() { | ||
| let line = format!("ID: {}, Name: {}, Amount: {:.2}, Type: {:?}\n", | ||
| expense.id, expense.name, expense.amount, expense.tx_type); | ||
| file.write_all(line.as_bytes()).expect("Could not write to file"); | ||
| } | ||
|
Comment on lines
+78
to
+82
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| ID: 2, Name: Beans, Amount: 5000.00, Type: Credit | ||
| ID: 1, Name: Rice, Amount: 20000.00, Type: Credit | ||
|
Comment on lines
+1
to
+2
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cargo package names with uppercase letters (e.g.,
Stephen-Ngozi-User-Input) can produce warnings and are not accepted on crates.io. Consider using a lowercase, kebab-case name (e.g.,stephen-ngozi-user-input).