1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//! Request-local planner control. No thread-local state or retained callback.
//! Every tick denotes one actually executed, counted operation. Callers flush
//! before publishing a result; dropping an interrupted plan publishes nothing.
use formualizer_common::ExcelError;
pub(crate) struct PlanControl<F> {
total: u64,
pending: u64,
checkpoint: F,
}
impl<F: FnMut(u64) -> Result<(), ExcelError>> PlanControl<F> {
/// Check cancellation before any planning allocation.
pub fn new(checkpoint: F) -> Result<Self, ExcelError> {
let mut control = Self {
total: 0,
pending: 0,
checkpoint,
};
control.flush()?;
Ok(control)
}
pub fn total(&self) -> u64 {
self.total
}
pub fn tick(&mut self) -> Result<(), ExcelError> {
self.total += 1;
self.pending += 1;
if self.pending == 4096 {
self.flush()?;
}
Ok(())
}
/// For bounded fixed-size operations such as histogram initialization.
/// Split even a crossing batch so no callback delta can exceed 4096.
pub fn charge(&mut self, mut units: u64) -> Result<(), ExcelError> {
while units != 0 {
let batch = units.min(4096 - self.pending);
self.total += batch;
self.pending += batch;
units -= batch;
if self.pending == 4096 {
self.flush()?;
}
}
Ok(())
}
pub fn flush(&mut self) -> Result<(), ExcelError> {
(self.checkpoint)(self.pending)?;
self.pending = 0;
Ok(())
}
}