use serde_json::Value;
use std::collections::VecDeque;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TodoPriority {
Low,
Normal,
High,
Critical,
}
#[derive(Debug, Clone)]
pub struct TodoItem {
pub module: String,
pub action: String,
pub data: Value,
pub priority: TodoPriority,
pub response_channel: Option<Sender<TodoResponse>>,
}
#[derive(Debug, Clone)]
pub struct TodoResponse {
pub success: bool,
pub data: Option<Value>,
pub error: Option<String>,
}
#[derive(Clone)]
pub struct ModuleTodoQueue {
queues: Arc<Mutex<std::collections::HashMap<String, VecDeque<TodoItem>>>>,
}
impl ModuleTodoQueue {
pub fn new() -> Self {
Self {
queues: Arc::new(Mutex::new(std::collections::HashMap::new())),
}
}
pub fn add_todo(&self, todo: TodoItem) {
let mut queues = self.queues.lock().unwrap();
let module_queue = queues.entry(todo.module.clone()).or_default();
let position = module_queue
.iter()
.position(|item| item.priority < todo.priority);
match position {
Some(pos) => module_queue.insert(pos, todo),
None => module_queue.push_back(todo),
}
}
pub fn get_todo(&self, module: &str) -> Option<TodoItem> {
let mut queues = self.queues.lock().unwrap();
queues.get_mut(module).and_then(|queue| queue.pop_front())
}
pub fn has_todos(&self, module: &str) -> bool {
let queues = self.queues.lock().unwrap();
queues.get(module).is_some_and(|queue| !queue.is_empty())
}
pub fn create_request(
&self,
module: String,
action: String,
data: Value,
priority: TodoPriority,
) -> (TodoItem, Receiver<TodoResponse>) {
let (tx, rx) = channel();
let todo = TodoItem {
module,
action,
data,
priority,
response_channel: Some(tx),
};
(todo, rx)
}
}
impl Default for ModuleTodoQueue {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_todo_queue_priority() {
let queue = ModuleTodoQueue::new();
queue.add_todo(TodoItem {
module: "test".to_string(),
action: "low".to_string(),
data: json!({}),
priority: TodoPriority::Low,
response_channel: None,
});
queue.add_todo(TodoItem {
module: "test".to_string(),
action: "high".to_string(),
data: json!({}),
priority: TodoPriority::High,
response_channel: None,
});
queue.add_todo(TodoItem {
module: "test".to_string(),
action: "normal".to_string(),
data: json!({}),
priority: TodoPriority::Normal,
response_channel: None,
});
let first = queue.get_todo("test").unwrap();
assert_eq!(first.action, "high");
let second = queue.get_todo("test").unwrap();
assert_eq!(second.action, "normal");
let third = queue.get_todo("test").unwrap();
assert_eq!(third.action, "low");
}
}