use std::collections::BinaryHeap;
use std::collections::HashMap;
use crate::types::AgentId;
#[derive(Debug)]
pub struct PriorityQueue<T> {
heap: BinaryHeap<T>,
index: HashMap<AgentId, usize>,
}
impl<T> PriorityQueue<T>
where
T: Ord + Clone,
T: HasAgentId,
{
pub fn new() -> Self {
Self {
heap: BinaryHeap::new(),
index: HashMap::new(),
}
}
pub fn push(&mut self, item: T) {
let agent_id = item.agent_id();
self.index.insert(agent_id, self.heap.len());
self.heap.push(item);
}
pub fn pop(&mut self) -> Option<T> {
if let Some(item) = self.heap.pop() {
let agent_id = item.agent_id();
self.index.remove(&agent_id);
self.rebuild_index();
Some(item)
} else {
None
}
}
pub fn remove(&mut self, agent_id: &AgentId) -> Option<T> {
if self.index.remove(agent_id).is_some() {
let mut items: Vec<T> = self.heap.drain().collect();
let mut removed_item = None;
items.retain(|item| {
if &item.agent_id() == agent_id {
removed_item = Some(item.clone());
false
} else {
true
}
});
self.heap = items.into_iter().collect();
self.rebuild_index();
removed_item
} else {
None
}
}
pub fn contains(&self, agent_id: &AgentId) -> bool {
self.index.contains_key(agent_id)
}
pub fn find(&self, agent_id: &AgentId) -> Option<&T> {
if self.index.contains_key(agent_id) {
self.heap.iter().find(|item| &item.agent_id() == agent_id)
} else {
None
}
}
pub fn len(&self) -> usize {
self.heap.len()
}
pub fn is_empty(&self) -> bool {
self.heap.is_empty()
}
pub fn peek(&self) -> Option<&T> {
self.heap.peek()
}
fn rebuild_index(&mut self) {
self.index.clear();
for (idx, item) in self.heap.iter().enumerate() {
self.index.insert(item.agent_id(), idx);
}
}
pub fn clear(&mut self) {
self.heap.clear();
self.index.clear();
}
pub fn to_vec(&self) -> Vec<T> {
self.heap.iter().cloned().collect()
}
}
impl<T> Default for PriorityQueue<T>
where
T: Ord + Clone + HasAgentId,
{
fn default() -> Self {
Self::new()
}
}
pub trait HasAgentId {
fn agent_id(&self) -> AgentId;
}
impl HasAgentId for super::ScheduledTask {
fn agent_id(&self) -> AgentId {
self.agent_id
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::scheduler::ScheduledTask;
use crate::types::{
AgentConfig, AgentId, ExecutionMode, Priority, ResourceLimits, SecurityTier,
};
use std::collections::HashMap;
fn create_test_task(priority: Priority) -> ScheduledTask {
let agent_id = AgentId::new();
let config = AgentConfig {
id: agent_id,
name: "test".to_string(),
dsl_source: "test".to_string(),
execution_mode: ExecutionMode::Ephemeral,
security_tier: SecurityTier::Tier1,
resource_limits: ResourceLimits::default(),
capabilities: vec![],
policies: vec![],
metadata: HashMap::new(),
priority,
};
ScheduledTask::new(config)
}
#[test]
fn test_priority_queue_ordering() {
let mut queue = PriorityQueue::new();
let low_task = create_test_task(Priority::Low);
let high_task = create_test_task(Priority::High);
let normal_task = create_test_task(Priority::Normal);
queue.push(low_task.clone());
queue.push(high_task.clone());
queue.push(normal_task.clone());
assert_eq!(queue.pop().unwrap().priority, Priority::High);
assert_eq!(queue.pop().unwrap().priority, Priority::Normal);
assert_eq!(queue.pop().unwrap().priority, Priority::Low);
}
#[test]
fn test_priority_queue_remove() {
let mut queue = PriorityQueue::new();
let task1 = create_test_task(Priority::High);
let task2 = create_test_task(Priority::Normal);
let task3 = create_test_task(Priority::Low);
let agent_id2 = task2.agent_id;
queue.push(task1);
queue.push(task2);
queue.push(task3);
assert_eq!(queue.len(), 3);
assert!(queue.contains(&agent_id2));
let removed = queue.remove(&agent_id2);
assert!(removed.is_some());
assert_eq!(removed.unwrap().agent_id, agent_id2);
assert_eq!(queue.len(), 2);
assert!(!queue.contains(&agent_id2));
}
}