///|
/// A shared, sticky work allowance for one SDK call or a caller-owned workflow.
/// Units are deterministic accounting credits, not milliseconds or heap bytes.
/// The cancellation callback must be quick and must not reenter this control.
pub struct WorkControl {
allowance : Int32
should_cancel : (String) -> Bool
mut consumed : Int32
mut stopped : String?
mut stopped_kind : WorkStopKind?
}
///|
/// Machine-readable, sticky cause; the human-readable stop_reason is unchanged.
#derive(Eq, Debug)
pub(all) enum WorkStopKind {
CancelRequested
AllowanceExhausted
}
///|
pub extend WorkStopKind with Eq::{equal, not_equal}
///|
pub extend WorkStopKind with Debug::{to_repr}
///|
pub fn WorkControl::stop_kind(self : WorkControl) -> WorkStopKind? {
self.stopped_kind
}
///|
pub fn WorkControl::default() -> WorkControl {
{
allowance: 500000000,
should_cancel: _ => false,
consumed: 0,
stopped: None,
stopped_kind: None,
}
}
///|
/// The same control may be shared by prepare/rebuild/verify to bound their sum.
/// A cancelled or exhausted control cannot be reset; create a new one to retry.
pub fn WorkControl::new(
work_units~ : Int32 = 500000000,
should_cancel~ : (String) -> Bool = _ => false,
) -> WorkControl raise {
guard work_units >= 0 && work_units <= 1000000000 else {
raise Refused("work allowance must be between 0 and 1000000000")
}
{
allowance: work_units,
should_cancel,
consumed: 0,
stopped: None,
stopped_kind: None,
}
}
///|
pub fn WorkControl::cancel(self : WorkControl) -> Unit {
if self.stopped is None {
self.stopped = Some("operation cancelled by caller")
self.stopped_kind = Some(CancelRequested)
}
}
///|
pub fn WorkControl::used(self : WorkControl) -> Int32 {
self.consumed
}
///|
pub fn WorkControl::remaining(self : WorkControl) -> Int32 {
self.allowance - self.consumed
}
///|
pub fn WorkControl::stop_reason(self : WorkControl) -> String? {
self.stopped
}
///|
fn WorkControl::poll(self : WorkControl, stage : String, units : Int32) -> Bool {
if self.stopped is Some(_) {
return true
}
if (self.should_cancel)(stage) {
self.cancel()
}
if self.stopped is Some(_) {
return true
}
if units < 0 || units > self.remaining() {
self.stopped = Some("work allowance exhausted at " + stage)
self.stopped_kind = Some(AllowanceExhausted)
return true
}
self.consumed += units
false
}
///|
fn WorkControl::checkpoint(
self : WorkControl,
stage : String,
units : Int32,
) -> Unit raise {
if self.poll(stage, units) {
raise Incomplete(self.stopped.unwrap())
}
}
///|
// Reserve bounded pairwise scans without multiplying untrusted counts first.
fn WorkControl::pairs(
self : WorkControl,
stage : String,
left : Int32,
right : Int32,
) -> Unit raise {
self.checkpoint(stage, 0)
if left > 0 && right > self.remaining() / left {
self.stopped = Some("work allowance exhausted at " + stage)
self.stopped_kind = Some(AllowanceExhausted)
raise Incomplete(self.stopped.unwrap())
}
self.checkpoint(stage, left * right)
}
///|
fn work_digest(data : BytesView, control : WorkControl) -> String raise {
control.checkpoint("hash", data.length())
let hash = digest(data)
control.checkpoint("hash-complete", 0)
hash
}