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}