sum_queue/
lib.rs

1//! `SumQueue` it's a queue struct that keeps a fixed number of
2//! items by time, not capacity, similar to a cache, but with a simpler
3//! and faster implementation. It also allows to get summarized stats
4//! of the values on it at any time.
5//! 
6//! ## Examples
7//! 
8//! ```
9//! use std::time::Duration;
10//! use std::thread;
11//! use sum_queue::SumQueue;
12//!
13//! // creates a queue where elements expire after 2 seconds
14//! let mut queue: SumQueue<i32> = SumQueue::new(Duration::from_secs(2));
15//! queue.push(1);
16//! queue.push(10);
17//! queue.push(3);
18//!
19//! // Check the peek without removing the element
20//! assert_eq!(queue.peek(), Some(&1));
21//! // elements are removed in the same order were pushed
22//! assert_eq!(queue.pop(), Some(1));
23//! assert_eq!(queue.pop(), Some(10));
24//! assert_eq!(queue.pop(), Some(3));
25//! assert_eq!(queue.pop(), None);
26//!
27//! // Lets puts elements again
28//! queue.push(1);
29//! queue.push(5);
30//! queue.push(2);
31//! // Elements can be iterated as many times as you want
32//! println!("heap data: {:?}", queue.iter().collect::<Vec<_>>());  // [1, 5, 2]
33//!
34//! // Check stats
35//! let stats = queue.stats();
36//! println!("Stats - min value in queue: {}", stats.min.unwrap());         // 1
37//! println!("Stats - max value in queue: {}", stats.max.unwrap());         // 5
38//! println!("Stats - sum all values in queue: {}", stats.sum.unwrap());    // 8
39//! println!("Stats - length of queue: {}", stats.len);                     // 3
40//!
41//! assert_eq!(queue.pop(), Some(1));
42//! assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&5, &2]);
43//! println!("Elements after pop: {:?}", queue.iter().collect::<Vec<_>>()); // [5, 2]
44//!
45//! // After a second the elements are still the same
46//! thread::sleep(Duration::from_secs(1));
47//! println!("Same after 1 sec: {:?}", queue.iter().collect::<Vec<_>>());   // [5, 2]
48//!
49//! queue.push(50); // Add an element 1 second younger than the rest of elements
50//! println!("Same elements + 50: {:?}", queue.iter().collect::<Vec<_>>()); // [5, 2, 50]
51//!
52//! // Now let sleep 1 sec so the first elements expire
53//! thread::sleep(Duration::from_secs(1));
54//! println!("Just 50: {:?}", queue.iter().collect::<Vec<_>>());            // [50]
55//!
56//! // 1 second more later the last element also expires
57//! thread::sleep(Duration::from_secs(1));
58//! println!("No elements: {:?}", queue.iter().collect::<Vec<_>>());        // []
59//! ```
60//!
61//! ## Implementation
62//!
63//! Underneath uses a [`BinaryHeap`] struct to keep the values,
64//! and implements the same methods: `push()`, `pop()`, `peek()` ...
65//! although worth to note that the implementations of the `SumQueue` type take mutable
66//! ownership of the `self` reference (eg. `peek(&mut self) -> Option<&T>`). That is
67//! because the cleaning of the expired elements of the queue occurs each time
68//! a method is called to read or write a value, including the `len()` method.
69//!
70//! So as long you manage only one instance of `SumQueue`, there is no
71//! risk of excessive memory allocation, because while you push elements with the `push()`
72//! method, or call any other method to read the queue you are taking care of removing
73//! and deallocating the expired elements, but if you are using multiple instances, and
74//! pushing too many items to some queues and not accessing others further, the memory usage
75//! may growth with elements expired not been deallocated because you are not accessing
76//! those queues to push, pop or get the stats of them. In that case you can at least
77//! try to call often to the `len()` method to force the unused queues to remove and
78//! deallocate the expired elements.
79
80use std::cmp::Ordering;
81use std::collections::BinaryHeap;
82use std::collections::binary_heap;
83use std::ops::Add;
84use std::time::{Instant, Duration};
85
86/// Internal element used by `SumQueue` to hold the values.
87struct QueueElement<T> {
88    time: Instant,
89    value: T
90}
91
92/// Stats of the queue.
93///
94/// It provides the following statistics: **min** and **max** value
95/// in the queue, the **sum** of all the values and the **length**
96/// of all elements hold in the queue.
97///
98/// The values are computed taking into account only
99/// the existent elements in the queue, and not past
100/// elements removed because expiration or because
101/// they were removed.
102///
103/// You can get the stats object calling to
104/// the [`SumQueue::stats()`] method of the queue:
105///
106/// ```
107/// use std::time::Duration;
108/// use sum_queue::SumQueue;
109/// let mut queue = SumQueue::new(Duration::from_millis(800));
110/// queue.push(-1);
111/// queue.push(5);
112/// queue.push(2);
113/// let stats = queue.stats();
114/// assert_eq!(stats.min, Some(-1));
115/// assert_eq!(stats.max, Some(5));
116/// assert_eq!(stats.sum, Some(6));
117/// assert_eq!(stats.len, 3);
118/// ```
119///
120/// But you can also get the stats
121/// while pushing elements, which it's more
122/// efficient than push and then get the stats:
123///
124/// ```
125/// use std::time::Duration;
126/// use sum_queue::SumQueue;
127/// let mut queue = SumQueue::new(Duration::from_secs(1000));
128/// queue.push(-1);
129/// queue.push(5);
130/// let stats = queue.push_and_stats(2);
131/// assert_eq!(stats.min, Some(-1));
132/// assert_eq!(stats.max, Some(5));
133/// assert_eq!(stats.sum, Some(6));
134/// assert_eq!(stats.len, 3);
135/// ```
136pub struct QueueStats<T: Ord + Add<Output = T>> {
137    /// min value of the queue
138    pub min: Option<T>,
139    /// max value of the queue
140    pub max: Option<T>,
141    /// sum of all the values in the queue
142    pub sum: Option<T>,
143    /// size of the queue, same than [`SumQueue::len()`]
144    pub len: usize
145}
146
147impl<T> PartialEq for QueueElement<T> {
148    fn eq(&self, other: &Self) -> bool {
149        self.time == other.time
150    }
151}
152impl<T> Eq for QueueElement<T> {}
153
154impl<T> Ord for QueueElement<T> {
155    fn cmp(&self, other: &Self) -> Ordering {
156        //! Reverse order to set lower number higher
157        other.time.cmp(&self.time)
158    }
159}
160
161impl<T> PartialOrd for QueueElement<T> {
162    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
163        Some(self.cmp(other))
164    }
165}
166
167fn now() -> Instant {
168    Instant::now()
169}
170
171/// Main struct that holds the queue of elements.
172///
173/// There are different ways to create the queue:
174///
175/// ```
176/// use std::time::Duration;
177/// use sum_queue::SumQueue;
178///
179/// let mut queue: SumQueue<i32>;
180///
181/// // Create a queue with elements that expires after 60 seconds
182/// queue = SumQueue::new(Duration::from_secs(60));
183/// // Create with 500 milliseconds expiration and an initial capacity of 20 elements
184/// queue = SumQueue::with_capacity(Duration::from_millis(500), 20);
185/// ```
186pub struct SumQueue<T> {
187    /// the heap with the data
188    heap: BinaryHeap<QueueElement<T>>,
189    /// max time the elements will
190    /// live in the queue.
191    max_age: Duration,
192}
193
194impl<T> SumQueue<T> {
195    /// Creates an empty `SumQueue`, where the elements inside
196    /// will live `max_age_duration` at maximum.
197    pub fn new(max_age_duration: Duration) -> SumQueue<T> {
198        SumQueue {
199            heap: BinaryHeap::<QueueElement<T>>::new(),
200            max_age: max_age_duration,
201        }
202    }
203
204    /// Creates an empty `SumQueue` with a specific initial capacity.
205    /// This preallocates enough memory for `capacity` elements,
206    /// so that the [`BinaryHeap`] inside the `SumQueue` does not have
207    /// to be reallocated until it contains at least that many values.
208    /// The elements inside the queue will live `max_age_duration` time at maximum.
209    pub fn with_capacity(max_age_duration: Duration, capacity: usize) -> SumQueue<T> {
210        SumQueue {
211            heap: BinaryHeap::<QueueElement<T>>::with_capacity(capacity),
212            max_age: max_age_duration,
213        }
214    }
215
216    /// Pushes an item onto the heap of the queue.
217    ///
218    /// See [`BinaryHeap::push`] to known more about the time complexity.
219    ///
220    /// It returns the size of the queue, and before the element is pushed to the heap,
221    /// it also drops all expired elements in the queue.
222    ///
223    /// ```
224    /// use std::time::Duration;
225    /// use sum_queue::SumQueue;
226    /// let mut queue = SumQueue::new(Duration::from_secs(60));
227    /// queue.push(1);
228    /// queue.push(5);
229    /// assert_eq!(queue.push(2), 3);
230    /// assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&1, &5, &2]);
231    /// ```
232    pub fn push(&mut self, item: T) -> usize {
233        let now = now();
234        self.clear_oldest(now);
235        self.heap.push(QueueElement {
236            time: now,
237            value: item
238        });
239        self.heap.len()
240    }
241
242    fn clear_oldest(&mut self, now: Instant) {
243        while let Some(el) = self.heap.peek() {
244            let peek_age = now - el.time;
245            if peek_age > self.max_age {
246                self.heap.pop();
247            } else {
248                break;
249            }
250        }
251    }
252
253    /// Drops all items.
254    pub fn clear(&mut self) {
255        self.heap.clear();
256    }
257
258    /// Returns the length of the heap.
259    ///
260    /// It takes a mutable reference of `self` because
261    /// before return the size it also cleans all the
262    /// expired elements of the queue, so only
263    /// no expired elements are count.
264    pub fn len(&mut self) -> usize {
265        self.clear_oldest(now());
266        self.heap.len()
267    }
268
269    /// Checks if the heap is empty. Expired elements are not taken
270    /// into account because are droped by `is_empty()` before
271    /// return the result.
272    ///
273    /// ```
274    /// use std::time::Duration;
275    /// use std::thread;
276    /// use sum_queue::SumQueue;
277    /// let mut queue = SumQueue::new(Duration::from_millis(600));
278    ///
279    /// assert!(queue.is_empty());
280    ///
281    /// queue.push(123);
282    /// queue.push(555);
283    ///
284    /// assert!(!queue.is_empty());
285    ///
286    /// thread::sleep(Duration::from_secs(1));
287    ///
288    /// assert!(queue.is_empty());
289    /// ```
290    pub fn is_empty(&mut self) -> bool {
291        self.len() == 0
292    }
293
294    /// Returns the number of elements the heap can hold without reallocating.
295    ///
296    /// ```
297    /// use std::time::Duration;
298    /// use sum_queue::SumQueue;
299    /// let mut queue: SumQueue<char> = SumQueue::with_capacity(Duration::from_secs(60), 5);
300    /// assert_eq!(queue.capacity(), 5);
301    /// assert_eq!(queue.len(), 0);
302    /// ```
303    pub fn capacity(&self) -> usize {
304        self.heap.capacity()
305    }
306
307    /// Returns the max time the elements will live in the queue.
308    ///
309    /// ```
310    /// use std::time::Duration;
311    /// use sum_queue::SumQueue;
312    /// let mut queue: SumQueue<char> = SumQueue::new(Duration::from_secs(60));
313    /// assert_eq!(queue.max_age().as_secs(), 60);
314    /// ```
315    pub fn max_age(&self) -> Duration {
316        self.max_age
317    }
318
319    /// Returns the first item in the heap, or `None` if it is empty.
320    ///
321    /// Before the element is returned, it also drops all expired
322    /// elements from the queue.
323    ///
324    /// ```
325    /// use std::time::Duration;
326    /// use sum_queue::SumQueue;
327    /// let mut queue = SumQueue::new(Duration::from_secs(60));
328    /// assert_eq!(queue.peek(), None);
329    /// queue.push("Hello");
330    /// queue.push("World");
331    /// queue.push("!");
332    /// assert_eq!(queue.peek(), Some(&"Hello"));
333    /// ```
334    pub fn peek(&mut self) -> Option<&T> {
335        self.clear_oldest(now());
336        self.heap.peek().map( |q_element| &q_element.value)
337    }
338
339    /// Removes the first item from the heap and returns it, or `None` if it
340    /// is empty.
341    ///
342    /// Before the element is dropped from the queue and returned,
343    /// it also drops all expired elements.
344    ///
345    /// ```
346    /// use std::time::Duration;
347    /// use sum_queue::SumQueue;
348    /// let mut queue = SumQueue::with_capacity(Duration::from_secs(60), 5);
349    /// assert_eq!(queue.pop(), None);
350    /// queue.push('a');
351    /// queue.push('x');
352    /// queue.push('c');
353    /// assert_eq!(queue.pop(), Some('a'));
354    /// assert_eq!(queue.pop(), Some('x'));
355    /// assert_eq!(queue.pop(), Some('c'));
356    /// assert_eq!(queue.pop(), None);
357    /// ```
358    pub fn pop(&mut self) -> Option<T> {
359        self.clear_oldest(now());
360        self.heap.pop().map( |q_element| q_element.value)
361    }
362
363    /// Returns an iterator visiting all values in the underlying heap, in
364    /// same order they were pushed.
365    ///
366    /// Before return the iterator, it also drops all expired elements.
367    ///
368    /// The iterator does not change the state of the queue, this
369    /// method takes ownership of the queue because as mentioned above
370    /// it clears the expired elements before return the iterator, even
371    /// if the iterator is not consumed later on.
372    ///
373    /// ```
374    /// use std::time::Duration;
375    /// use sum_queue::SumQueue;
376    /// let mut queue = SumQueue::new(Duration::from_secs(60));
377    /// queue.push('a');
378    /// queue.push('z');
379    /// queue.push('x');
380    /// assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&'a', &'z', &'x']);
381    /// ```
382    pub fn iter(&mut self) -> Iter<'_, T> {
383        self.clear_oldest(now());
384        Iter { iter: self.heap.iter() }
385    }
386}
387
388impl<T: Copy + Ord + Add<Output = T>> SumQueue<T> {
389
390    fn _stats(&mut self, len: usize) -> QueueStats<T> {
391        let mut min = None; let mut max = None; let mut sum = None;
392        for i in self.heap.iter().map(|x| x.value) {
393            if min == None || Some(i) < min {
394                min = Some(i);
395            }
396            if max == None || Some(i) > max {
397                max = Some(i);
398            }
399            sum = match sum {
400                Some(s) => Some(s + i),
401                None => Some(i)
402            };
403        }
404        QueueStats {
405            min, max, sum, len
406        }
407    }
408
409    /// Get statistics of the queue. The type of the elements
410    /// on it needs to implements the `Copy`, `Ord` and `Add` traits.
411    ///
412    /// Before the stats are returned, it also drops all expired elements.
413    ///
414    /// ```
415    /// use std::time::Duration;
416    /// use sum_queue::SumQueue;
417    /// let mut queue: SumQueue<i64> = SumQueue::new(Duration::from_secs(1000));
418    /// queue.push(-10);
419    /// queue.push(50);
420    /// queue.push(40);
421    /// queue.push(20);
422    /// let stats = queue.stats();
423    /// assert_eq!(stats.min, Some(-10));
424    /// assert_eq!(stats.max, Some(50));
425    /// assert_eq!(stats.sum, Some(100));
426    /// assert_eq!(stats.len, 4);
427    /// ```
428    ///
429    /// See also `push_and_stats`.
430    pub fn stats(&mut self) -> QueueStats<T> {
431        let len = self.len();
432        self._stats(len)
433    }
434
435    /// Pushes an item onto the heap of the queue, and returns
436    /// the stats of the queue. The type of the elements
437    /// on it need to implements the `Copy`, `Ord` and `Add`
438    /// traits.
439    ///
440    /// Before push and return the stats, it also drops all expired elements.
441    ///
442    /// ```
443    /// use std::time::Duration;
444    /// use sum_queue::SumQueue;
445    /// let mut queue: SumQueue<i64> = SumQueue::new(Duration::from_secs(1000));
446    /// queue.push(-10);
447    /// queue.push(50);
448    /// queue.push(40);
449    /// let stats = queue.push_and_stats(20);
450    /// assert_eq!(stats.min, Some(-10));
451    /// assert_eq!(stats.max, Some(50));
452    /// assert_eq!(stats.sum, Some(100));
453    /// assert_eq!(stats.len, 4);
454    /// ```
455    ///
456    /// Use `push` instead if you don't need the stats
457    /// or the elements in the heap don't implement
458    /// any of the required traits.
459    pub fn push_and_stats(&mut self, item: T) -> QueueStats<T> {
460        let len = self.push(item);
461        self._stats(len)
462    }
463}
464
465/// An iterator over the elements of a `SumQueue`.
466///
467/// This `struct` is created by [`SumQueue::iter()`]. See its
468/// documentation for more.
469pub struct Iter<'a, T: 'a> {
470    iter: binary_heap::Iter<'a, QueueElement<T>>,
471}
472
473impl<'a, T> Iterator for Iter<'a, T> {
474    type Item = &'a T;
475
476    fn next(&mut self) -> Option<&'a T> {
477        let element = self.iter.next()?;
478        Some(&element.value)
479    }
480}
481
482mod tests {
483    pub use std::thread;
484    pub use std::time::Duration;
485    pub use crate::SumQueue;
486
487    #[test]
488    fn push_pop_peek() {
489        let mut queue: SumQueue<i32> = SumQueue::new(Duration::from_secs(60));
490        queue.push(1);
491        queue.push(5);
492        assert_eq!(queue.push(2), 3);  // push return queue length
493        assert_eq!(queue.peek(), Some(&1));
494        assert_eq!(queue.peek(), Some(&1));  // still the same
495        assert_eq!(queue.pop(), Some(1));
496        assert_eq!(queue.pop(), Some(5));
497        assert_eq!(queue.pop(), Some(2));
498        assert_eq!(queue.pop(), None);
499        assert_eq!(queue.peek(), None);
500        queue.push(1_000);
501        assert_eq!(queue.peek(), Some(&1_000));
502    }
503
504    #[test]
505    fn push_pop_peek_refs() {
506        let mut queue: SumQueue<&i32> = SumQueue::new(Duration::from_secs(60));
507        queue.push(&1);
508        queue.push(&5);
509        assert_eq!(queue.push(&2), 3);
510        assert_eq!(queue.peek(), Some(&&1));
511        assert_eq!(queue.peek(), Some(&&1));
512        assert_eq!(queue.pop(), Some(&1));
513        assert_eq!(queue.pop(), Some(&5));
514        assert_eq!(queue.pop(), Some(&2));
515        assert_eq!(queue.pop(), None);
516        assert_eq!(queue.peek(), None);
517        queue.push(&1_000);
518        assert_eq!(queue.peek(), Some(&&1_000));
519    }
520
521    #[test]
522    fn len_clear() {
523        let mut queue: SumQueue<char> =SumQueue::with_capacity(
524            Duration::from_secs(60), 2); // small capacity shouldn't be a problem
525        assert_eq!(queue.len(), 0);
526        queue.push('a');
527        queue.push('b');
528        queue.push('c');
529        assert_eq!(queue.len(), 3);
530        queue.pop();
531        assert_eq!(queue.len(), 2);
532        queue.clear();
533        assert_eq!(queue.len(), 0);
534        queue.push('$');
535        assert_eq!(queue.len(), 1);
536    }
537
538    #[test]
539    fn iter() {
540        let mut queue: SumQueue<&str> = SumQueue::with_capacity(
541            Duration::from_secs(60), 20);
542        queue.push("Hey");
543        queue.push("You");
544        queue.push("!");
545        println!("heap data with &str references: {:?}", queue.iter().collect::<Vec<_>>());
546        // data can be iterated as many time as you want
547        assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&"Hey", &"You", &"!"]);
548        print!("heap data, iterate one by one... :");
549        for word in queue.iter() {  // iterate one by one don't crash
550            print!(" {}", word)
551        }
552        println!();
553    }
554
555    #[test]
556    fn expire() {
557        let max_age_secs = 2;
558        let mut queue: SumQueue<i32> = SumQueue::with_capacity(
559            Duration::from_secs(max_age_secs), 20);
560        queue.push(1);
561        queue.push(5);
562        queue.push(2);
563        assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&1, &5, &2]);
564        println!("Elements in queue with max age of {} secs: {:?}",
565                 max_age_secs, queue.iter().collect::<Vec<_>>());
566
567        sleep_secs(1);
568        assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&1, &5, &2]);
569        println!("No expiration yet, same elements: {:?}", queue.iter().collect::<Vec<_>>());
570
571        println!("\nAdding element 50 ...");
572        queue.push(50);
573        assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&1, &5, &2, &50]);
574        println!("Same elements + 50: {:?}", queue.iter().collect::<Vec<_>>());
575
576        sleep_secs(1);
577        assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&50]);
578        println!("Expired original list, only 50 in the list: {:?}",
579                 queue.iter().collect::<Vec<_>>());
580
581        sleep_secs(2);
582        assert_eq!(queue.iter().collect::<Vec<_>>().len(), 0);
583        println!("No elements kept: {:?}", queue.iter().collect::<Vec<_>>());
584    }
585
586    #[test]
587    fn expire_less_one_sec() {
588        let max_age_millis = 200;
589        let mut queue: SumQueue<i32> = SumQueue::with_capacity(
590            Duration::from_millis(max_age_millis), 20);
591        queue.push(1);
592        queue.push(5);
593        queue.push(2);
594        assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&1, &5, &2]);
595        println!("Elements in queue with max age of {} millis: {:?}",
596                 max_age_millis, queue.iter().collect::<Vec<_>>());
597
598        sleep_millis(100);
599        assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&1, &5, &2]);
600        println!("No expiration yet, same elements: {:?}", queue.iter().collect::<Vec<_>>());
601
602        println!("\nAdding element 50 ...");
603        queue.push(50);
604        assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&1, &5, &2, &50]);
605        println!("Same elements + 50: {:?}", queue.iter().collect::<Vec<_>>());
606
607        sleep_millis(100);
608        assert_eq!(queue.iter().collect::<Vec<_>>(), vec![&50]);
609        println!("Expired original list, only 50 in the list: {:?}",
610                 queue.iter().collect::<Vec<_>>());
611
612        sleep_millis(200);
613        assert_eq!(queue.iter().collect::<Vec<_>>().len(), 0);
614        println!("No elements kept: {:?}", queue.iter().collect::<Vec<_>>());
615    }
616
617    #[test]
618    fn stats_empty_when_queue_not_initialized() {
619        let mut queue: SumQueue<i64> = SumQueue::new(Duration::from_millis(9000));
620        let stats = queue.stats();
621        assert_eq!(stats.min, None);
622        assert_eq!(stats.max, None);
623        assert_eq!(stats.sum, None);
624        assert_eq!(stats.len, 0);
625    }
626
627    #[test]
628    fn stats() {
629        let mut queue: SumQueue<i64> = SumQueue::new(Duration::from_secs(1000));
630        queue.push(-10);
631        queue.push(50);
632        queue.push(20);
633        queue.push(20);
634
635        let mut stats = queue.stats();
636        assert_eq!(stats.min, Some(-10));
637        assert_eq!(stats.max, Some(50));
638        assert_eq!(stats.sum, Some(80));
639        assert_eq!(stats.len, 4);
640
641        queue.clear();
642        stats = queue.stats();
643        assert_eq!(stats.min, None);
644        assert_eq!(stats.max, None);
645        assert_eq!(stats.sum, None);
646        assert_eq!(stats.len, 0);
647
648        queue.push(100_000);
649        stats = queue.stats();
650        assert_eq!(stats.min, Some(100_000));
651        assert_eq!(stats.max, Some(100_000));
652        assert_eq!(stats.sum, Some(100_000));
653        assert_eq!(stats.len, 1);
654
655        queue.push(5);
656        stats = queue.push_and_stats(1);
657        assert_eq!(stats.min, Some(1));
658        assert_eq!(stats.max, Some(100_000));
659        assert_eq!(stats.sum, Some(100_006));
660        assert_eq!(stats.len, 3);
661    }
662
663    #[cfg(test)]
664    fn sleep_secs(dur_secs: u64) {
665        println!("\nSleeping {} secs ...", dur_secs);
666        thread::sleep(Duration::from_secs(dur_secs));
667    }
668
669    #[cfg(test)]
670    fn sleep_millis(dur_millis: u64) {
671        println!("\nSleeping {} millis ...", dur_millis);
672        thread::sleep(Duration::from_millis(dur_millis));
673    }
674}