Rust LogoReminder System

A Reminder System is a software application or a feature within an application designed to alert users about events, tasks, or appointments at a specified future time or interval. Its primary purpose is to help users manage their time, ensure they don't miss important deadlines, or forget specific actions. It acts as a digital assistant to keep track of commitments.

Key functionalities typically include:
* Scheduling: Users can define a future date and time for a reminder. This often supports various patterns like one-time reminders, or recurring reminders (daily, weekly, monthly, yearly).
* Storage: Reminders need to be stored persistently so they are not lost when the application closes. This usually involves databases (e.g., SQLite, PostgreSQL), file systems (e.g., JSON, YAML files), or in-memory structures for simpler or temporary systems.
* Monitoring/Scheduling Engine: A core component that continuously or periodically checks the stored reminders against the current time. When a reminder's designated time is reached or passed, it triggers the notification process.
* Notification: At the designated time, the system triggers an alert to the user. This can manifest in various forms: a pop-up window, an email, an SMS, an in-app notification, an audible sound, or a push notification to a mobile device.
* Management: Users should be able to interact with their reminders, typically by viewing a list of all reminders, editing their details (message, time), deleting them, or marking them as complete.

Core components often found in a Reminder System:
1. Reminder Data Structure: A way to represent a single reminder. Common attributes include a unique identifier (`id`), the reminder's content (`message`/`description`), the `due_time` or `schedule`, a `status` (e.g., pending, triggered, completed), and potentially a `recurrence_pattern` for repeating reminders.
2. Reminder Store: A mechanism to store and retrieve reminders. This could be a simple `Vec` or `HashMap` in memory for basic examples, or a more robust database connection in production systems.
3. Scheduler/Checker: A background process, thread, or task that routinely scans the reminder store to identify reminders whose `due_time` has arrived or passed.
4. Notification Handler: A component responsible for delivering the alert once a reminder is triggered. It abstracts the method of notification (e.g., printing to console, sending an email).
5. User Interface (UI) / Application Programming Interface (API): Provides the means for users or other applications to interact with the system (add new reminders, view existing ones, modify, or delete them).

Considerations for building a robust Reminder System include handling different time zones and daylight saving changes, ensuring data persistence and recovery, designing for scalability if many users or reminders are expected, and providing an effective yet unobtrusive user experience for notifications.

The example code provided below demonstrates a basic in-memory reminder system in Rust. It defines a `Reminder` struct, a `ReminderStore` to manage reminders, and uses a separate thread to periodically check for overdue reminders, triggering a console notification when they occur. Users can interact with it via a simple command-line interface.

Example Code

use std::collections::BTreeMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use std::thread;
use std::io::{self, Write};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct Reminder {
    id: u64,
    message: String,
    due_time: SystemTime,
    triggered: bool,
}

impl Reminder {
    fn new(id: u64, message: String, due_time: SystemTime) -> Self {
        Reminder {
            id,
            message,
            due_time,
            triggered: false,
        }
    }

    fn is_overdue(&self, current_time: SystemTime) -> bool {
        // A reminder is overdue if its due_time is less than or equal to current_time
        // and it has not been triggered yet.
        !self.triggered && self.due_time <= current_time
    }
}

// A simple in-memory reminder store using a BTreeMap to keep reminders sorted by time.
// It also keeps a separate map by ID for quick lookups.
struct ReminderStore {
    // BTreeMap to keep reminders sorted by due_time for efficient lookup of overdue items.
    // Key: due_time, Value: Vec<Reminder> (to handle multiple reminders with the same due_time).
    reminders_by_time: BTreeMap<SystemTime, Vec<Reminder>>,
    // Also maintain a mapping by ID for easy lookup, modification, or deletion.
    reminders_by_id: BTreeMap<u64, Reminder>,
    next_id: u64,
}

impl ReminderStore {
    fn new() -> Self {
        ReminderStore {
            reminders_by_time: BTreeMap::new(),
            reminders_by_id: BTreeMap::new(),
            next_id: 1,
        }
    }

