#[cfg(not(feature = "std"))]
use alloc::collections::BTreeSet;
#[cfg(feature = "std")]
use std::collections::HashSet;
use crate::InspectLimits;
#[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> {
pub fn new() -> Self {
Self::with_limits(InspectLimits::default())
}
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,
}
}
pub fn limits(&self) -> &InspectLimits {
&self.limits
}
pub fn depth(&self) -> usize {
self.depth
}
pub fn depth_exceeded(&self) -> bool {
self.depth >= self.limits.max_depth
}
pub fn nodes_exceeded(&self) -> bool {
self.nodes_visited >= self.limits.max_nodes
}
pub fn visit_node(&mut self) {
self.nodes_visited += 1;
}
pub fn enter(&mut self) -> DepthGuard<'_, 'a> {
self.depth += 1;
DepthGuard { cx: self }
}
pub fn is_visited(&self, addr: usize) -> bool {
self.visited_addrs.contains(&addr)
}
pub fn mark_visited(&mut self, addr: usize) {
self.visited_addrs.insert(addr);
}
}
impl Default for InspectCx<'_> {
fn default() -> Self {
Self::new()
}
}
#[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
}
}