Skip to main content

tj_core/dream/
scope.rs

1//! Resolve which session transcripts are in scope for a dream run.
2
3use std::time::SystemTime;
4
5/// A discovered session with its file modification time.
6pub struct SessionFile {
7    pub path: std::path::PathBuf,
8    pub mtime: SystemTime,
9}
10
11/// Keep sessions modified strictly after `since` (the watermark as a
12/// SystemTime). When `since` is None, all sessions are in scope.
13/// `limit` (when Some) caps the result to the newest N.
14pub fn in_scope(
15    mut sessions: Vec<SessionFile>,
16    since: Option<SystemTime>,
17    limit: Option<usize>,
18) -> Vec<std::path::PathBuf> {
19    sessions.sort_by_key(|s| std::cmp::Reverse(s.mtime));
20    let mut out: Vec<std::path::PathBuf> = sessions
21        .into_iter()
22        .filter(|s| match since {
23            Some(t) => s.mtime > t,
24            None => true,
25        })
26        .map(|s| s.path)
27        .collect();
28    if let Some(n) = limit {
29        out.truncate(n);
30    }
31    out
32}
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37    use std::time::Duration;
38
39    fn at(secs: u64) -> SystemTime {
40        SystemTime::UNIX_EPOCH + Duration::from_secs(secs)
41    }
42
43    #[test]
44    fn filters_by_since_and_caps_by_limit() {
45        let s = vec![
46            SessionFile {
47                path: "a".into(),
48                mtime: at(100),
49            },
50            SessionFile {
51                path: "b".into(),
52                mtime: at(200),
53            },
54            SessionFile {
55                path: "c".into(),
56                mtime: at(300),
57            },
58        ];
59        // since = 150 → keeps b(200) and c(300), newest first
60        let r = in_scope(s, Some(at(150)), None);
61        assert_eq!(
62            r,
63            vec![std::path::PathBuf::from("c"), std::path::PathBuf::from("b")]
64        );
65    }
66
67    #[test]
68    fn none_since_keeps_all_limit_caps() {
69        let s = vec![
70            SessionFile {
71                path: "a".into(),
72                mtime: at(100),
73            },
74            SessionFile {
75                path: "b".into(),
76                mtime: at(200),
77            },
78            SessionFile {
79                path: "c".into(),
80                mtime: at(300),
81            },
82        ];
83        let r = in_scope(s, None, Some(2));
84        assert_eq!(
85            r,
86            vec![std::path::PathBuf::from("c"), std::path::PathBuf::from("b")]
87        );
88    }
89}