From 58caad48e946e095d8f2ea0cd00943bfc606c8bc Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Wed, 11 Nov 2026 16:40:15 +0000 Subject: [PATCH] address review: each resetData call counts before batching, skipped calls' names are not prepared, and each skip cause is reported apart --- crates/engine/src/xfa.rs | 49 ++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/crates/engine/src/xfa.rs b/crates/engine/src/xfa.rs index 0a39be3374..9ad0068010 100644 --- a/crates/engine/src/xfa.rs +++ b/crates/engine/src/xfa.rs @@ -464,6 +464,8 @@ struct Runner<'a, 'b> { /// the event's time budget, which is kept as it was then: the clock is swapped before the end). resets: usize, resets_skipped: usize, + /// Of those, the ones left undone because the clock was spent, and its budget then. + resets_timed_out: usize, reset_skip_budget_ms: Option, relayouts: usize, relayouts_skipped: bool, @@ -520,6 +522,7 @@ impl<'a, 'b> Runner<'a, 'b> { skipped: 0, resets: 0, resets_skipped: 0, + resets_timed_out: 0, reset_skip_budget_ms: None, relayouts: 0, relayouts_skipped: false, @@ -787,18 +790,6 @@ impl<'a, 'b> Runner<'a, 'b> { /// `xfa.host.resetData`: the fields back to their defaults, in the form and the data. fn reset(&mut self, names: &[String]) -> Result<(), String> { - // A script may ask for thousands of resets, each a scan of the form: past a count (which - // holds where the clock can't, in the browser) or the event's time budget they are - // skipped, and the event says so. - let late = self.clock.spent(); - if late || self.resets >= MAX_RESETS_PER_EVENT { - self.resets_skipped += 1; - if late { - self.reset_skip_budget_ms = Some(self.clock.budget_ms); - } - return Ok(()); - } - self.resets += 1; self.flush()?; let by_som = self.by_som().clone(); let targets = (!names.is_empty()).then(|| ResetTargets::new(names)); @@ -963,7 +954,21 @@ impl<'a, 'b> Runner<'a, 'b> { XfaEffect::ResetData(names) => { // A script resetting several subforms in a row (`resetData` once for each) // resets them together: the same fields end up at their defaults. - pending_reset.get_or_insert_with(ResetRun::default).add(names); + // A script may ask for thousands of resets, each a scan of the form: each call + // counts, and past [`MAX_RESETS_PER_EVENT`] (which holds where the clock can't, + // in the browser) or the event's time budget it is skipped, and the event says + // so. A skipped call's names are not prepared. + let late = self.clock.spent(); + if late || self.resets >= MAX_RESETS_PER_EVENT { + self.resets_skipped += 1; + if late { + self.resets_timed_out += 1; + self.reset_skip_budget_ms = Some(self.clock.budget_ms); + } + } else { + self.resets += 1; + pending_reset.get_or_insert_with(ResetRun::default).add(names); + } let next_is_reset = effects.get(at.saturating_add(1)).is_some_and(|e| matches!(e, XfaEffect::ResetData(_))); if !next_is_reset && let Some(run) = pending_reset.take() { self.reset(run.names())?; @@ -1107,12 +1112,18 @@ impl<'a, 'b> Runner<'a, 'b> { }; self.run.out.errors.push(format!("The form's scripts were stopped: {why}; {} more were skipped", self.skipped)); } - if self.resets_skipped > 0 { - let why = match self.reset_skip_budget_ms { - Some(ms) => format!("the scripts took more than {} seconds", ms / 1000), - None => format!("more than {MAX_RESETS_PER_EVENT} resets were asked for"), - }; - self.run.out.errors.push(format!("The form's scripts were stopped: {why}; {} more resets were skipped", self.resets_skipped)); + let over_the_count = self.resets_skipped - self.resets_timed_out; + if over_the_count > 0 { + self.run.out.errors.push(format!( + "The form's scripts were stopped: more than {MAX_RESETS_PER_EVENT} resets were asked for; {over_the_count} more resets were skipped" + )); + } + if let (true, Some(ms)) = (self.resets_timed_out > 0, self.reset_skip_budget_ms) { + self.run.out.errors.push(format!( + "The form's scripts were stopped: the scripts took more than {} seconds; {} more resets were skipped", + ms / 1000, + self.resets_timed_out + )); } if self.dropped_output > 0 { self.run.out.errors.push(format!("The form's scripts produced too much output; {} more messages were left out", self.dropped_output));