src/ast/mod.rs
src/ast/mod.rs, line 1634-1684
impl Drop for Ast {
fn drop(&mut self) {
use core::mem;
match *self {
Ast::Empty(_)
| Ast::Flags(_)
| Ast::Literal(_)
| Ast::Dot(_)
| Ast::Assertion(_)
| Ast::ClassUnicode(_)
| Ast::ClassPerl(_)
// Bracketed classes are recursive, they get their own Drop impl.
| Ast::ClassBracketed(_) => return,
Ast::Repetition(ref x) if !x.ast.has_subexprs() => return,
Ast::Group(ref x) if !x.ast.has_subexprs() => return,
Ast::Alternation(ref x) if x.asts.is_empty() => return,
Ast::Concat(ref x) if x.asts.is_empty() => return,
_ => {}
}
let empty_span = || Span::splat(Position::new(0, 0, 0));
let empty_ast = || Ast::empty(empty_span());
let mut stack = vec![mem::replace(self, empty_ast())];
while let Some(mut ast) = stack.pop() {
match ast {
Ast::Empty(_)
| Ast::Flags(_)
| Ast::Literal(_)
| Ast::Dot(_)
| Ast::Assertion(_)
| Ast::ClassUnicode(_)
| Ast::ClassPerl(_)
// Bracketed classes are recursive, so they get their own Drop
// impl.
| Ast::ClassBracketed(_) => {}
Ast::Repetition(ref mut x) => {
stack.push(mem::replace(&mut x.ast, empty_ast()));
}
Ast::Group(ref mut x) => {
stack.push(mem::replace(&mut x.ast, empty_ast()));
}
Ast::Alternation(ref mut x) => {
stack.extend(x.asts.drain(..));
}
Ast::Concat(ref mut x) => {
stack.extend(x.asts.drain(..));
}
}
}
}
Ast has a custom Drop that deallocates iteratively using a heap work
stack, so destroying a deeply nested AST does not recurse and cannot overflow
the call stack. ClassSet (lines 1689 onward) and Hir (in hir/mod.rs)
carry the same iterative-drop pattern. Without these, dropping a pathological
pattern such as a few hundred thousand nested groups would recurse through the
default destructor and crash. The interval-set data structure backing
character classes (hir/interval.rs) keeps its ranges in a sorted,
non-overlapping canonical form; union, intersection, and difference are linear
merges over that form and canonicalize re-sorts in O(n log n), with no
adversarial-input degradation beyond the sort. Justifies algorithm-impl-bounds,
datastructure-impl-safe, and datastructure-impl-bounds.