Skip to main content

RecursionGuard

Struct RecursionGuard 

Source
pub struct RecursionGuard<K: Hash + Eq + Copy> { /* private fields */ }
Expand description

Tracks recursion state for cycle detection, depth limiting, and iteration bounding.

§Usage

use crate::recursion::{RecursionGuard, RecursionProfile, RecursionResult};

let mut guard = RecursionGuard::with_profile(RecursionProfile::TypeEvaluation);

match guard.enter(key) {
    RecursionResult::Entered => {
        let result = do_work();
        guard.leave(key);
        result
    }
    RecursionResult::Cycle => handle_cycle(),
    RecursionResult::DepthExceeded
    | RecursionResult::IterationExceeded => handle_exceeded(),
}

§Debug-mode safety

In debug builds (#[cfg(debug_assertions)]):

  • Dropping a guard with entries still in the visiting set panics.
  • Calling leave(key) with a key not in the visiting set panics.

Implementations§

Source§

impl<K: Hash + Eq + Copy> RecursionGuard<K>

Source

pub fn new(max_depth: u32, max_iterations: u32) -> Self

Create a guard with explicit limits.

Prefer with_profile for standard use cases.

Source

pub fn with_profile(profile: RecursionProfile) -> Self

Create a guard from a named RecursionProfile.

Source

pub const fn with_max_visiting(self, max_visiting: u32) -> Self

Builder: set a custom max visiting-set size.

Source

pub fn enter(&mut self, key: K) -> RecursionResult

Try to enter a recursive computation for key.

Returns RecursionResult::Entered if the computation may proceed. On success the caller must call leave with the same key when done.

The other variants indicate why entry was denied:

Source

pub fn leave(&mut self, key: K)

Leave a recursive computation for key.

Must be called exactly once after every successful enter.

§Debug panics

In debug builds, panics if key is not in the visiting set (double-leave or leave without matching enter).

Source

pub fn scope<T>( &mut self, key: K, f: impl FnOnce() -> T, ) -> Result<T, RecursionResult>

Execute f inside a guarded scope.

Calls enter(key), runs f if entered, then calls leave(key). Returns Ok(value) on success or Err(reason) if entry was denied.

This is the safest API when the guard is standalone (not a field of a struct that f also needs to mutate).

§Panic safety

If f panics, leave() is not called — the entry leaks. This is safe because the guard’s Drop impl (debug builds) checks std::thread::panicking() and suppresses the leak-detection panic during unwinding.

Source

pub fn is_visiting(&self, key: &K) -> bool

Check if key is currently being visited (without entering).

Source

pub fn is_visiting_any(&self, predicate: impl Fn(&K) -> bool) -> bool

Check if any currently-visiting key satisfies the predicate.

Used for symbol-level cycle detection: the same interface may appear with different DefIds in different checker contexts, so we need to check all visiting entries for symbol-level matches.

Source

pub const fn depth(&self) -> u32

Current recursion depth (number of active entries on the stack).

Source

pub const fn iterations(&self) -> u32

Total enter attempts so far (successful or not).

Source

pub fn visiting_count(&self) -> usize

Number of keys currently in the visiting set.

Source

pub const fn is_active(&self) -> bool

Returns true if the guard has any active entries.

Source

pub const fn max_depth(&self) -> u32

The configured maximum depth.

Source

pub const fn max_iterations(&self) -> u32

The configured maximum iterations.

Source

pub const fn is_exceeded(&self) -> bool

Returns true if any limit was previously exceeded.

Once set, this flag stays true until reset() is called. This is sticky: even if depth later decreases below the limit, the flag remains set. This is intentional — callers use it to bail out early on subsequent calls (e.g. TS2589 “excessively deep” diagnostics).

Source

pub const fn mark_exceeded(&mut self)

Manually mark the guard as exceeded.

Useful when an external condition (e.g. distribution size limit) means further recursion should be blocked.

Source

pub fn reset(&mut self)

Reset all state while preserving configured limits.

After reset the guard behaves as if freshly constructed.

Trait Implementations§

Source§

impl<K: Hash + Eq + Copy> Drop for RecursionGuard<K>

Available on debug-assertions enabled only.
Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl<K> Freeze for RecursionGuard<K>

§

impl<K> RefUnwindSafe for RecursionGuard<K>
where K: RefUnwindSafe,

§

impl<K> Send for RecursionGuard<K>
where K: Send,

§

impl<K> Sync for RecursionGuard<K>
where K: Sync,

§

impl<K> Unpin for RecursionGuard<K>
where K: Unpin,

§

impl<K> UnsafeUnpin for RecursionGuard<K>

§

impl<K> UnwindSafe for RecursionGuard<K>
where K: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Upcast<T> for S
where T: UpcastFrom<S> + ?Sized, S: ?Sized,

Source§

fn upcast(&self) -> &T
where Self: ErasableGeneric, T: ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider ref type within the Wasm bindgen generics type system. Read more
Source§

fn upcast_into(self) -> T
where Self: Sized + ErasableGeneric, T: ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider type within the Wasm bindgen generics type system. Read more
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more