Skip to main content

detcore_model/collections/
replay_cursor.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9use std::collections::VecDeque;
10use std::fmt;
11use std::iter::FromIterator;
12
13/// This is a queue like data structure used when replaying schedule
14///
15/// Apart from being an [`Iterator`], it supports [`ReplayCursor::peek`] and
16/// [`ReplayCursor::peek_nth`] to look ahead an arbitrary number of events while replaying.
17#[derive(Debug)]
18pub struct ReplayCursor<T> {
19    inner_data: VecDeque<T>,
20}
21
22impl<T: Eq + fmt::Display> ReplayCursor<T> {
23    /// peeks the following nth element from the top of the cursor
24    pub fn peek_nth(&self, index: usize) -> Option<&T> {
25        self.inner_data.get(index)
26    }
27
28    /// peeks the following item from the top of the cursor
29    pub fn peek(&self) -> Option<&T> {
30        self.peek_nth(0)
31    }
32
33    /// Look ahead N positions to see if an element satisfying the predicate is found within that
34    /// window.  Return the position, if found.
35    pub fn prefix_contains<F>(&self, winsize: usize, pred: F) -> Option<usize>
36    where
37        F: Fn(&T) -> bool,
38    {
39        for (i, v) in self.inner_data.iter().enumerate().take(winsize) {
40            if pred(v) {
41                return Some(i);
42            }
43        }
44        None
45    }
46
47    pub fn drop(&mut self, count: usize) {
48        let _ = self.inner_data.split_off(count);
49    }
50
51    // print a window of up to N events
52    pub fn display_first_n(&self, count: usize) -> String {
53        let mut acc = String::new();
54        let mut first = true;
55        for x in self.inner_data.iter().take(count) {
56            acc.push_str(&format!("{}{}", if first { "" } else { " " }, x));
57            first = false;
58        }
59        acc
60    }
61}
62
63impl<T> Iterator for ReplayCursor<T> {
64    type Item = T;
65
66    fn next(&mut self) -> Option<Self::Item> {
67        if self.inner_data.is_empty() {
68            None
69        } else {
70            self.inner_data.pop_front()
71        }
72    }
73}
74
75impl<T: fmt::Display> FromIterator<T> for ReplayCursor<T> {
76    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
77        let reverse_data: VecDeque<_> = VecDeque::from_iter(iter);
78        Self {
79            inner_data: reverse_data,
80        }
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use std::collections::VecDeque;
87    use std::fmt::Display;
88
89    use pretty_assertions::assert_eq;
90
91    use super::*;
92
93    fn peek_pair<T>(cursor: &ReplayCursor<T>) -> (Option<&T>, Option<&T>)
94    where
95        T: std::cmp::Eq + Display,
96    {
97        (cursor.peek_nth(0), cursor.peek_nth(1))
98    }
99
100    #[test]
101    fn test_peek() {
102        let cursor: ReplayCursor<usize> = vec![1, 2, 3, 4, 5, 6].into_iter().collect();
103        assert_eq!(cursor.peek(), Some(&1));
104    }
105
106    #[test]
107    fn test_peek_empty() {
108        let cursor = ReplayCursor::<usize> {
109            inner_data: VecDeque::new(),
110        };
111        assert_eq!(cursor.peek(), None);
112    }
113
114    #[test]
115    fn test_peek_pair() {
116        let cursor: ReplayCursor<usize> = vec![1, 2, 3].into_iter().collect();
117        assert_eq!(peek_pair(&cursor), (Some(&1), Some(&2)));
118        assert_eq!(peek_pair(&cursor), (Some(&1), Some(&2)));
119    }
120
121    #[test]
122    fn test_peek_pair_one() {
123        let cursor: ReplayCursor<usize> = vec![1].into_iter().collect();
124        assert_eq!(peek_pair(&cursor), (Some(&1), None));
125        assert_eq!(peek_pair(&cursor), (Some(&1), None));
126    }
127
128    #[test]
129    fn test_peek_pair_empty() {
130        let cursor: ReplayCursor<usize> = ReplayCursor {
131            inner_data: VecDeque::new(),
132        };
133        assert_eq!(peek_pair(&cursor), (None, None));
134        assert_eq!(peek_pair(&cursor), (None, None));
135    }
136
137    #[test]
138    fn test_next() {
139        let mut cursor: ReplayCursor<usize> = vec![1, 2, 3].into_iter().collect();
140        let result = vec![cursor.next(), cursor.next(), cursor.next(), cursor.next()];
141        assert_eq!(result, vec![Some(1), Some(2), Some(3), None]);
142    }
143
144    #[test]
145    fn test_peek_nth() {
146        let cursor: ReplayCursor<usize> = vec![1, 2, 3].into_iter().collect();
147        let result = vec![
148            cursor.peek_nth(0),
149            cursor.peek_nth(1),
150            cursor.peek_nth(2),
151            cursor.peek_nth(3),
152        ];
153        assert_eq!(result, vec![Some(&1), Some(&2), Some(&3), None]);
154    }
155}