spatial_narrative/index/
temporal.rs1use crate::core::{TimeRange, Timestamp};
29use std::collections::BTreeMap;
30
31#[derive(Debug)]
35pub struct TemporalIndex<T> {
36 tree: BTreeMap<i64, Vec<usize>>,
38 items: Vec<T>,
40 timestamps: Vec<Timestamp>,
42}
43
44impl<T: Clone> TemporalIndex<T> {
45 pub fn new() -> Self {
47 Self {
48 tree: BTreeMap::new(),
49 items: Vec::new(),
50 timestamps: Vec::new(),
51 }
52 }
53
54 pub fn from_iter<I, F>(iter: I, timestamp_fn: F) -> Self
56 where
57 I: IntoIterator<Item = T>,
58 F: Fn(&T) -> &Timestamp,
59 {
60 let mut index = Self::new();
61 for item in iter {
62 let ts = timestamp_fn(&item).clone();
63 index.insert(item, &ts);
64 }
65 index
66 }
67
68 pub fn insert(&mut self, item: T, timestamp: &Timestamp) {
70 let idx = self.items.len();
71 let key = timestamp.to_unix_millis();
72
73 self.items.push(item);
74 self.timestamps.push(timestamp.clone());
75 self.tree.entry(key).or_default().push(idx);
76 }
77
78 pub fn query_range(&self, range: &TimeRange) -> Vec<&T> {
80 let start_key = range.start.to_unix_millis();
81 let end_key = range.end.to_unix_millis();
82
83 self.tree
84 .range(start_key..=end_key)
85 .flat_map(|(_, indices)| indices.iter().map(|&i| &self.items[i]))
86 .collect()
87 }
88
89 pub fn before(&self, timestamp: &Timestamp) -> Vec<&T> {
91 let key = timestamp.to_unix_millis();
92
93 self.tree
94 .range(..key)
95 .flat_map(|(_, indices)| indices.iter().map(|&i| &self.items[i]))
96 .collect()
97 }
98
99 pub fn after(&self, timestamp: &Timestamp) -> Vec<&T> {
101 let key = timestamp.to_unix_millis();
102
103 self.tree
104 .range((key + 1)..)
105 .flat_map(|(_, indices)| indices.iter().map(|&i| &self.items[i]))
106 .collect()
107 }
108
109 pub fn at_or_before(&self, timestamp: &Timestamp) -> Vec<&T> {
111 let key = timestamp.to_unix_millis();
112
113 self.tree
114 .range(..=key)
115 .flat_map(|(_, indices)| indices.iter().map(|&i| &self.items[i]))
116 .collect()
117 }
118
119 pub fn at_or_after(&self, timestamp: &Timestamp) -> Vec<&T> {
121 let key = timestamp.to_unix_millis();
122
123 self.tree
124 .range(key..)
125 .flat_map(|(_, indices)| indices.iter().map(|&i| &self.items[i]))
126 .collect()
127 }
128
129 pub fn first(&self) -> Option<&T> {
131 self.tree
132 .iter()
133 .next()
134 .and_then(|(_, indices)| indices.first().map(|&i| &self.items[i]))
135 }
136
137 pub fn last(&self) -> Option<&T> {
139 self.tree
140 .iter()
141 .next_back()
142 .and_then(|(_, indices)| indices.last().map(|&i| &self.items[i]))
143 }
144
145 pub fn chronological(&self) -> Vec<&T> {
147 self.tree
148 .iter()
149 .flat_map(|(_, indices)| indices.iter().map(|&i| &self.items[i]))
150 .collect()
151 }
152
153 pub fn reverse_chronological(&self) -> Vec<&T> {
155 self.tree
156 .iter()
157 .rev()
158 .flat_map(|(_, indices)| indices.iter().rev().map(|&i| &self.items[i]))
159 .collect()
160 }
161
162 pub fn time_range(&self) -> Option<TimeRange> {
164 let first_key = self.tree.keys().next()?;
165 let last_key = self.tree.keys().next_back()?;
166
167 let start = Timestamp::from_unix_millis(*first_key)?;
168 let end = Timestamp::from_unix_millis(*last_key)?;
169
170 Some(TimeRange::new(start, end))
171 }
172
173 pub fn sliding_window(&self, window_size: chrono::Duration) -> SlidingWindowIter<'_, T> {
175 SlidingWindowIter {
176 index: self,
177 window_millis: window_size.num_milliseconds(),
178 current_start: self.tree.keys().next().copied(),
179 }
180 }
181
182 pub fn len(&self) -> usize {
184 self.items.len()
185 }
186
187 pub fn is_empty(&self) -> bool {
189 self.items.is_empty()
190 }
191
192 pub fn items(&self) -> &[T] {
194 &self.items
195 }
196}
197
198impl<T: Clone> Default for TemporalIndex<T> {
199 fn default() -> Self {
200 Self::new()
201 }
202}
203
204pub struct SlidingWindowIter<'a, T> {
206 index: &'a TemporalIndex<T>,
207 window_millis: i64,
208 current_start: Option<i64>,
209}
210
211impl<'a, T: Clone> Iterator for SlidingWindowIter<'a, T> {
212 type Item = Vec<&'a T>;
213
214 fn next(&mut self) -> Option<Self::Item> {
215 let start = self.current_start?;
216 let end = start + self.window_millis;
217
218 self.current_start = self.index.tree.range((start + 1)..).next().map(|(k, _)| *k);
220
221 let items: Vec<_> = self
222 .index
223 .tree
224 .range(start..end)
225 .flat_map(|(_, indices)| indices.iter().map(|&i| &self.index.items[i]))
226 .collect();
227
228 if items.is_empty() && self.current_start.is_some() {
229 self.next() } else if items.is_empty() {
231 None
232 } else {
233 Some(items)
234 }
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241
242 fn make_timestamp(hour: u32) -> Timestamp {
243 Timestamp::parse(&format!("2024-01-01T{:02}:00:00Z", hour)).unwrap()
244 }
245
246 #[test]
247 fn test_temporal_index_new() {
248 let index: TemporalIndex<String> = TemporalIndex::new();
249 assert!(index.is_empty());
250 }
251
252 #[test]
253 fn test_temporal_index_insert() {
254 let mut index = TemporalIndex::new();
255 index.insert("Morning", &make_timestamp(9));
256 index.insert("Noon", &make_timestamp(12));
257 index.insert("Evening", &make_timestamp(18));
258
259 assert_eq!(index.len(), 3);
260 }
261
262 #[test]
263 fn test_temporal_index_query_range() {
264 let mut index = TemporalIndex::new();
265 index.insert("9am", &make_timestamp(9));
266 index.insert("12pm", &make_timestamp(12));
267 index.insert("3pm", &make_timestamp(15));
268 index.insert("6pm", &make_timestamp(18));
269
270 let range = TimeRange::new(make_timestamp(11), make_timestamp(16));
271 let results = index.query_range(&range);
272
273 assert_eq!(results.len(), 2);
274 }
275
276 #[test]
277 fn test_temporal_index_before_after() {
278 let mut index = TemporalIndex::new();
279 index.insert("9am", &make_timestamp(9));
280 index.insert("12pm", &make_timestamp(12));
281 index.insert("3pm", &make_timestamp(15));
282
283 let before = index.before(&make_timestamp(12));
284 assert_eq!(before.len(), 1);
285 assert_eq!(*before[0], "9am");
286
287 let after = index.after(&make_timestamp(12));
288 assert_eq!(after.len(), 1);
289 assert_eq!(*after[0], "3pm");
290 }
291
292 #[test]
293 fn test_temporal_index_first_last() {
294 let mut index = TemporalIndex::new();
295 index.insert("First", &make_timestamp(8));
296 index.insert("Middle", &make_timestamp(12));
297 index.insert("Last", &make_timestamp(20));
298
299 assert_eq!(index.first(), Some(&"First"));
300 assert_eq!(index.last(), Some(&"Last"));
301 }
302
303 #[test]
304 fn test_temporal_index_chronological() {
305 let mut index = TemporalIndex::new();
306 index.insert("C", &make_timestamp(15));
308 index.insert("A", &make_timestamp(9));
309 index.insert("B", &make_timestamp(12));
310
311 let ordered: Vec<_> = index.chronological();
312 assert_eq!(ordered, vec![&"A", &"B", &"C"]);
313 }
314}