1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
4pub struct ResourceLimits {
5 pub memory_limit_bytes: usize,
6 pub time_limit_ms: u64,
7 pub max_stack_depth: usize,
8 pub max_allocations: usize,
9}
10
11impl Default for ResourceLimits {
12 fn default() -> Self {
13 Self {
14 memory_limit_bytes: 32 * 1024 * 1024, time_limit_ms: 5000, max_stack_depth: 512,
17 max_allocations: 100_000,
18 }
19 }
20}
21
22#[derive(Debug, Default)]
24pub struct ResourceTracker {
25 pub allocations: usize,
26 pub current_stack_depth: usize,
27 pub peak_stack_depth: usize,
28 start_time: Option<std::time::Instant>,
29}
30
31impl ResourceTracker {
32 pub fn start(&mut self) {
33 self.start_time = Some(std::time::Instant::now());
34 }
35
36 pub fn check_time(&self, limits: &ResourceLimits) -> crate::error::Result<()> {
37 if let Some(start) = self.start_time {
38 if start.elapsed().as_millis() as u64 > limits.time_limit_ms {
39 return Err(crate::ZapcodeError::TimeLimitExceeded);
40 }
41 }
42 Ok(())
43 }
44
45 pub fn check_stack(&self, limits: &ResourceLimits) -> crate::error::Result<()> {
46 if self.current_stack_depth > limits.max_stack_depth {
47 return Err(crate::ZapcodeError::StackOverflow(self.current_stack_depth));
48 }
49 Ok(())
50 }
51
52 pub fn track_allocation(&mut self, limits: &ResourceLimits) -> crate::error::Result<()> {
53 self.allocations += 1;
54 if self.allocations > limits.max_allocations {
55 return Err(crate::ZapcodeError::AllocationLimitExceeded);
56 }
57 Ok(())
58 }
59
60 pub fn push_frame(&mut self) {
61 self.current_stack_depth += 1;
62 if self.current_stack_depth > self.peak_stack_depth {
63 self.peak_stack_depth = self.current_stack_depth;
64 }
65 }
66
67 pub fn pop_frame(&mut self) {
68 self.current_stack_depth = self.current_stack_depth.saturating_sub(1);
69 }
70}