aozora_syntax/borrowed/mod.rs
1//! Zero-copy, arena-allocated AST.
2//!
3//! This module is the AST that the `aozora-lex` pipeline produces and
4//! that downstream consumers (`aozora-render`, `aozora`, the FFI /
5//! WASM / Python drivers) walk.
6//!
7//! # Lifetime model
8//!
9//! Every type carries a single lifetime parameter `'src`, the
10//! lifetime of the source text being parsed *and* of the arena
11//! allocator that owns the tree's storage. By convention the
12//! enclosing `Document<'src>` owns both, so `'src` is the borrow of
13//! that document.
14//!
15//! All AST types are `Copy` because they only contain `Copy` data:
16//! `&'src` references, primitives, and `Copy` enums. This means a
17//! parsed [`AozoraNode`] can be passed by value without ceremony and
18//! the visitor pattern in `aozora-render` does not need
19//! `&mut` self for traversal.
20//!
21//! # Memory ownership
22//!
23//! Construction allocates into an [`Arena`] (a thin wrapper over
24//! `bumpalo::Bump`). Every `&'src str` inside the tree points either
25//! to the arena (rewritten / synthesised text) or to the source
26//! string (zero-copy borrow of original bytes). When the arena drops,
27//! the entire tree drops as a single deallocation; per-node `Drop`
28//! never runs.
29//!
30//! # Why "borrowed"?
31//!
32//! Every type here borrows its payload from the source / arena
33//! rather than owning a heap copy. The "observable equivalence"
34//! purity contract permits arena mutation behind the scenes while
35//! keeping the public surface deterministic.
36
37mod arena;
38mod intern;
39mod non_empty;
40mod registry;
41mod types;
42
43pub use arena::Arena;
44pub use intern::{InternStats, Interner};
45pub use non_empty::{NonEmpty, NonEmptyStr};
46pub use registry::{ContainerPair, NodeRef, Registry};
47pub use types::{
48 Annotation, AozoraHeading, AozoraNode, Bouten, Content, DoubleRuby, Gaiji, HeadingHint,
49 Kaeriten, Ruby, Sashie, Segment, TateChuYoko, Warichu,
50};