1use crate::translation::DynTranslator;
28use crate::wave_container::{AnalogCacheKey, SignalAccessor, VariableMeta};
29use std::sync::OnceLock;
30
31pub use surfer_translation_types::{NAN_HIGHIMP, NAN_UNDEF, is_nan_highimp};
32
33#[derive(Clone, Copy, PartialEq)]
34struct MinMax {
35 min: f64,
36 max: f64,
37 has_non_finite: bool,
38}
39
40impl MinMax {
41 fn new(value: f64) -> Self {
42 if value.is_finite() {
43 Self {
44 min: value,
45 max: value,
46 has_non_finite: false,
47 }
48 } else {
49 Self {
53 min: f64::INFINITY,
54 max: f64::NEG_INFINITY,
55 has_non_finite: true,
56 }
57 }
58 }
59
60 fn combine(&self, other: &Self) -> Self {
61 Self {
62 min: self.min.min(other.min),
63 max: self.max.max(other.max),
64 has_non_finite: self.has_non_finite || other.has_non_finite,
65 }
66 }
67
68 fn from_slice(values: &[f64]) -> Self {
69 values
70 .iter()
71 .fold(Self::new(values[0]), |acc, &v| acc.combine(&Self::new(v)))
72 }
73}
74
75pub struct CacheQueryResult {
76 pub current: Option<(u64, f64)>,
77 pub next: Option<u64>,
78}
79
80struct SignalRMQ {
81 timestamps: Vec<u64>,
82 values: Vec<f64>,
83 block_size: usize,
84 sparse_table: Vec<Vec<MinMax>>,
87}
88
89impl SignalRMQ {
90 fn new(signal: impl IntoIterator<Item = (u64, f64)>, block_size: usize) -> Self {
91 let data = signal.into_iter().collect::<Vec<_>>();
92
93 debug_assert!(
94 data.windows(2).all(|w| w[1].0 > w[0].0),
95 "Timestamps must be strictly increasing"
96 );
97
98 let (timestamps, values) = data.into_iter().unzip::<u64, f64, Vec<_>, Vec<_>>();
99
100 let num_blocks = values.len().div_ceil(block_size);
101
102 let block_summaries = (0..num_blocks)
103 .map(|block_idx| {
104 let start = block_idx * block_size;
105 let end = (start + block_size).min(values.len());
106 MinMax::from_slice(&values[start..end])
107 })
108 .collect::<Vec<_>>();
109
110 let sparse_table = Self::build_sparse_table(&block_summaries);
111
112 Self {
113 timestamps,
114 values,
115 block_size,
116 sparse_table,
117 }
118 }
119
120 fn build_sparse_table(block_summaries: &[MinMax]) -> Vec<Vec<MinMax>> {
125 let num_blocks = block_summaries.len();
126 let num_levels = num_blocks.ilog2() as usize;
127
128 let mut table = vec![block_summaries.to_vec()];
130
131 for level in 0..num_levels {
132 let prev = &table[level];
133 let span = 1 << level; let next_level = (0..num_blocks)
137 .map(|i| {
138 let left = prev[i];
139 prev.get(i + span).map_or(left, |right| left.combine(right))
141 })
142 .collect::<Vec<_>>();
143
144 table.push(next_level);
145 }
146
147 table
148 }
149
150 fn query_time_range(&self, t_start: u64, t_end: u64) -> Option<MinMax> {
151 if t_start > t_end {
152 return None;
153 }
154
155 let l = self
156 .timestamps
157 .binary_search(&t_start)
158 .unwrap_or_else(|x| x);
159 let r = match self.timestamps.binary_search(&t_end) {
160 Ok(idx) => idx,
161 Err(idx) => {
162 if idx == 0 {
163 return None;
164 }
165 idx - 1
166 }
167 };
168
169 if l > r || l >= self.values.len() {
170 return None;
171 }
172
173 Some(self.query_index_range(l, r))
174 }
175
176 fn query_index_range(&self, l: usize, r: usize) -> MinMax {
177 debug_assert!(l <= r && r < self.values.len(), "Invalid index range");
178
179 let l_block = l / self.block_size;
180 let r_block = r / self.block_size;
181
182 if l_block == r_block {
183 return MinMax::from_slice(&self.values[l..=r]);
184 }
185
186 let l_block_end = (l_block + 1) * self.block_size - 1;
188 let mut result = MinMax::from_slice(&self.values[l..=l_block_end.min(r)]);
189
190 let r_block_start = r_block * self.block_size;
192 if r_block > l_block {
193 let partial = MinMax::from_slice(&self.values[r_block_start..=r]);
194 result = result.combine(&partial);
195 }
196
197 let first_full_block = l_block + 1;
199 let last_full_block = r_block - 1;
200
201 if first_full_block <= last_full_block {
202 let middle = self.query_blocks(first_full_block, last_full_block);
203 result = result.combine(&middle);
204 }
205
206 result
207 }
208
209 fn query_blocks(&self, l_block: usize, r_block: usize) -> MinMax {
210 debug_assert!(
211 l_block <= r_block,
212 "query_blocks called with l_block > r_block"
213 );
214
215 if l_block == r_block {
216 return self.sparse_table[0][l_block];
217 }
218
219 let range_len = r_block - l_block + 1;
220 let level = range_len.ilog2() as usize;
221 let jump = 1 << level;
222
223 let left = self.sparse_table[level][l_block];
224 let right = self.sparse_table[level][r_block - jump + 1];
225
226 left.combine(&right)
227 }
228
229 fn time_range(&self) -> Option<(u64, u64)> {
230 if self.timestamps.is_empty() {
231 None
232 } else {
233 Some((self.timestamps[0], *self.timestamps.last().unwrap()))
234 }
235 }
236
237 fn query_at_time(&self, time: u64) -> CacheQueryResult {
243 match self.timestamps.binary_search(&time) {
244 Ok(idx) => CacheQueryResult {
245 current: Some((self.timestamps[idx], self.values[idx])),
246 next: self.timestamps.get(idx + 1).copied(),
247 },
248 Err(0) => CacheQueryResult {
249 current: None, next: self.timestamps.first().copied(),
251 },
252 Err(idx) => CacheQueryResult {
253 current: Some((self.timestamps[idx - 1], self.values[idx - 1])),
254 next: self.timestamps.get(idx).copied(),
255 },
256 }
257 }
258}
259
260pub struct AnalogSignalCache {
262 rmq: SignalRMQ,
263 pub global_min: f64,
264 pub global_max: f64,
265 pub num_timestamps: u64,
267}
268
269impl AnalogSignalCache {
270 pub fn build(
271 accessor: SignalAccessor,
272 translator: &DynTranslator,
273 meta: &VariableMeta,
274 num_timestamps: u64,
275 block_size: Option<usize>,
276 ) -> Option<Self> {
277 let block_size = block_size.unwrap_or(64);
278
279 let mut signal_data = Vec::new();
280
281 for (time_u64, var_value) in accessor.iter_changes() {
282 let numeric = translator
283 .translate_numeric(meta, &var_value)
284 .unwrap_or(f64::NAN);
285 signal_data.push((time_u64, numeric));
286 }
287
288 if signal_data.is_empty() {
289 return None;
290 }
291
292 let rmq = SignalRMQ::new(signal_data, block_size);
293 let (first_time, last_time) = rmq.time_range()?;
294 let global = rmq.query_time_range(first_time, last_time)?;
295
296 Some(Self {
297 rmq,
298 global_min: global.min,
299 global_max: global.max,
300 num_timestamps,
301 })
302 }
303
304 #[must_use]
305 pub fn query_time_range(&self, start: u64, end: u64) -> Option<(f64, f64)> {
306 let result = self.rmq.query_time_range(start, end)?;
307 if result.has_non_finite {
308 Some((result.min, NAN_UNDEF))
310 } else {
311 Some((result.min, result.max))
312 }
313 }
314
315 #[must_use]
316 pub fn query_at_time(&self, time: u64) -> CacheQueryResult {
317 self.rmq.query_at_time(time)
318 }
319}
320
321pub struct AnalogCacheEntry {
326 inner: OnceLock<AnalogSignalCache>,
327 pub cache_key: AnalogCacheKey,
328 pub generation: u64,
329}
330
331impl AnalogCacheEntry {
332 #[must_use]
333 pub fn new(cache_key: AnalogCacheKey, generation: u64) -> Self {
334 Self {
335 inner: OnceLock::new(),
336 cache_key,
337 generation,
338 }
339 }
340
341 pub fn is_ready(&self) -> bool {
342 self.inner.get().is_some()
343 }
344
345 pub fn get(&self) -> Option<&AnalogSignalCache> {
346 self.inner.get()
347 }
348
349 pub fn set(&self, cache: AnalogSignalCache) {
350 let _ = self.inner.set(cache);
351 }
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357
358 #[test]
359 fn test_single_sample() {
360 let signal = vec![(100, 5.0)];
361 let rmq = SignalRMQ::new(signal, 64);
362
363 assert_eq!(rmq.timestamps.len(), 1);
364 assert_eq!(rmq.time_range(), Some((100, 100)));
365
366 let result = rmq.query_time_range(100, 100).unwrap();
367 assert_eq!(result.min, 5.0);
368 assert_eq!(result.max, 5.0);
369
370 assert!(rmq.query_time_range(0, 99).is_none());
371 assert!(rmq.query_time_range(101, 200).is_none());
372 }
373
374 #[test]
375 fn test_two_samples() {
376 let signal = vec![(10, 3.0), (20, 7.0)];
377 let rmq = SignalRMQ::new(signal, 64);
378
379 let result = rmq.query_time_range(10, 20).unwrap();
380 assert_eq!(result.min, 3.0);
381 assert_eq!(result.max, 7.0);
382
383 let result = rmq.query_time_range(10, 10).unwrap();
384 assert_eq!(result.min, 3.0);
385 assert_eq!(result.max, 3.0);
386
387 let result = rmq.query_time_range(20, 20).unwrap();
388 assert_eq!(result.min, 7.0);
389 assert_eq!(result.max, 7.0);
390 }
391
392 #[cfg(debug_assertions)]
393 #[test]
394 #[should_panic(expected = "Timestamps must be strictly increasing")]
395 fn test_unsorted_input() {
396 let signal = vec![(20, 7.0), (10, 3.0), (15, 5.0)];
397 SignalRMQ::new(signal, 64);
398 }
399
400 #[test]
401 fn test_irregular_timestamps() {
402 let signal = vec![
403 (1, 1.0),
404 (37, 5.0),
405 (41, 2.0),
406 (512, 8.0),
407 (513, 3.0),
408 (2080, 6.0),
409 ];
410 let rmq = SignalRMQ::new(signal, 2);
411
412 let result = rmq.query_time_range(1, 2080).unwrap();
414 assert_eq!(result.min, 1.0);
415 assert_eq!(result.max, 8.0);
416
417 let result = rmq.query_time_range(37, 513).unwrap();
419 assert_eq!(result.min, 2.0);
420 assert_eq!(result.max, 8.0);
421
422 let result = rmq.query_time_range(512, 512).unwrap();
424 assert_eq!(result.min, 8.0);
425 assert_eq!(result.max, 8.0);
426 }
427
428 #[test]
429 fn test_large_signal_multiple_blocks() {
430 let mut signal = Vec::new();
431 for i in 0..1000 {
432 signal.push((i as u64, f64::from(i % 100)));
433 }
434
435 let rmq = SignalRMQ::new(signal, 32);
436
437 let result = rmq.query_time_range(0, 999).unwrap();
439 assert_eq!(result.min, 0.0);
440 assert_eq!(result.max, 99.0);
441
442 let result = rmq.query_time_range(0, 31).unwrap();
444 assert_eq!(result.min, 0.0);
445 assert_eq!(result.max, 31.0);
446
447 let result = rmq.query_time_range(50, 150).unwrap();
449 assert_eq!(result.min, 0.0);
450 assert_eq!(result.max, 99.0);
451 }
452
453 #[test]
454 fn test_all_same_values() {
455 let signal: Vec<_> = (0..100).map(|i| (i as u64, 42.0)).collect();
456 let rmq = SignalRMQ::new(signal, 32);
457
458 let result = rmq.query_time_range(0, 99).unwrap();
459 assert_eq!(result.min, 42.0);
460 assert_eq!(result.max, 42.0);
461
462 let result = rmq.query_time_range(25, 75).unwrap();
463 assert_eq!(result.min, 42.0);
464 assert_eq!(result.max, 42.0);
465 }
466
467 #[test]
468 fn test_monotonic_increasing() {
469 let signal: Vec<_> = (0..100).map(|i| (i as u64, f64::from(i))).collect();
470 let rmq = SignalRMQ::new(signal, 32);
471
472 let result = rmq.query_time_range(0, 99).unwrap();
473 assert_eq!(result.min, 0.0);
474 assert_eq!(result.max, 99.0);
475
476 let result = rmq.query_time_range(20, 40).unwrap();
477 assert_eq!(result.min, 20.0);
478 assert_eq!(result.max, 40.0);
479 }
480
481 #[test]
482 fn test_monotonic_decreasing() {
483 let signal: Vec<_> = (0..100).map(|i| (i as u64, f64::from(99 - i))).collect();
484 let rmq = SignalRMQ::new(signal, 32);
485
486 let result = rmq.query_time_range(0, 99).unwrap();
487 assert_eq!(result.min, 0.0);
488 assert_eq!(result.max, 99.0);
489
490 let result = rmq.query_time_range(20, 40).unwrap();
491 assert_eq!(result.min, 59.0);
492 assert_eq!(result.max, 79.0);
493 }
494
495 #[test]
496 fn test_negative_values() {
497 let signal = vec![(0, -5.0), (1, 3.0), (2, -2.0), (3, 8.0), (4, -10.0)];
498 let rmq = SignalRMQ::new(signal, 2);
499
500 let result = rmq.query_time_range(0, 4).unwrap();
501 assert_eq!(result.min, -10.0);
502 assert_eq!(result.max, 8.0);
503
504 let result = rmq.query_time_range(0, 2).unwrap();
505 assert_eq!(result.min, -5.0);
506 assert_eq!(result.max, 3.0);
507 }
508
509 #[test]
510 fn test_very_large_timestamps() {
511 let signal = vec![
512 (1_000_000_000, 1.0),
513 (2_000_000_000, 5.0),
514 (3_000_000_000, 2.0),
515 (u64::MAX - 1, 10.0),
516 ];
517 let rmq = SignalRMQ::new(signal, 2);
518
519 let result = rmq.query_time_range(1_000_000_000, u64::MAX).unwrap();
520 assert_eq!(result.min, 1.0);
521 assert_eq!(result.max, 10.0);
522 }
523
524 #[test]
525 fn test_query_before_signal() {
526 let signal = vec![(100, 5.0), (200, 10.0)];
527 let rmq = SignalRMQ::new(signal, 64);
528
529 assert!(rmq.query_time_range(0, 50).is_none());
530 assert!(rmq.query_time_range(0, 99).is_none());
531 }
532
533 #[test]
534 fn test_query_after_signal() {
535 let signal = vec![(100, 5.0), (200, 10.0)];
536 let rmq = SignalRMQ::new(signal, 64);
537
538 assert!(rmq.query_time_range(300, 400).is_none());
539 }
540
541 #[test]
542 fn test_query_partial_overlap_start() {
543 let signal = vec![(100, 5.0), (200, 10.0), (300, 15.0)];
544 let rmq = SignalRMQ::new(signal, 64);
545
546 let result = rmq.query_time_range(50, 150).unwrap();
547 assert_eq!(result.min, 5.0);
548 assert_eq!(result.max, 5.0);
549 }
550
551 #[test]
552 fn test_query_partial_overlap_end() {
553 let signal = vec![(100, 5.0), (200, 10.0), (300, 15.0)];
554 let rmq = SignalRMQ::new(signal, 64);
555
556 let result = rmq.query_time_range(250, 400).unwrap();
557 assert_eq!(result.min, 15.0);
558 assert_eq!(result.max, 15.0);
559 }
560
561 #[test]
562 fn test_query_between_samples() {
563 let signal = vec![(100, 5.0), (200, 10.0), (300, 15.0)];
564 let rmq = SignalRMQ::new(signal, 64);
565
566 assert!(rmq.query_time_range(110, 190).is_none());
567 }
568
569 #[test]
570 fn test_small_block_size() {
571 let signal: Vec<_> = (0..20).map(|i| (i as u64, f64::from(i))).collect();
572 let rmq = SignalRMQ::new(signal, 2);
573
574 let result = rmq.query_time_range(0, 19).unwrap();
575 assert_eq!(result.min, 0.0);
576 assert_eq!(result.max, 19.0);
577
578 let result = rmq.query_time_range(5, 15).unwrap();
579 assert_eq!(result.min, 5.0);
580 assert_eq!(result.max, 15.0);
581 }
582
583 #[test]
584 fn test_large_block_size() {
585 let signal: Vec<_> = (0..20).map(|i| (i as u64, f64::from(i))).collect();
586 let rmq = SignalRMQ::new(signal, 100);
587
588 let result = rmq.query_time_range(0, 19).unwrap();
589 assert_eq!(result.min, 0.0);
590 assert_eq!(result.max, 19.0);
591 }
592
593 #[test]
594 fn test_floating_point_precision() {
595 let signal = vec![(0, 0.1), (1, 0.2), (2, 0.3)];
596 let rmq = SignalRMQ::new(signal, 64);
597
598 let result = rmq.query_time_range(0, 2).unwrap();
599 assert!((result.min - 0.1).abs() < 1e-10);
600 assert!((result.max - 0.3).abs() < 1e-10);
601 }
602
603 #[test]
604 fn test_special_float_values() {
605 let signal = vec![(0, 0.0), (1, -0.0), (2, 1.0)];
606 let rmq = SignalRMQ::new(signal, 64);
607
608 let result = rmq.query_time_range(0, 2).unwrap();
609 assert_eq!(result.min, 0.0);
610 assert_eq!(result.max, 1.0);
611 }
612
613 #[test]
614 fn test_query_exact_boundaries() {
615 let signal = vec![(10, 1.0), (20, 2.0), (30, 3.0), (40, 4.0)];
616 let rmq = SignalRMQ::new(signal, 2);
617
618 let result = rmq.query_time_range(20, 30).unwrap();
620 assert_eq!(result.min, 2.0);
621 assert_eq!(result.max, 3.0);
622 }
623
624 #[test]
625 fn test_index_range_query() {
626 let signal: Vec<_> = (0..100).map(|i| (i as u64, f64::from(i))).collect();
627 let rmq = SignalRMQ::new(signal, 32);
628
629 let result = rmq.query_index_range(10, 20);
630 assert_eq!(result.min, 10.0);
631 assert_eq!(result.max, 20.0);
632
633 let result = rmq.query_index_range(0, 99);
634 assert_eq!(result.min, 0.0);
635 assert_eq!(result.max, 99.0);
636 }
637
638 #[test]
639 fn test_nans_in_signal() {
640 let mut signal: Vec<_> = (0..100).map(|i| (i + i, i as f64)).collect();
641 signal[10].1 = f64::NAN;
642 let rmq = SignalRMQ::new(signal, 32);
643
644 let result = rmq.query_time_range(0, 30).unwrap();
646 assert!(result.has_non_finite);
647
648 let result = rmq.query_time_range(30, 50).unwrap();
650 assert!(!result.has_non_finite);
651 assert_eq!(result.min, 15.0);
652 assert_eq!(result.max, 25.0);
653 }
654
655 #[test]
656 fn test_all_nans() {
657 let signal: Vec<_> = (0..10).map(|i| (i as u64, f64::NAN)).collect();
658 let rmq = SignalRMQ::new(signal, 4);
659
660 let result = rmq.query_time_range(0, 9).unwrap();
661 assert!(result.has_non_finite);
662 assert_eq!(result.min, f64::INFINITY);
664 assert_eq!(result.max, f64::NEG_INFINITY);
665 }
666
667 #[test]
668 fn test_nan_propagation() {
669 let signal = vec![(0, 1.0), (1, f64::NAN), (2, 3.0)];
670 let rmq = SignalRMQ::new(signal, 64);
671
672 let result = rmq.query_time_range(0, 2).unwrap();
674 assert!(result.has_non_finite);
675
676 assert_eq!(result.min, 1.0);
679 assert_eq!(result.max, 3.0);
680
681 let result = rmq.query_time_range(2, 2).unwrap();
683 assert!(!result.has_non_finite);
684 assert_eq!(result.min, 3.0);
685 }
686
687 #[test]
688 fn test_neg_infinity_values() {
689 let signal = vec![(0, 1.0), (1, f64::NEG_INFINITY), (2, 5.0)];
690 let rmq = SignalRMQ::new(signal, 64);
691
692 let result = rmq.query_time_range(0, 2).unwrap();
693 assert!(result.has_non_finite);
694 assert_eq!(result.min, 1.0);
696 assert_eq!(result.max, 5.0);
697 }
698
699 #[test]
700 fn test_mixed_non_finite() {
701 let signal = vec![
702 (0, 1.0),
703 (1, f64::NAN),
704 (2, 3.0),
705 (3, f64::INFINITY),
706 (4, 5.0),
707 (5, f64::NEG_INFINITY),
708 (6, 2.0),
709 ];
710 let rmq = SignalRMQ::new(signal, 64);
711
712 let result = rmq.query_time_range(0, 6).unwrap();
713 assert!(result.has_non_finite);
714 assert_eq!(result.min, 1.0);
716 assert_eq!(result.max, 5.0);
717 }
718
719 #[test]
720 fn test_all_infinity() {
721 let signal = vec![
722 (0, f64::INFINITY),
723 (1, f64::NEG_INFINITY),
724 (2, f64::INFINITY),
725 ];
726 let rmq = SignalRMQ::new(signal, 64);
727
728 let result = rmq.query_time_range(0, 2).unwrap();
729 assert!(result.has_non_finite);
730 assert_eq!(result.min, f64::INFINITY);
732 assert_eq!(result.max, f64::NEG_INFINITY);
733 }
734
735 #[test]
736 fn test_single_block_query() {
737 let signal: Vec<_> = (0..10).map(|i| (i as u64, f64::from(i))).collect();
738 let rmq = SignalRMQ::new(signal, 64);
739
740 let result = rmq.query_time_range(0, 9).unwrap();
742 assert_eq!(result.min, 0.0);
743 assert_eq!(result.max, 9.0);
744 }
745
746 #[test]
747 fn test_cross_block_boundary() {
748 let signal: Vec<_> = (0..100).map(|i| (i as u64, f64::from(i))).collect();
749 let rmq = SignalRMQ::new(signal, 32);
750
751 let result = rmq.query_time_range(30, 35).unwrap();
753 assert_eq!(result.min, 30.0);
754 assert_eq!(result.max, 35.0);
755 }
756
757 #[test]
758 fn test_zigzag_pattern() {
759 let mut signal = Vec::new();
760 for i in 0..100 {
761 let value = if i % 2 == 0 { 0.0 } else { 100.0 };
762 signal.push((i as u64, value));
763 }
764 let rmq = SignalRMQ::new(signal, 16);
765
766 let result = rmq.query_time_range(0, 99).unwrap();
767 assert_eq!(result.min, 0.0);
768 assert_eq!(result.max, 100.0);
769
770 let result = rmq.query_time_range(10, 20).unwrap();
772 assert_eq!(result.min, 0.0);
773 assert_eq!(result.max, 100.0);
774 }
775
776 #[test]
777 fn test_query_at_time_exact_match() {
778 let signal = vec![(10, 1.0), (20, 2.0), (30, 3.0)];
779 let rmq = SignalRMQ::new(signal, 64);
780
781 let result = rmq.query_at_time(20);
782 assert_eq!(result.current, Some((20, 2.0)));
783 assert_eq!(result.next, Some(30));
784 }
785
786 #[test]
787 fn test_query_at_time_between_samples() {
788 let signal = vec![(10, 1.0), (20, 2.0), (30, 3.0)];
789 let rmq = SignalRMQ::new(signal, 64);
790
791 let result = rmq.query_at_time(15);
793 assert_eq!(result.current, Some((10, 1.0)));
794 assert_eq!(result.next, Some(20));
795
796 let result = rmq.query_at_time(25);
798 assert_eq!(result.current, Some((20, 2.0)));
799 assert_eq!(result.next, Some(30));
800 }
801
802 #[test]
803 fn test_query_at_time_before_first_sample() {
804 let signal = vec![(10, 1.0), (20, 2.0), (30, 3.0)];
805 let rmq = SignalRMQ::new(signal, 64);
806
807 let result = rmq.query_at_time(5);
808 assert_eq!(result.current, None);
809 assert_eq!(result.next, Some(10));
810 }
811
812 #[test]
813 fn test_query_at_time_after_last_sample() {
814 let signal = vec![(10, 1.0), (20, 2.0), (30, 3.0)];
815 let rmq = SignalRMQ::new(signal, 64);
816
817 let result = rmq.query_at_time(40);
818 assert_eq!(result.current, Some((30, 3.0)));
819 assert_eq!(result.next, None);
820 }
821
822 #[test]
823 fn test_query_at_time_single_sample() {
824 let signal = vec![(100, 5.0)];
825 let rmq = SignalRMQ::new(signal, 64);
826
827 let result = rmq.query_at_time(50);
829 assert_eq!(result.current, None);
830 assert_eq!(result.next, Some(100));
831
832 let result = rmq.query_at_time(100);
834 assert_eq!(result.current, Some((100, 5.0)));
835 assert_eq!(result.next, None);
836
837 let result = rmq.query_at_time(200);
839 assert_eq!(result.current, Some((100, 5.0)));
840 assert_eq!(result.next, None);
841 }
842
843 #[test]
844 fn test_query_at_time_at_boundaries() {
845 let signal = vec![(0, 1.0), (100, 2.0)];
846 let rmq = SignalRMQ::new(signal, 64);
847
848 let result = rmq.query_at_time(0);
850 assert_eq!(result.current, Some((0, 1.0)));
851 assert_eq!(result.next, Some(100));
852
853 let result = rmq.query_at_time(100);
855 assert_eq!(result.current, Some((100, 2.0)));
856 assert_eq!(result.next, None);
857 }
858}