Skip to main content

timewindow/
iter.rs

1use chrono::{DateTime, Utc};
2
3use crate::{Window, WindowSource};
4
5/// An iterator over successive upcoming windows from a [`WindowSource`].
6///
7/// This iterator repeatedly calls [`WindowSource::next_window`] and yields the
8/// returned windows in ascending start-time order.
9///
10/// # Progress semantics
11///
12/// After yielding a window, the iterator advances its internal cursor to that
13/// window's `start`, not its `end`. This is intentional: sources may produce
14/// overlapping windows, and advancing by `end` could skip valid future windows
15/// that start during an earlier yielded window.
16///
17/// Implementations of [`WindowSource::next_window`] are required to return a
18/// window whose `start` is strictly greater than the supplied cursor. As a
19/// defensive safeguard, this iterator terminates if a source returns a
20/// non-progressing window.
21///
22/// # Termination
23///
24/// The iterator ends when the source returns `None`, or when the source
25/// violates the strict-progress contract.
26pub struct NextWindows<'a, S>
27where
28    S: WindowSource,
29{
30    source: &'a S,
31    cursor: DateTime<Utc>,
32}
33
34impl<'a, S> NextWindows<'a, S>
35where
36    S: WindowSource,
37{
38    /// Creates an iterator over windows starting strictly after `from`.
39    pub fn new(source: &'a S, from: DateTime<Utc>) -> Self {
40        Self {
41            source,
42            cursor: from,
43        }
44    }
45}
46
47impl<'a, S> Iterator for NextWindows<'a, S>
48where
49    S: WindowSource,
50{
51    type Item = Window<S::Meta>;
52
53    fn next(&mut self) -> Option<Self::Item> {
54        let window = self.source.next_window(self.cursor)?;
55        if window.start <= self.cursor {
56            return None;
57        }
58        self.cursor = window.start;
59        Some(window)
60    }
61}
62
63/// Extension methods for [`WindowSource`].
64///
65/// This trait provides convenience iteration helpers for any window source.
66pub trait WindowSourceExt: WindowSource {
67    /// Returns an iterator over successive windows after `from`.
68    ///
69    /// Each yielded window is produced by repeated calls to
70    /// [`WindowSource::next_window`]. The iterator preserves overlap-aware
71    /// semantics by advancing from one yielded window's `start` to the next.
72    ///
73    /// For infinite recurring sources, this iterator may itself be infinite;
74    /// callers can combine it with adapters like [`Iterator::take`].
75    fn next_windows_from(&self, from: DateTime<Utc>) -> NextWindows<'_, Self>
76    where
77        Self: Sized,
78    {
79        NextWindows::new(self, from)
80    }
81}
82
83impl<T: WindowSource> WindowSourceExt for T {}