    // Adds a new reminder to the store.
    fn add_reminder(&mut self, message: String, due_time: SystemTime) -> u64 {
        let id = self.next_id;
        self.next_id += 1;
        let reminder = Reminder::new(id, message, due_time);

        self.reminders_by_time
            .entry(due_time)
            .or_insert_with(Vec::new)
            .push(reminder.clone()); // Clone is necessary as BTreeMap takes ownership

        self.reminders_by_id.insert(id, reminder);
        id
    }

    // Checks for and marks overdue reminders, returning a list of triggered ones.
    fn get_overdue_reminders(&mut self, current_time: SystemTime) -> Vec<Reminder> {
        let mut overdue_list = Vec::new();

        // Iterate through reminders in chronological order using the BTreeMap.
        for (due_time, reminders) in &mut self.reminders_by_time {
            if *due_time > current_time {
                break; // All subsequent reminders are in the future, so we can stop.
            }

            for reminder_entry in reminders.iter_mut() {
                if reminder_entry.is_overdue(current_time) {
                    println!("[REMINDER TRIGGERED] ID: {}, Message: '{}' at {:?}",
                             reminder_entry.id, reminder_entry.message, reminder_entry.due_time);
                    reminder_entry.triggered = true;
                    // Update the triggered status in the reminders_by_id map as well
                    if let Some(r_by_id) = self.reminders_by_id.get_mut(&reminder_entry.id) {
                        r_by_id.triggered = true;
                    }
                    overdue_list.push(reminder_entry.clone());
                }
            }
        }
        overdue_list
    }

    // Displays all reminders currently in the store.
    fn display_all_reminders(&self) {
        println!("\n--- Current Reminders ---");
        if self.reminders_by_id.is_empty() {
            println!("No reminders set.");
            return;
        }
        for (id, reminder) in &self.reminders_by_id {
            println!("ID: {}, Message: '{}', Due: {:?} (Triggered: {})",
                     id, reminder.message, reminder.due_time, reminder.triggered);
        }
        println!("-------------------------\n");
    }
}

fn main() -> io::Result<()> {
    // Create a shared, mutable reminder store accessible from multiple threads.
    let reminder_store = Arc::new(Mutex::new(ReminderStore::new()));

    // Clone the Arc for the checker thread.
    let store_clone_for_checker = Arc::clone(&reminder_store);

    // Spawn a new thread to continuously check for overdue reminders.
    thread::spawn(move || {
        let mut last_check_time = SystemTime::now();
        loop {
            let current_time = SystemTime::now();
            // Only check if time has actually advanced (or if it's the first check)
            if current_time > last_check_time {
                let mut store = store_clone_for_checker.lock().unwrap(); // Acquire lock
                store.get_overdue_reminders(current_time); // Check and trigger reminders
                last_check_time = current_time; // Update last check time
            }
            // Pause briefly to avoid busy-waiting and consuming too much CPU.
            thread::sleep(Duration::from_millis(100));
        }
    });

    let mut input = String::new();
    loop {
        input.clear();
        print!("Enter command (add / list / exit): ");
        io::stdout().flush()?; // Ensure prompt is displayed before reading input
        io::stdin().read_line(&mut input)?;
        let command = input.trim().to_lowercase();

        match command.as_str() {
            "add" => {
                let mut message = String::new();
                print!("Enter reminder message: ");
                io::stdout().flush()?;
                io::stdin().read_line(&mut message)?;
                let message = message.trim().to_string();

                let mut delay_str = String::new();
                print!("Enter delay in seconds (e.g., 5 for 5 seconds): ");
                io::stdout().flush()?;
                io::stdin().read_line(&mut delay_str)?;
                let delay = delay_str.trim().parse::<u64>().unwrap_or(0);

                if delay > 0 {
                    let due_time = SystemTime::now() + Duration::from_secs(delay);
                    let id = reminder_store.lock().unwrap().add_reminder(message, due_time);
                    println!("Reminder added with ID: {}", id);
                } else {
                    println!("Invalid delay. Reminder not added.");
                }
            }
            "list" => {
                reminder_store.lock().unwrap().display_all_reminders();
            }
            "exit" => {
                println!("Exiting reminder system.");
                break; // Exit the main loop
            }
            _ => {
                println!("Unknown command. Please use 'add', 'list', or 'exit'.");
            }
        }
    }

    Ok(())
}