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:
- Prevent panics in library code - synkit never panics on edge-case numeric inputs
- Allow sentinel values - Special spans like
(0, 0)or(MAX, MAX)work safely - 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::ResourceLimitfor runtime limit checkingStreamConfigfor configuring buffer sizesParseConfig(when using recursion limits) for nesting depth