inspect-core 0.1.0

Core types and traits for the inspect-rs introspection system
Documentation
//! Inspection context for configuration and state.

#[cfg(not(feature = "std"))]
use alloc::collections::BTreeSet;
#[cfg(feature = "std")]
use std::collections::HashSet;

use crate::InspectLimits;

/// Context for an inspection session.
///
/// Carries configuration, limits, and traversal state through the
/// inspection process to ensure safety and respect resource constraints.
#[derive(Debug)]
pub struct InspectCx<'a> {
    limits: InspectLimits,
    depth: usize,
    nodes_visited: usize,
    #[cfg(feature = "std")]
    visited_addrs: HashSet<usize>,
    #[cfg(not(feature = "std"))]
    visited_addrs: BTreeSet<usize>,
    _marker: core::marker::PhantomData<&'a ()>,
}

impl<'a> InspectCx<'a> {
    /// Create a new inspection context with default limits.
    pub fn new() -> Self {
        Self::with_limits(InspectLimits::default())
    }

    /// Create a new inspection context with specific limits.
    pub fn with_limits(limits: InspectLimits) -> Self {
        Self {
            limits,
            depth: 0,
            nodes_visited: 0,
            #[cfg(feature = "std")]
            visited_addrs: HashSet::new(),
            #[cfg(not(feature = "std"))]
            visited_addrs: BTreeSet::new(),
            _marker: core::marker::PhantomData,
        }
    }

    /// Get the configured limits.
    pub fn limits(&self) -> &InspectLimits {
        &self.limits
    }

    /// Get the current traversal depth.
    pub fn depth(&self) -> usize {
        self.depth
    }

    /// Check if the depth limit has been reached.
    pub fn depth_exceeded(&self) -> bool {
        self.depth >= self.limits.max_depth
    }

    /// Check if the node limit has been reached.
    pub fn nodes_exceeded(&self) -> bool {
        self.nodes_visited >= self.limits.max_nodes
    }

    /// Increment the node counter.
    pub fn visit_node(&mut self) {
        self.nodes_visited += 1;
    }

    /// Enter a deeper level of traversal.
    pub fn enter(&mut self) -> DepthGuard<'_, 'a> {
        self.depth += 1;
        DepthGuard { cx: self }
    }

    /// Check if an address has been visited (cycle detection).
    pub fn is_visited(&self, addr: usize) -> bool {
        self.visited_addrs.contains(&addr)
    }

    /// Mark an address as visited.
    pub fn mark_visited(&mut self, addr: usize) {
        self.visited_addrs.insert(addr);
    }
}

impl Default for InspectCx<'_> {
    fn default() -> Self {
        Self::new()
    }
}

/// RAII guard for depth tracking.
#[derive(Debug)]
pub struct DepthGuard<'cx, 'a> {
    cx: &'cx mut InspectCx<'a>,
}

impl Drop for DepthGuard<'_, '_> {
    fn drop(&mut self) {
        self.cx.depth -= 1;
    }
}

impl<'cx, 'a> core::ops::Deref for DepthGuard<'cx, 'a> {
    type Target = InspectCx<'a>;

    fn deref(&self) -> &Self::Target {
        self.cx
    }
}

impl core::ops::DerefMut for DepthGuard<'_, '_> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.cx
    }
}