Skip to main content

inspect_core/
context.rs

1//! Inspection context for configuration and state.
2
3#[cfg(not(feature = "std"))]
4use alloc::collections::BTreeSet;
5#[cfg(feature = "std")]
6use std::collections::HashSet;
7
8use crate::InspectLimits;
9
10/// Context for an inspection session.
11///
12/// Carries configuration, limits, and traversal state through the
13/// inspection process to ensure safety and respect resource constraints.
14#[derive(Debug)]
15pub struct InspectCx<'a> {
16    limits: InspectLimits,
17    depth: usize,
18    nodes_visited: usize,
19    #[cfg(feature = "std")]
20    visited_addrs: HashSet<usize>,
21    #[cfg(not(feature = "std"))]
22    visited_addrs: BTreeSet<usize>,
23    _marker: core::marker::PhantomData<&'a ()>,
24}
25
26impl<'a> InspectCx<'a> {
27    /// Create a new inspection context with default limits.
28    pub fn new() -> Self {
29        Self::with_limits(InspectLimits::default())
30    }
31
32    /// Create a new inspection context with specific limits.
33    pub fn with_limits(limits: InspectLimits) -> Self {
34        Self {
35            limits,
36            depth: 0,
37            nodes_visited: 0,
38            #[cfg(feature = "std")]
39            visited_addrs: HashSet::new(),
40            #[cfg(not(feature = "std"))]
41            visited_addrs: BTreeSet::new(),
42            _marker: core::marker::PhantomData,
43        }
44    }
45
46    /// Get the configured limits.
47    pub fn limits(&self) -> &InspectLimits {
48        &self.limits
49    }
50
51    /// Get the current traversal depth.
52    pub fn depth(&self) -> usize {
53        self.depth
54    }
55
56    /// Check if the depth limit has been reached.
57    pub fn depth_exceeded(&self) -> bool {
58        self.depth >= self.limits.max_depth
59    }
60
61    /// Check if the node limit has been reached.
62    pub fn nodes_exceeded(&self) -> bool {
63        self.nodes_visited >= self.limits.max_nodes
64    }
65
66    /// Increment the node counter.
67    pub fn visit_node(&mut self) {
68        self.nodes_visited += 1;
69    }
70
71    /// Enter a deeper level of traversal.
72    pub fn enter(&mut self) -> DepthGuard<'_, 'a> {
73        self.depth += 1;
74        DepthGuard { cx: self }
75    }
76
77    /// Check if an address has been visited (cycle detection).
78    pub fn is_visited(&self, addr: usize) -> bool {
79        self.visited_addrs.contains(&addr)
80    }
81
82    /// Mark an address as visited.
83    pub fn mark_visited(&mut self, addr: usize) {
84        self.visited_addrs.insert(addr);
85    }
86}
87
88impl Default for InspectCx<'_> {
89    fn default() -> Self {
90        Self::new()
91    }
92}
93
94/// RAII guard for depth tracking.
95#[derive(Debug)]
96pub struct DepthGuard<'cx, 'a> {
97    cx: &'cx mut InspectCx<'a>,
98}
99
100impl Drop for DepthGuard<'_, '_> {
101    fn drop(&mut self) {
102        self.cx.depth -= 1;
103    }
104}
105
106impl<'cx, 'a> core::ops::Deref for DepthGuard<'cx, 'a> {
107    type Target = InspectCx<'a>;
108
109    fn deref(&self) -> &Self::Target {
110        self.cx
111    }
112}
113
114impl core::ops::DerefMut for DepthGuard<'_, '_> {
115    fn deref_mut(&mut self) -> &mut Self::Target {
116        self.cx
117    }
118}