s2n_quic_core/stream/
iter.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use super::StreamId;
5#[cfg(any(test, feature = "generator"))]
6use bolero_generator::prelude::*;
7
8/// An Iterator over Stream Ids of a particular type.
9#[derive(Debug, Clone, Copy)]
10#[cfg_attr(any(feature = "generator", test), derive(TypeGenerator))]
11pub struct StreamIter {
12    start_stream_id: StreamId,
13    max_stream_id: StreamId,
14    finished: bool,
15}
16
17impl StreamIter {
18    #[inline]
19    pub fn new(start_stream_id: StreamId, max_stream_id: StreamId) -> Self {
20        debug_assert_eq!(start_stream_id.stream_type(), max_stream_id.stream_type());
21        debug_assert_eq!(start_stream_id.initiator(), max_stream_id.initiator());
22        debug_assert!(start_stream_id <= max_stream_id);
23
24        Self {
25            start_stream_id,
26            max_stream_id,
27            finished: false,
28        }
29    }
30
31    #[inline]
32    pub fn max_stream_id(self) -> StreamId {
33        self.max_stream_id
34    }
35}
36
37impl Iterator for StreamIter {
38    type Item = StreamId;
39
40    fn next(&mut self) -> Option<Self::Item> {
41        // short circuit when finished
42        if self.finished {
43            return None;
44        }
45
46        match self.start_stream_id.cmp(&self.max_stream_id) {
47            core::cmp::Ordering::Less => {
48                let ret = self.start_stream_id;
49                // The Stream ID can be expected to be valid, since `max_stream_id`
50                // is a valid `StreamId` and all IDs we iterate over are lower.
51                self.start_stream_id = self
52                    .start_stream_id
53                    .next_of_type()
54                    .expect("Expect a valid Stream ID");
55                Some(ret)
56            }
57            core::cmp::Ordering::Equal => {
58                // Avoid incrementing beyond `max_stream_id` and mark finished to
59                // to avoid returning max value again
60                self.finished = true;
61                Some(self.start_stream_id)
62            }
63            core::cmp::Ordering::Greater => {
64                debug_assert!(false, "The `new` method should verify valid ranges");
65
66                // finished
67                self.finished = true;
68                None
69            }
70        }
71    }
72}
73
74#[cfg(test)]
75mod fuzz_target {
76    use super::*;
77
78    #[test]
79    #[cfg_attr(miri, ignore)] // This test is too expensive for miri to complete in a reasonable amount of time
80    #[cfg_attr(kani, kani::proof, kani::unwind(1), kani::solver(kissat))]
81    fn fuzz_builder() {
82        bolero::check!()
83            .with_type::<(StreamId, StreamId)>()
84            .cloned()
85            .for_each(|(min, max)| {
86                // enforce min <= max
87                if min > max {
88                    return;
89                }
90                // enforce same initiator type
91                if min.initiator() != max.initiator() {
92                    return;
93                }
94                // enforce same stream type
95                if min.stream_type() != max.stream_type() {
96                    return;
97                }
98
99                // All other combinations of min/max StreamId should be valid
100                StreamIter::new(min, max);
101            });
102    }
103}