Skip to main content

fpm_rs/callbacks/
context.rs

1use crate::{
2    Result,
3    diagnostics::{DiagnosticRequest, Diagnostics},
4    model::ImagePlaneModel,
5    reconstruction::{
6        AlgorithmMetricRecord, ReconstructionResult, ReconstructionState, ReconstructionTrace,
7    },
8};
9
10/// Control decision returned by a callback hook.
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum CallbackAction {
13    /// Continue the current reconstruction.
14    Continue,
15    /// Stop cleanly after the current hook and return a partial result.
16    Stop,
17}
18
19/// Point in runner execution at which a callback can be invoked.
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
21pub enum CallbackHook {
22    /// Once after initialization and before the first scheduled frame.
23    Start,
24    /// After a processed acquisition frame when frame callbacks are enabled.
25    FrameEnd,
26    /// After every complete acquisition schedule pass.
27    IterationEnd,
28    /// Once after a [`crate::reconstruction::ReconstructionResult`] is assembled.
29    Finish,
30}
31
32/// Borrowed reconstruction snapshot supplied to non-finish callback hooks.
33pub struct StepContext<'a> {
34    /// One-based current iteration, or zero at the start hook.
35    pub iteration: usize,
36    /// Current zero-based acquisition-frame index at frame-end hooks.
37    pub frame_index: Option<usize>,
38    /// Current zero-based batch index at frame-end hooks.
39    pub batch_index: Option<usize>,
40    /// Current mutable-run state exposed immutably to callbacks.
41    pub state: &'a ReconstructionState,
42    /// Diagnostics computed because active callbacks requested them.
43    pub diagnostics: &'a Diagnostics,
44    /// Trace of iterations completed before or at this hook.
45    pub trace: &'a ReconstructionTrace,
46    /// Algorithm-specific scalar metrics emitted for the current completed iteration.
47    pub current_algorithm_metrics: &'a [AlgorithmMetricRecord],
48    /// Compiled image-plane model used by the run.
49    pub model: &'a ImagePlaneModel,
50    /// Optional user-facing reconstruction-problem name.
51    pub problem_name: Option<&'a str>,
52}
53
54/// Thread-sendable observer or early-stop controller for reconstruction execution.
55///
56/// Implementors declare diagnostics before hooks so the runner computes only requested
57/// snapshots. Hooks receive borrowed state and cannot mutate numerical reconstruction data.
58pub trait Callback: Send {
59    /// Declares diagnostics required at every hook by legacy or non-periodic callbacks.
60    fn requires(&self) -> Vec<DiagnosticRequest> {
61        Vec::new()
62    }
63
64    /// Requests diagnostics for a specific hook. Built-in periodic callbacks
65    /// override this to avoid computing snapshots on inactive iterations.
66    fn requires_for(&self, _hook: CallbackHook, _iteration: usize) -> Vec<DiagnosticRequest> {
67        self.requires()
68    }
69
70    /// Runs once after state initialization and may stop before processing frames.
71    fn on_start(&mut self, _context: &StepContext<'_>) -> Result<CallbackAction> {
72        Ok(CallbackAction::Continue)
73    }
74
75    /// Runs once for every completed frame when frame callbacks are enabled.
76    /// For multi-frame algorithms, all frames in a batch observe the same
77    /// post-batch state while `frame_index` and natural loss remain per-frame.
78    fn on_frame_end(&mut self, _context: &StepContext<'_>) -> Result<CallbackAction> {
79        Ok(CallbackAction::Continue)
80    }
81
82    /// Runs after a complete iteration and may request clean termination.
83    fn on_iteration_end(&mut self, _context: &StepContext<'_>) -> Result<CallbackAction> {
84        Ok(CallbackAction::Continue)
85    }
86
87    /// Runs once with the final owned result; errors are propagated by the runner.
88    fn on_finish(&mut self, _result: &ReconstructionResult) -> Result<()> {
89        Ok(())
90    }
91}