Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Safety & Clamping Behavior

synkit uses safe Rust throughout and employs defensive clamping to prevent panics from edge-case inputs. This page documents behaviors where invalid inputs are silently corrected rather than rejected.

Span Length Calculation

The SpanLike::len() method uses saturating subtraction:

fn len(&self) -> usize {
    self.end().saturating_sub(self.start())
}

Behavior: If end < start (an inverted span), returns 0 instead of panicking or wrapping around.

Rationale: Inverted spans can occur as sentinel values or from malformed input. Returning zero length treats them as empty spans.

Span Join

The SpanLike::join() method computes the union of two spans:

fn join(&self, other: &Self) -> Self {
    Self::new(self.start().min(other.start()), self.end().max(other.end()))
}

Behavior: Uses min() for start and max() for end. No validation that inputs are well-formed.

Rationale: Mathematical min/max cannot overflow or panic. Even inverted input spans produce a consistent result.

Incremental Buffer Consumption

The IncrementalBuffer::consume() method advances the cursor:

pub fn consume(&mut self, n: usize) {
    self.cursor = (self.cursor + n).min(self.tokens.len());
}

Behavior: If n exceeds remaining tokens, cursor clamps to buffer length.

Rationale: Allows callers to safely “consume all” by passing usize::MAX. Prevents out-of-bounds access.

Generated TokenStream Rewind

The TokenStream::rewind() method generated by parser_kit! uses clamp:

fn rewind(&mut self, pos: usize) {
    self.cursor = pos.clamp(self.range_start, self.range_end);
}

Behavior: Invalid positions are silently adjusted to the valid range [range_start, range_end].

Rationale: Parsing backtrack positions may become stale after buffer modifications. Clamping ensures the cursor remains valid.

When Clamping Matters

These behaviors are designed to:

  1. Prevent panics in library code - synkit never panics on edge-case numeric inputs
  2. Allow sentinel values - Special spans like (0, 0) or (MAX, MAX) work safely
  3. Support defensive programming - Callers don’t need to pre-validate every operation

When to Validate Explicitly

If your application requires strict validation (e.g., rejecting inverted spans), add checks at parse boundaries:

fn validate_span(span: &impl SpanLike) -> Result<(), MyError> {
    if span.end() < span.start() {
        return Err(MyError::InvalidSpan);
    }
    Ok(())
}

Resource Limits

For protection against resource exhaustion (e.g., deeply nested input), see:

  • StreamError::ResourceLimit for runtime limit checking
  • StreamConfig for configuring buffer sizes
  • ParseConfig (when using recursion limits) for nesting depth