pub struct RuleSnapshot {Show 21 fields
pub i: usize,
pub d: usize,
pub name: RuleName,
pub spec: Arc<RuleSpec>,
pub state: RuleState,
pub bo: bool,
pub ao: bool,
pub bc: bool,
pub ac: bool,
pub need: i32,
pub node: Rc<RefCell<Value>>,
pub parent_rule: Option<Rc<RuleSnapshot>>,
pub child_rule: Option<Rc<RuleSnapshot>>,
pub prev_rule: Option<Rc<RuleSnapshot>>,
pub next_rule: Option<Rc<RuleSnapshot>>,
pub next_rule_name: Option<RuleName>,
pub n: Rc<HashMap<String, i32>>,
pub u: Rc<HashMap<String, Value>>,
pub k: Rc<HashMap<String, Value>>,
pub o: Rc<Vec<Token>>,
pub c: Rc<Vec<Token>>,
}Fields§
§i: usize§d: usize§name: RuleName§spec: Arc<RuleSpec>§state: RuleState§bo: bool§ao: bool§bc: bool§ac: bool§need: i32§node: Rc<RefCell<Value>>§parent_rule: Option<Rc<RuleSnapshot>>§child_rule: Option<Rc<RuleSnapshot>>§prev_rule: Option<Rc<RuleSnapshot>>§next_rule: Option<Rc<RuleSnapshot>>§next_rule_name: Option<RuleName>§n: Rc<HashMap<String, i32>>§u: Rc<HashMap<String, Value>>§k: Rc<HashMap<String, Value>>§o: Rc<Vec<Token>>Matched open and close tokens. Shared rather than owned: the parse
loop only ever replaces these wholesale, and a snapshot that copied
them copied every Token’s name and source text with them.
c: Rc<Vec<Token>>Trait Implementations§
Source§impl Clone for RuleSnapshot
impl Clone for RuleSnapshot
Source§impl Debug for RuleSnapshot
impl Debug for RuleSnapshot
Source§impl Drop for RuleSnapshot
impl Drop for RuleSnapshot
Source§fn drop(&mut self)
fn drop(&mut self)
Unlink iteratively, because the derived drop recurses and the links below form a chain as long as the input.
parent_rule, child_rule, prev_rule and next_rule each own an
Rc<RuleSnapshot>, so the generated glue walks a chain with the call
stack: drop_in_place<RuleSnapshot> calls Rc::drop_slow calls
drop_in_place<RuleSnapshot> again, one frame per link. A grammar
that pushes or replaces a rule per input element builds one link per
element, so a flat JSON array of 150,000 numbers – nesting depth
ONE, nothing recursive about the document – overflowed the default
8 MiB main-thread stack and aborted the process.
Fat LTO makes it worse rather than better: inlining the cycle into
itself multiplies the per-link frame, so a default release build
survived an input that a build in the configuration rs/README.md
documents for shipping did not. That is the wrong way round, and it
is why this is a Drop impl rather than advice about stack size.
The scratch is a local rather than a thread-local. A thread-local
is faster and was wrong twice over: its key can be destroyed before
another thread-local holding a snapshot is, and touching a
destroyed key panics from inside a destructor; and re-entering this
function while its RefCell is borrowed panics too. A local is
immune to both, and the early return below means most drops never
reach it.