agentic_robotics_rt/
scheduler.rs

1//! Priority-based task scheduler
2
3use crate::RTPriority;
4use std::collections::BinaryHeap;
5use std::cmp::Ordering;
6use std::time::{Duration, Instant};
7
8/// Scheduled task
9#[derive(Debug)]
10pub struct ScheduledTask {
11    pub priority: RTPriority,
12    pub deadline: Instant,
13    pub task_id: u64,
14}
15
16impl PartialEq for ScheduledTask {
17    fn eq(&self, other: &Self) -> bool {
18        self.priority == other.priority && self.deadline == other.deadline
19    }
20}
21
22impl Eq for ScheduledTask {}
23
24impl PartialOrd for ScheduledTask {
25    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
26        Some(self.cmp(other))
27    }
28}
29
30impl Ord for ScheduledTask {
31    fn cmp(&self, other: &Self) -> Ordering {
32        // Higher priority first, then earlier deadline
33        match self.priority.cmp(&other.priority) {
34            Ordering::Equal => other.deadline.cmp(&self.deadline),
35            ordering => ordering,
36        }
37    }
38}
39
40/// Priority scheduler
41pub struct PriorityScheduler {
42    queue: BinaryHeap<ScheduledTask>,
43    next_task_id: u64,
44}
45
46impl PriorityScheduler {
47    /// Create a new scheduler
48    pub fn new() -> Self {
49        Self {
50            queue: BinaryHeap::new(),
51            next_task_id: 0,
52        }
53    }
54
55    /// Schedule a task
56    pub fn schedule(&mut self, priority: RTPriority, deadline: Duration) -> u64 {
57        let task_id = self.next_task_id;
58        self.next_task_id += 1;
59
60        let task = ScheduledTask {
61            priority,
62            deadline: Instant::now() + deadline,
63            task_id,
64        };
65
66        self.queue.push(task);
67        task_id
68    }
69
70    /// Get the next task to execute
71    pub fn next_task(&mut self) -> Option<ScheduledTask> {
72        self.queue.pop()
73    }
74
75    /// Get the number of pending tasks
76    pub fn pending_tasks(&self) -> usize {
77        self.queue.len()
78    }
79
80    /// Clear all tasks
81    pub fn clear(&mut self) {
82        self.queue.clear();
83    }
84}
85
86impl Default for PriorityScheduler {
87    fn default() -> Self {
88        Self::new()
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn test_scheduler() {
98        let mut scheduler = PriorityScheduler::new();
99
100        // Schedule tasks with different priorities
101        scheduler.schedule(RTPriority::Low, Duration::from_millis(100));
102        scheduler.schedule(RTPriority::High, Duration::from_millis(100));
103        scheduler.schedule(RTPriority::Critical, Duration::from_millis(100));
104
105        assert_eq!(scheduler.pending_tasks(), 3);
106
107        // Should get critical first
108        let task1 = scheduler.next_task().unwrap();
109        assert_eq!(task1.priority, RTPriority::Critical);
110
111        // Then high
112        let task2 = scheduler.next_task().unwrap();
113        assert_eq!(task2.priority, RTPriority::High);
114
115        // Then low
116        let task3 = scheduler.next_task().unwrap();
117        assert_eq!(task3.priority, RTPriority::Low);
118
119        assert_eq!(scheduler.pending_tasks(), 0);
120    }
121}