Skip to main content

zapcode_core/
sandbox.rs

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, // 32MB
15            time_limit_ms: 5000,                  // 5s
16            max_stack_depth: 512,
17            max_allocations: 100_000,
18        }
19    }
20}
21
22/// Tracks resource usage during execution.
23#[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}