Skip to main content

subtr_actor/collector/
callback.rs

1use crate::{Collector, ReplayProcessor, SubtrActorResult, TimeAdvance};
2use boxcars;
3
4/// A lightweight collector that invokes a callback at a configurable frame cadence.
5///
6/// This is useful for side effects that should observe replay traversal without
7/// owning replay-derived state, such as progress reporting, instrumentation, or
8/// debugging hooks.
9pub struct CallbackCollector<C> {
10    callback: C,
11    frame_interval: usize,
12}
13
14impl<C> CallbackCollector<C> {
15    /// Returns the configured callback cadence in processed frames.
16    pub fn frame_interval(&self) -> usize {
17        self.frame_interval
18    }
19}
20
21impl<C> CallbackCollector<C>
22where
23    C: FnMut(&boxcars::Frame, usize, f32) -> SubtrActorResult<()>,
24{
25    /// Creates a collector that invokes the callback for every processed frame.
26    pub fn new(callback: C) -> Self {
27        Self::with_frame_interval(callback, 1)
28    }
29
30    /// Creates a collector that invokes the callback every `frame_interval`
31    /// processed frames.
32    ///
33    /// A `frame_interval` of `0` is normalized to `1`.
34    pub fn with_frame_interval(callback: C, frame_interval: usize) -> Self {
35        Self {
36            callback,
37            frame_interval: frame_interval.max(1),
38        }
39    }
40}
41
42impl<C> Collector for CallbackCollector<C>
43where
44    C: FnMut(&boxcars::Frame, usize, f32) -> SubtrActorResult<()>,
45{
46    fn process_frame(
47        &mut self,
48        _processor: &ReplayProcessor,
49        frame: &boxcars::Frame,
50        frame_number: usize,
51        current_time: f32,
52    ) -> SubtrActorResult<TimeAdvance> {
53        if frame_number.is_multiple_of(self.frame_interval) {
54            (self.callback)(frame, frame_number, current_time)?;
55        }
56
57        Ok(TimeAdvance::NextFrame)
58    }
59}