Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
7 changes: 7 additions & 0 deletions submissions/week-2/day-3/Stephen-Ngozi-User-Input/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions submissions/week-2/day-3/Stephen-Ngozi-User-Input/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "Stephen-Ngozi-User-Input"
Copy link

Copilot AI Feb 9, 2026

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).

Suggested change
name = "Stephen-Ngozi-User-Input"
name = "stephen-ngozi-user-input"

Copilot uses AI. Check for mistakes.
version = "0.1.0"
edition = "2024"

[dependencies]
50 changes: 50 additions & 0 deletions submissions/week-2/day-3/Stephen-Ngozi-User-Input/src/main.rs
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
7 changes: 7 additions & 0 deletions submissions/week-2/day-5/Stephen-Ngozi-Merkle-Tree/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions submissions/week-2/day-5/Stephen-Ngozi-Merkle-Tree/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "Stephen-Ngozi-Merkle-Tree"
Copy link

Copilot AI Feb 9, 2026

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-Merkle-Tree) can produce warnings and are not accepted on crates.io. Consider using a lowercase, kebab-case name (e.g., stephen-ngozi-merkle-tree).

Suggested change
name = "Stephen-Ngozi-Merkle-Tree"
name = "stephen-ngozi-merkle-tree"

Copilot uses AI. Check for mistakes.
version = "0.1.0"
edition = "2024"

[dependencies]
17 changes: 17 additions & 0 deletions submissions/week-2/day-5/Stephen-Ngozi-Merkle-Tree/src/expense.rs
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,
}
141 changes: 141 additions & 0 deletions submissions/week-2/day-5/Stephen-Ngozi-Merkle-Tree/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
mod expense;
mod tracker;

Comment on lines +1 to +3
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR metadata/title is for “Week 2 Day 3”, but this PR also adds a full Day 5 submission under submissions/week-2/day-5/.... If Day 5 work is intended, update the PR title/description; otherwise split into separate PRs.

Copilot uses AI. Check for mistakes.
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
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file name stephen_expences.txt appears to be a misspelling of “expenses”. Renaming it (and updating the save path/message) will make it easier to understand and search for.

Suggested change
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 uses AI. Check for mistakes.
println!("Bye bye go home!");
break;
}
}else if input == "1" {
println!("Enter expense name:");
let mut name = String::new();
io::stdin().read_line(&mut name).expect("Failed to read input");
let name = name.trim().to_string();

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");
Comment on lines +50 to +53
Copy link

Copilot AI Feb 9, 2026

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).

Suggested change
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).");
}
}
};

Copilot uses AI. Check for mistakes.

println!("Is this Credit or Debit? (c/d):");
let mut tx_input = String::new();
io::stdin().read_line(&mut tx_input).expect("Failed to read input");
let tx_input = tx_input.trim();

let tx_type = if tx_input == "c" {
TransactionType::Credit
} else {
TransactionType::Debit
};

let new_expense = tracker.add(name, amount, tx_type);
println!(" Expense added successfully!");
println!("ID: {}, Name: {}, Amount: ${:.2}, Type: {:?}",
Copy link

Copilot AI Feb 9, 2026

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.

Suggested change
println!("ID: {}, Name: {}, Amount: ${:.2}, Type: {:?}",
println!("ID: {}, Name: {}, Amount: Naria{:.2}, Type: {:?}",

Copilot uses AI. Check for mistakes.
new_expense.id, new_expense.name, new_expense.amount, new_expense.tx_type);
}else if input == "2" {
let expenses = tracker.view_all();

if expenses.is_empty() {
println!("No Expenses in the Tracker");
} else {
println!("All Expenses");
for expense in expenses {
println!("ID: {} | Name: {} | Amount: Naria{:.2} | Type: {:?}",
expense.id, expense.name, expense.amount, expense.tx_type);
}
Comment on lines +80 to +84
Copy link

Copilot AI Feb 9, 2026

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 uses AI. Check for mistakes.
Comment on lines +82 to +84
Copy link

Copilot AI Feb 9, 2026

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 uses AI. Check for mistakes.
}
} else if input == "3" {
println!("Enter the ID of the Expence");

Comment on lines +87 to +88
Copy link

Copilot AI Feb 9, 2026

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 uses AI. Check for mistakes.
let mut new_id_input = String::new();

io::stdin().read_line(&mut new_id_input).expect("Failed to read input");
let id: u8 = new_id_input.trim().parse().expect("Please enter a valid ID");



println!("Enter new 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");

println!("Is this Credit or Debit? (c/d):");
let mut tx_input = String::new();
io::stdin().read_line(&mut tx_input).expect("Failed to read input");
let tx_input = tx_input.trim();

let tx_type = if tx_input == "c" {
TransactionType::Credit
} else {
TransactionType::Debit
};

if tracker.update(id, amount, tx_type){
println!("Expense Updated Successfu");
Copy link

Copilot AI Feb 9, 2026

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.

Suggested change
println!("Expense Updated Successfu");
println!("Expense Updated Successful");

Copilot uses AI. Check for mistakes.

Comment on lines +112 to +114
Copy link

Copilot AI Feb 9, 2026

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 uses AI. Check for mistakes.
if let Some(expense) = tracker.values.get(&id) {
println!("ID: {}, Name: {}, Amount: Naria{:.2}, Type: {:?}",
expense.id, expense.name, expense.amount, expense.tx_type);
}else {
println!("Expense with ID {} not found!", id);

}
Comment on lines +118 to +121
Copy link

Copilot AI Feb 9, 2026

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.

Suggested change
}else {
println!("Expense with ID {} not found!", id);
}
}
} else {
println!("Expense with ID {} not found!", id);

Copilot uses AI. Check for mistakes.
}
}else if input == "4" {
println!("Enter the ID of the expense you to delete:");

let mut id_input = String::new();

io::stdin().read_line(&mut id_input).expect("Failed to read input");
let id: u8 = id_input.trim().parse().expect("Please enter a valid ID");

if tracker.delete(id){
println!(" Your Expence is Deleted ");
}else {
println!("Expense with ID {} not found!", id);
}
}else {
println!("Invalid choice. Please try again.");
}




}

}
84 changes: 84 additions & 0 deletions submissions/week-2/day-5/Stephen-Ngozi-Merkle-Tree/src/tracker.rs
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
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExpenseTracker exposes its internal state via pub values and pub next_id, and main.rs reaches into tracker.values directly. This makes it easy to break invariants (e.g., changing next_id) and couples callers to the internal storage. Prefer making fields private and adding methods like get(id), iter()/list() or returning the updated expense from update().

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +22
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using u8 for values keys / next_id means IDs will overflow after 255 inserts (next_id += 1 wraps in release), which can lead to duplicate IDs and overwriting existing expenses. Consider u64/usize (and/or handling overflow explicitly).

Copilot uses AI. Check for mistakes.

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
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

save_to_file iterates over HashMap::values(), which is intentionally non-deterministic; the saved file order may change between runs. If you want stable output, write expenses in a sorted order (e.g., reuse view_all() or sort keys before writing).

Copilot uses AI. Check for mistakes.
}
}
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
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stephen_expences.txt looks like a runtime-generated output file (it’s created by save_to_file). Committing generated state makes future PRs noisy and can lead to merge conflicts; consider removing it from the submission and/or adding it to .gitignore (or writing under target//a dedicated data/ directory that is ignored).

Copilot uses AI. Check for mistakes.
Loading