Skip to main content

oxihuman_core/
update_queue.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Ordered update queue: items enqueued with a priority, drained in order.
6
7use std::cmp::Reverse;
8use std::collections::BinaryHeap;
9
10/// An item pending in the update queue.
11#[allow(dead_code)]
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct UpdateItem {
14    pub priority: u32,
15    pub id: u32,
16    pub tag: String,
17}
18
19impl PartialOrd for UpdateItem {
20    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
21        Some(self.cmp(other))
22    }
23}
24
25impl Ord for UpdateItem {
26    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
27        Reverse(self.priority).cmp(&Reverse(other.priority))
28    }
29}
30
31/// An update queue sorted by priority (lowest = first).
32#[allow(dead_code)]
33#[derive(Debug, Clone, Default)]
34pub struct UpdateQueue {
35    heap: BinaryHeap<UpdateItem>,
36    total_enqueued: u64,
37}
38
39/// Create a new `UpdateQueue`.
40#[allow(dead_code)]
41pub fn new_update_queue() -> UpdateQueue {
42    UpdateQueue::default()
43}
44
45/// Enqueue an item.
46#[allow(dead_code)]
47pub fn uq_enqueue(q: &mut UpdateQueue, id: u32, priority: u32, tag: &str) {
48    q.heap.push(UpdateItem {
49        priority,
50        id,
51        tag: tag.to_string(),
52    });
53    q.total_enqueued += 1;
54}
55
56/// Dequeue the highest-priority item (lowest priority number).
57#[allow(dead_code)]
58pub fn uq_dequeue(q: &mut UpdateQueue) -> Option<UpdateItem> {
59    q.heap.pop()
60}
61
62/// Peek at the next item without removing.
63#[allow(dead_code)]
64pub fn uq_peek(q: &UpdateQueue) -> Option<&UpdateItem> {
65    q.heap.peek()
66}
67
68/// Number of items pending.
69#[allow(dead_code)]
70pub fn uq_len(q: &UpdateQueue) -> usize {
71    q.heap.len()
72}
73
74/// Whether the queue is empty.
75#[allow(dead_code)]
76pub fn uq_is_empty(q: &UpdateQueue) -> bool {
77    q.heap.is_empty()
78}
79
80/// Total items ever enqueued.
81#[allow(dead_code)]
82pub fn uq_total_enqueued(q: &UpdateQueue) -> u64 {
83    q.total_enqueued
84}
85
86/// Drain all items into a sorted Vec (ascending priority).
87#[allow(dead_code)]
88pub fn uq_drain_all(q: &mut UpdateQueue) -> Vec<UpdateItem> {
89    let mut items = Vec::new();
90    while let Some(item) = q.heap.pop() {
91        items.push(item);
92    }
93    items
94}
95
96/// Clear the queue.
97#[allow(dead_code)]
98pub fn uq_clear(q: &mut UpdateQueue) {
99    q.heap.clear();
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn test_empty() {
108        let q = new_update_queue();
109        assert!(uq_is_empty(&q));
110    }
111
112    #[test]
113    fn test_enqueue_and_len() {
114        let mut q = new_update_queue();
115        uq_enqueue(&mut q, 1, 5, "x");
116        assert_eq!(uq_len(&q), 1);
117    }
118
119    #[test]
120    fn test_priority_order() {
121        let mut q = new_update_queue();
122        uq_enqueue(&mut q, 1, 10, "low");
123        uq_enqueue(&mut q, 2, 1, "high");
124        let first = uq_dequeue(&mut q).expect("should succeed");
125        assert_eq!(first.id, 2);
126    }
127
128    #[test]
129    fn test_peek_does_not_remove() {
130        let mut q = new_update_queue();
131        uq_enqueue(&mut q, 1, 3, "x");
132        uq_peek(&q);
133        assert_eq!(uq_len(&q), 1);
134    }
135
136    #[test]
137    fn test_drain_all() {
138        let mut q = new_update_queue();
139        uq_enqueue(&mut q, 3, 5, "c");
140        uq_enqueue(&mut q, 1, 1, "a");
141        uq_enqueue(&mut q, 2, 3, "b");
142        let items = uq_drain_all(&mut q);
143        assert_eq!(items.len(), 3);
144        assert!(uq_is_empty(&q));
145        assert_eq!(items[0].id, 1);
146    }
147
148    #[test]
149    fn test_clear() {
150        let mut q = new_update_queue();
151        uq_enqueue(&mut q, 1, 1, "x");
152        uq_clear(&mut q);
153        assert!(uq_is_empty(&q));
154    }
155
156    #[test]
157    fn test_total_enqueued() {
158        let mut q = new_update_queue();
159        uq_enqueue(&mut q, 1, 1, "a");
160        uq_enqueue(&mut q, 2, 2, "b");
161        assert_eq!(uq_total_enqueued(&q), 2);
162    }
163
164    #[test]
165    fn test_dequeue_empty() {
166        let mut q = new_update_queue();
167        assert!(uq_dequeue(&mut q).is_none());
168    }
169
170    #[test]
171    fn test_tag_preserved() {
172        let mut q = new_update_queue();
173        uq_enqueue(&mut q, 1, 0, "mytag");
174        let item = uq_dequeue(&mut q).expect("should succeed");
175        assert_eq!(item.tag, "mytag".to_string());
176    }
177}