cadmpeg_core/decode/
work_scratch.rs1use super::budget::{DecodeBudget, ScopedReservation};
5use super::error::ResourceLimit;
6
7#[derive(Debug)]
9pub struct WorkScratch<'a> {
10 reservation: Option<ScopedReservation<'a>>,
11}
12
13impl<'a> WorkScratch<'a> {
14 pub(super) fn new(
15 session: Option<&'a DecodeBudget>,
16 bytes: u64,
17 operation: &'static str,
18 ) -> Result<Self, ResourceLimit> {
19 let reservation = session
20 .map(|session| session.reserve_scoped_limit(bytes, operation))
21 .transpose()?;
22 Ok(Self { reservation })
23 }
24
25 pub fn grow(&mut self, bytes: u64) -> Result<(), ResourceLimit> {
30 if let Some(reservation) = &mut self.reservation {
31 reservation.grow_limit(bytes)?;
32 }
33 Ok(())
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use super::super::arena::DecodeArena;
40 use super::super::context::DecodeContext;
41 use super::super::error::ResourceDimension;
42 use super::super::policy::DecodePolicy;
43
44 #[test]
45 fn evaluator_scratch_tracks_live_growth_and_preserves_refusal() {
46 let mut policy = DecodePolicy::service();
47 policy.limits.max_materialized_bytes = 8;
48 let arena = DecodeArena::new();
49 let (ctx, _) =
50 DecodeContext::from_root_bytes(&[], &arena, &policy).expect("admitted test operation");
51 let budget = ctx.work_budget(10);
52 {
53 let mut scratch = budget
54 .reserve_scratch(4, "test evaluator scratch")
55 .expect("admitted test operation");
56 scratch.grow(4).expect("admitted test operation");
57 }
58 let mut scratch = budget
59 .reserve_scratch(8, "test evaluator scratch")
60 .expect("admitted test operation");
61 let error = scratch.grow(1).expect_err("test operation must refuse");
62 assert_eq!(error.dimension, ResourceDimension::MaterializedBytes);
63 assert_eq!(error.used, 8);
64 assert_eq!(error.additional, 1);
65 drop(scratch);
66 assert!(
67 matches!(ctx.finish_session(), Err(crate::CodecError::ResourceLimit(limit)) if limit == error)
68 );
69 }
70}