Skip to main content

ipfrs_network/
request_priority_queue.rs

1//! Priority-based work queue for processing peer requests.
2//!
3//! Provides [`PeerRequestQueue`] — a multi-level priority queue keyed by
4//! [`RequestPriority`] (Critical > High > Normal > Low).  Within each priority
5//! level messages are dequeued in strict FIFO order.
6//!
7//! The queue tracks a monotonic logical clock advanced via [`PeerRequestQueue::tick`],
8//! stamps every incoming request with the current tick, and accumulates lifetime
9//! statistics in [`PriorityQueueStats`].
10
11use std::collections::{BTreeMap, VecDeque};
12
13// ─── RequestPriority ────────────────────────────────────────────────────────
14
15/// Priority level for a queued peer request.
16///
17/// Variants are ordered so that [`Ord`] yields `Low < Normal < High < Critical`,
18/// matching the dequeue precedence: Critical is popped first.
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[repr(u8)]
21pub enum RequestPriority {
22    /// Lowest priority — only processed when all higher tiers are empty.
23    Low = 0,
24    /// Default priority.
25    Normal = 1,
26    /// Elevated priority.
27    High = 2,
28    /// Highest priority — always processed first.
29    Critical = 3,
30}
31
32// ─── PeerRequest ────────────────────────────────────────────────────────────
33
34/// A single request waiting in the queue.
35#[derive(Debug, Clone)]
36pub struct PeerRequest {
37    /// Unique identifier assigned by the queue on enqueue.
38    pub id: u64,
39    /// Identifier of the peer that originated the request.
40    pub peer_id: String,
41    /// Priority tier governing dequeue order.
42    pub priority: RequestPriority,
43    /// Size of the request payload in bytes.
44    pub payload_size: u64,
45    /// Logical clock value at the time the request was enqueued.
46    pub enqueued_tick: u64,
47}
48
49// ─── PriorityQueueStats ─────────────────────────────────────────────────────
50
51/// Snapshot of queue statistics.
52#[derive(Debug, Clone)]
53pub struct PriorityQueueStats {
54    /// Total requests enqueued over the lifetime of the queue.
55    pub total_enqueued: u64,
56    /// Total requests dequeued over the lifetime of the queue.
57    pub total_dequeued: u64,
58    /// Current number of pending requests across all priority levels.
59    pub current_size: usize,
60    /// Pending requests at [`RequestPriority::Critical`].
61    pub critical_count: usize,
62    /// Pending requests at [`RequestPriority::High`].
63    pub high_count: usize,
64    /// Pending requests at [`RequestPriority::Normal`].
65    pub normal_count: usize,
66    /// Pending requests at [`RequestPriority::Low`].
67    pub low_count: usize,
68}
69
70// ─── PeerRequestQueue ───────────────────────────────────────────────────────
71
72/// Priority-based work queue for peer requests.
73///
74/// Requests are placed into per-priority FIFO sub-queues stored in a
75/// [`BTreeMap`].  On [`dequeue`](Self::dequeue), the highest non-empty
76/// priority level is drained first (Critical → High → Normal → Low).
77pub struct PeerRequestQueue {
78    /// Per-priority FIFO sub-queues.
79    queues: BTreeMap<RequestPriority, VecDeque<PeerRequest>>,
80    /// Next unique identifier to assign.
81    next_id: u64,
82    /// Monotonic logical clock.
83    current_tick: u64,
84    /// Lifetime enqueue counter.
85    total_enqueued: u64,
86    /// Lifetime dequeue counter.
87    total_dequeued: u64,
88}
89
90impl PeerRequestQueue {
91    /// Create a new, empty queue.
92    pub fn new() -> Self {
93        let mut queues = BTreeMap::new();
94        queues.insert(RequestPriority::Critical, VecDeque::new());
95        queues.insert(RequestPriority::High, VecDeque::new());
96        queues.insert(RequestPriority::Normal, VecDeque::new());
97        queues.insert(RequestPriority::Low, VecDeque::new());
98
99        Self {
100            queues,
101            next_id: 0,
102            current_tick: 0,
103            total_enqueued: 0,
104            total_dequeued: 0,
105        }
106    }
107
108    /// Enqueue a new request and return its unique identifier.
109    pub fn enqueue(&mut self, peer_id: &str, priority: RequestPriority, payload_size: u64) -> u64 {
110        let id = self.next_id;
111        self.next_id = self.next_id.wrapping_add(1);
112
113        let request = PeerRequest {
114            id,
115            peer_id: peer_id.to_string(),
116            priority,
117            payload_size,
118            enqueued_tick: self.current_tick,
119        };
120
121        // The sub-queue is guaranteed to exist because we seed all four in `new()`.
122        if let Some(q) = self.queues.get_mut(&priority) {
123            q.push_back(request);
124        }
125
126        self.total_enqueued += 1;
127        id
128    }
129
130    /// Pop the highest-priority request (FIFO within each level).
131    ///
132    /// Returns `None` when every sub-queue is empty.
133    pub fn dequeue(&mut self) -> Option<PeerRequest> {
134        // Iterate in *reverse* key order because `BTreeMap` orders by `Ord` and
135        // `Critical(3) > High(2) > Normal(1) > Low(0)`.
136        for (_, q) in self.queues.iter_mut().rev() {
137            if let Some(req) = q.pop_front() {
138                self.total_dequeued += 1;
139                return Some(req);
140            }
141        }
142        None
143    }
144
145    /// Peek at the highest-priority request without removing it.
146    pub fn peek(&self) -> Option<&PeerRequest> {
147        for (_, q) in self.queues.iter().rev() {
148            if let Some(req) = q.front() {
149                return Some(req);
150            }
151        }
152        None
153    }
154
155    /// Total number of requests across all priority levels.
156    pub fn len(&self) -> usize {
157        self.queues.values().map(VecDeque::len).sum()
158    }
159
160    /// Returns `true` when the queue contains no requests.
161    pub fn is_empty(&self) -> bool {
162        self.queues.values().all(VecDeque::is_empty)
163    }
164
165    /// Remove and return all requests at the given priority level.
166    pub fn drain_priority(&mut self, priority: RequestPriority) -> Vec<PeerRequest> {
167        match self.queues.get_mut(&priority) {
168            Some(q) => {
169                let drained: Vec<PeerRequest> = q.drain(..).collect();
170                self.total_dequeued += drained.len() as u64;
171                drained
172            }
173            None => Vec::new(),
174        }
175    }
176
177    /// Cancel a specific request by its unique identifier.
178    ///
179    /// Returns `true` if the request was found and removed.
180    pub fn cancel(&mut self, request_id: u64) -> bool {
181        for (_, q) in self.queues.iter_mut() {
182            if let Some(pos) = q.iter().position(|r| r.id == request_id) {
183                q.remove(pos);
184                return true;
185            }
186        }
187        false
188    }
189
190    /// Advance the logical clock by one tick.
191    pub fn tick(&mut self) {
192        self.current_tick = self.current_tick.wrapping_add(1);
193    }
194
195    /// Number of pending requests at the given priority level.
196    pub fn count_by_priority(&self, priority: RequestPriority) -> usize {
197        self.queues.get(&priority).map_or(0, VecDeque::len)
198    }
199
200    /// Sum of `payload_size` across all pending requests.
201    pub fn total_payload_bytes(&self) -> u64 {
202        self.queues
203            .values()
204            .flat_map(|q| q.iter())
205            .map(|r| r.payload_size)
206            .sum()
207    }
208
209    /// Snapshot of current queue statistics.
210    pub fn stats(&self) -> PriorityQueueStats {
211        PriorityQueueStats {
212            total_enqueued: self.total_enqueued,
213            total_dequeued: self.total_dequeued,
214            current_size: self.len(),
215            critical_count: self.count_by_priority(RequestPriority::Critical),
216            high_count: self.count_by_priority(RequestPriority::High),
217            normal_count: self.count_by_priority(RequestPriority::Normal),
218            low_count: self.count_by_priority(RequestPriority::Low),
219        }
220    }
221}
222
223impl Default for PeerRequestQueue {
224    fn default() -> Self {
225        Self::new()
226    }
227}
228
229// ─── Tests ──────────────────────────────────────────────────────────────────
230
231#[cfg(test)]
232mod tests {
233    use super::*;
234
235    // ── helpers ─────────────────────────────────────────────────────────────
236
237    fn new_queue() -> PeerRequestQueue {
238        PeerRequestQueue::new()
239    }
240
241    // ── basic enqueue / dequeue ─────────────────────────────────────────────
242
243    #[test]
244    fn enqueue_returns_unique_ids() {
245        let mut q = new_queue();
246        let id0 = q.enqueue("peer-a", RequestPriority::Normal, 100);
247        let id1 = q.enqueue("peer-a", RequestPriority::Normal, 200);
248        assert_ne!(id0, id1);
249    }
250
251    #[test]
252    fn dequeue_returns_none_when_empty() {
253        let mut q = new_queue();
254        assert!(q.dequeue().is_none());
255    }
256
257    #[test]
258    fn enqueue_then_dequeue_returns_same_request() {
259        let mut q = new_queue();
260        let id = q.enqueue("peer-a", RequestPriority::Normal, 512);
261        let req = q.dequeue().expect("should have one request");
262        assert_eq!(req.id, id);
263        assert_eq!(req.peer_id, "peer-a");
264        assert_eq!(req.payload_size, 512);
265    }
266
267    // ── priority ordering ───────────────────────────────────────────────────
268
269    #[test]
270    fn critical_dequeued_before_high() {
271        let mut q = new_queue();
272        q.enqueue("peer-a", RequestPriority::High, 10);
273        q.enqueue("peer-a", RequestPriority::Critical, 10);
274        let first = q.dequeue().expect("should have request");
275        assert_eq!(first.priority, RequestPriority::Critical);
276    }
277
278    #[test]
279    fn high_dequeued_before_normal() {
280        let mut q = new_queue();
281        q.enqueue("peer-a", RequestPriority::Normal, 10);
282        q.enqueue("peer-a", RequestPriority::High, 10);
283        let first = q.dequeue().expect("should have request");
284        assert_eq!(first.priority, RequestPriority::High);
285    }
286
287    #[test]
288    fn normal_dequeued_before_low() {
289        let mut q = new_queue();
290        q.enqueue("peer-a", RequestPriority::Low, 10);
291        q.enqueue("peer-a", RequestPriority::Normal, 10);
292        let first = q.dequeue().expect("should have request");
293        assert_eq!(first.priority, RequestPriority::Normal);
294    }
295
296    #[test]
297    fn full_priority_ordering() {
298        let mut q = new_queue();
299        q.enqueue("peer-a", RequestPriority::Low, 10);
300        q.enqueue("peer-a", RequestPriority::Normal, 10);
301        q.enqueue("peer-a", RequestPriority::Critical, 10);
302        q.enqueue("peer-a", RequestPriority::High, 10);
303
304        let r1 = q.dequeue().expect("msg");
305        let r2 = q.dequeue().expect("msg");
306        let r3 = q.dequeue().expect("msg");
307        let r4 = q.dequeue().expect("msg");
308
309        assert_eq!(r1.priority, RequestPriority::Critical);
310        assert_eq!(r2.priority, RequestPriority::High);
311        assert_eq!(r3.priority, RequestPriority::Normal);
312        assert_eq!(r4.priority, RequestPriority::Low);
313        assert!(q.dequeue().is_none());
314    }
315
316    // ── FIFO within same priority ───────────────────────────────────────────
317
318    #[test]
319    fn fifo_within_critical() {
320        let mut q = new_queue();
321        let id0 = q.enqueue("peer-a", RequestPriority::Critical, 10);
322        let id1 = q.enqueue("peer-a", RequestPriority::Critical, 20);
323        let id2 = q.enqueue("peer-a", RequestPriority::Critical, 30);
324        assert_eq!(q.dequeue().expect("msg").id, id0);
325        assert_eq!(q.dequeue().expect("msg").id, id1);
326        assert_eq!(q.dequeue().expect("msg").id, id2);
327    }
328
329    #[test]
330    fn fifo_within_high() {
331        let mut q = new_queue();
332        let id0 = q.enqueue("peer-b", RequestPriority::High, 10);
333        let id1 = q.enqueue("peer-b", RequestPriority::High, 20);
334        assert_eq!(q.dequeue().expect("msg").id, id0);
335        assert_eq!(q.dequeue().expect("msg").id, id1);
336    }
337
338    #[test]
339    fn fifo_within_normal() {
340        let mut q = new_queue();
341        let id0 = q.enqueue("peer-c", RequestPriority::Normal, 10);
342        let id1 = q.enqueue("peer-c", RequestPriority::Normal, 20);
343        let id2 = q.enqueue("peer-c", RequestPriority::Normal, 30);
344        assert_eq!(q.dequeue().expect("msg").id, id0);
345        assert_eq!(q.dequeue().expect("msg").id, id1);
346        assert_eq!(q.dequeue().expect("msg").id, id2);
347    }
348
349    #[test]
350    fn fifo_within_low() {
351        let mut q = new_queue();
352        let id0 = q.enqueue("peer-d", RequestPriority::Low, 10);
353        let id1 = q.enqueue("peer-d", RequestPriority::Low, 20);
354        assert_eq!(q.dequeue().expect("msg").id, id0);
355        assert_eq!(q.dequeue().expect("msg").id, id1);
356    }
357
358    // ── peek ────────────────────────────────────────────────────────────────
359
360    #[test]
361    fn peek_returns_none_when_empty() {
362        let q = new_queue();
363        assert!(q.peek().is_none());
364    }
365
366    #[test]
367    fn peek_does_not_remove() {
368        let mut q = new_queue();
369        q.enqueue("peer-a", RequestPriority::Normal, 100);
370        assert!(q.peek().is_some());
371        assert_eq!(q.len(), 1);
372        assert!(q.peek().is_some());
373        assert_eq!(q.len(), 1);
374    }
375
376    #[test]
377    fn peek_returns_highest_priority() {
378        let mut q = new_queue();
379        q.enqueue("peer-a", RequestPriority::Low, 10);
380        q.enqueue("peer-a", RequestPriority::High, 20);
381        let peeked = q.peek().expect("should have request");
382        assert_eq!(peeked.priority, RequestPriority::High);
383    }
384
385    // ── len / is_empty ──────────────────────────────────────────────────────
386
387    #[test]
388    fn len_counts_all_priorities() {
389        let mut q = new_queue();
390        q.enqueue("peer-a", RequestPriority::Critical, 10);
391        q.enqueue("peer-a", RequestPriority::High, 10);
392        q.enqueue("peer-a", RequestPriority::Normal, 10);
393        q.enqueue("peer-a", RequestPriority::Low, 10);
394        assert_eq!(q.len(), 4);
395    }
396
397    #[test]
398    fn is_empty_when_new() {
399        let q = new_queue();
400        assert!(q.is_empty());
401    }
402
403    #[test]
404    fn is_empty_false_after_enqueue() {
405        let mut q = new_queue();
406        q.enqueue("peer-a", RequestPriority::Normal, 10);
407        assert!(!q.is_empty());
408    }
409
410    #[test]
411    fn is_empty_true_after_all_dequeued() {
412        let mut q = new_queue();
413        q.enqueue("peer-a", RequestPriority::Normal, 10);
414        let _ = q.dequeue();
415        assert!(q.is_empty());
416    }
417
418    // ── drain_priority ──────────────────────────────────────────────────────
419
420    #[test]
421    fn drain_priority_removes_all_at_level() {
422        let mut q = new_queue();
423        q.enqueue("peer-a", RequestPriority::High, 10);
424        q.enqueue("peer-b", RequestPriority::High, 20);
425        q.enqueue("peer-a", RequestPriority::Normal, 30);
426
427        let drained = q.drain_priority(RequestPriority::High);
428        assert_eq!(drained.len(), 2);
429        assert_eq!(q.len(), 1);
430        assert_eq!(q.count_by_priority(RequestPriority::High), 0);
431    }
432
433    #[test]
434    fn drain_priority_returns_empty_when_none() {
435        let mut q = new_queue();
436        q.enqueue("peer-a", RequestPriority::Normal, 10);
437        let drained = q.drain_priority(RequestPriority::Critical);
438        assert!(drained.is_empty());
439    }
440
441    #[test]
442    fn drain_preserves_fifo_order() {
443        let mut q = new_queue();
444        let id0 = q.enqueue("peer-a", RequestPriority::Normal, 10);
445        let id1 = q.enqueue("peer-b", RequestPriority::Normal, 20);
446        let id2 = q.enqueue("peer-c", RequestPriority::Normal, 30);
447
448        let drained = q.drain_priority(RequestPriority::Normal);
449        assert_eq!(drained.len(), 3);
450        assert_eq!(drained[0].id, id0);
451        assert_eq!(drained[1].id, id1);
452        assert_eq!(drained[2].id, id2);
453    }
454
455    // ── cancel ──────────────────────────────────────────────────────────────
456
457    #[test]
458    fn cancel_removes_specific_request() {
459        let mut q = new_queue();
460        let _id0 = q.enqueue("peer-a", RequestPriority::Normal, 10);
461        let id1 = q.enqueue("peer-b", RequestPriority::Normal, 20);
462        let _id2 = q.enqueue("peer-c", RequestPriority::Normal, 30);
463
464        assert!(q.cancel(id1));
465        assert_eq!(q.len(), 2);
466
467        // Remaining requests should be id0 and id2 in FIFO order.
468        let r0 = q.dequeue().expect("msg");
469        let r2 = q.dequeue().expect("msg");
470        assert_eq!(r0.id, _id0);
471        assert_eq!(r2.id, _id2);
472    }
473
474    #[test]
475    fn cancel_returns_false_for_nonexistent_id() {
476        let mut q = new_queue();
477        q.enqueue("peer-a", RequestPriority::Normal, 10);
478        assert!(!q.cancel(9999));
479        assert_eq!(q.len(), 1);
480    }
481
482    #[test]
483    fn cancel_across_priorities() {
484        let mut q = new_queue();
485        let _id0 = q.enqueue("peer-a", RequestPriority::Critical, 10);
486        let id1 = q.enqueue("peer-b", RequestPriority::Low, 20);
487
488        assert!(q.cancel(id1));
489        assert_eq!(q.len(), 1);
490        let remaining = q.dequeue().expect("msg");
491        assert_eq!(remaining.priority, RequestPriority::Critical);
492    }
493
494    // ── tick ────────────────────────────────────────────────────────────────
495
496    #[test]
497    fn tick_advances_clock() {
498        let mut q = new_queue();
499        q.tick();
500        q.tick();
501        let id = q.enqueue("peer-a", RequestPriority::Normal, 10);
502        let req = q.dequeue().expect("msg");
503        assert_eq!(req.id, id);
504        assert_eq!(req.enqueued_tick, 2);
505    }
506
507    #[test]
508    fn enqueued_tick_reflects_current_clock() {
509        let mut q = new_queue();
510        q.enqueue("peer-a", RequestPriority::Normal, 10);
511        q.tick();
512        q.tick();
513        q.tick();
514        q.enqueue("peer-b", RequestPriority::Normal, 20);
515
516        let r0 = q.dequeue().expect("msg");
517        let r1 = q.dequeue().expect("msg");
518        assert_eq!(r0.enqueued_tick, 0);
519        assert_eq!(r1.enqueued_tick, 3);
520    }
521
522    // ── count_by_priority ───────────────────────────────────────────────────
523
524    #[test]
525    fn count_by_priority_tracks_correctly() {
526        let mut q = new_queue();
527        q.enqueue("peer-a", RequestPriority::Critical, 10);
528        q.enqueue("peer-b", RequestPriority::Critical, 10);
529        q.enqueue("peer-c", RequestPriority::Normal, 10);
530
531        assert_eq!(q.count_by_priority(RequestPriority::Critical), 2);
532        assert_eq!(q.count_by_priority(RequestPriority::High), 0);
533        assert_eq!(q.count_by_priority(RequestPriority::Normal), 1);
534        assert_eq!(q.count_by_priority(RequestPriority::Low), 0);
535    }
536
537    // ── total_payload_bytes ─────────────────────────────────────────────────
538
539    #[test]
540    fn total_payload_bytes_sums_all() {
541        let mut q = new_queue();
542        q.enqueue("peer-a", RequestPriority::Critical, 100);
543        q.enqueue("peer-b", RequestPriority::Normal, 200);
544        q.enqueue("peer-c", RequestPriority::Low, 300);
545        assert_eq!(q.total_payload_bytes(), 600);
546    }
547
548    #[test]
549    fn total_payload_bytes_decreases_after_dequeue() {
550        let mut q = new_queue();
551        q.enqueue("peer-a", RequestPriority::Normal, 500);
552        q.enqueue("peer-b", RequestPriority::Normal, 300);
553        let _ = q.dequeue();
554        assert_eq!(q.total_payload_bytes(), 300);
555    }
556
557    #[test]
558    fn total_payload_bytes_zero_when_empty() {
559        let q = new_queue();
560        assert_eq!(q.total_payload_bytes(), 0);
561    }
562
563    // ── stats ───────────────────────────────────────────────────────────────
564
565    #[test]
566    fn stats_tracks_enqueued_and_dequeued() {
567        let mut q = new_queue();
568        q.enqueue("peer-a", RequestPriority::Normal, 10);
569        q.enqueue("peer-b", RequestPriority::High, 20);
570        q.enqueue("peer-c", RequestPriority::Low, 30);
571        let _ = q.dequeue();
572
573        let s = q.stats();
574        assert_eq!(s.total_enqueued, 3);
575        assert_eq!(s.total_dequeued, 1);
576        assert_eq!(s.current_size, 2);
577    }
578
579    #[test]
580    fn stats_priority_counts() {
581        let mut q = new_queue();
582        q.enqueue("peer-a", RequestPriority::Critical, 10);
583        q.enqueue("peer-b", RequestPriority::Critical, 10);
584        q.enqueue("peer-c", RequestPriority::High, 10);
585        q.enqueue("peer-d", RequestPriority::Normal, 10);
586        q.enqueue("peer-e", RequestPriority::Low, 10);
587        q.enqueue("peer-f", RequestPriority::Low, 10);
588
589        let s = q.stats();
590        assert_eq!(s.critical_count, 2);
591        assert_eq!(s.high_count, 1);
592        assert_eq!(s.normal_count, 1);
593        assert_eq!(s.low_count, 2);
594    }
595
596    #[test]
597    fn stats_after_drain() {
598        let mut q = new_queue();
599        q.enqueue("peer-a", RequestPriority::High, 10);
600        q.enqueue("peer-b", RequestPriority::High, 10);
601        q.enqueue("peer-c", RequestPriority::Low, 10);
602
603        let _ = q.drain_priority(RequestPriority::High);
604        let s = q.stats();
605        assert_eq!(s.total_dequeued, 2);
606        assert_eq!(s.high_count, 0);
607        assert_eq!(s.low_count, 1);
608        assert_eq!(s.current_size, 1);
609    }
610
611    // ── mixed operations ────────────────────────────────────────────────────
612
613    #[test]
614    fn mixed_enqueue_dequeue_cancel_ordering() {
615        let mut q = new_queue();
616        let id_low = q.enqueue("peer-a", RequestPriority::Low, 10);
617        let _id_crit = q.enqueue("peer-b", RequestPriority::Critical, 20);
618        let id_normal = q.enqueue("peer-c", RequestPriority::Normal, 30);
619
620        // Cancel the normal-priority request.
621        assert!(q.cancel(id_normal));
622        assert_eq!(q.len(), 2);
623
624        // Critical should come first, then low.
625        let r1 = q.dequeue().expect("msg");
626        assert_eq!(r1.priority, RequestPriority::Critical);
627        let r2 = q.dequeue().expect("msg");
628        assert_eq!(r2.id, id_low);
629        assert!(q.is_empty());
630    }
631
632    #[test]
633    fn interleaved_enqueue_dequeue() {
634        let mut q = new_queue();
635        q.enqueue("peer-a", RequestPriority::Normal, 10);
636        q.enqueue("peer-b", RequestPriority::High, 20);
637
638        // Dequeue should get High first.
639        let r1 = q.dequeue().expect("msg");
640        assert_eq!(r1.priority, RequestPriority::High);
641
642        // Enqueue a Critical while Normal is still pending.
643        q.enqueue("peer-c", RequestPriority::Critical, 30);
644
645        // Critical should come next.
646        let r2 = q.dequeue().expect("msg");
647        assert_eq!(r2.priority, RequestPriority::Critical);
648
649        // Then Normal.
650        let r3 = q.dequeue().expect("msg");
651        assert_eq!(r3.priority, RequestPriority::Normal);
652        assert!(q.is_empty());
653    }
654
655    #[test]
656    fn multiple_peers_same_priority() {
657        let mut q = new_queue();
658        let id_a = q.enqueue("peer-a", RequestPriority::Normal, 10);
659        let id_b = q.enqueue("peer-b", RequestPriority::Normal, 20);
660        let id_c = q.enqueue("peer-c", RequestPriority::Normal, 30);
661
662        // Should come out in FIFO order regardless of peer_id.
663        assert_eq!(q.dequeue().expect("msg").id, id_a);
664        assert_eq!(q.dequeue().expect("msg").id, id_b);
665        assert_eq!(q.dequeue().expect("msg").id, id_c);
666    }
667
668    #[test]
669    fn default_impl_creates_empty_queue() {
670        let q = PeerRequestQueue::default();
671        assert!(q.is_empty());
672        assert_eq!(q.len(), 0);
673        assert_eq!(q.total_payload_bytes(), 0);
674    }
675}