Skip to main content

retex_engine/
nodes.rs

1//! Node memory: an arena of typesetting nodes addressed by [`NodeRef`].
2//!
3//! The node model mirrors LuaTeX's. Node type ids, subtypes and field sets
4//! are those that LuaTeX's `node` library reports (see
5//! `data/luatex-node-types.txt`). Lists are doubly linked through `next` and
6//! `prev`. List heads in the semantic nest are `temp` nodes, as in TeX.
7
8use std::rc::Rc;
9
10use crate::glue::Glue;
11use crate::token::TokenList;
12
13/// LuaTeX's node types, fields and subtypes, as `node.types()`,
14/// `node.fields()` and `node.subtypes()` report them
15/// (`data/luatex-node-types.txt`, see `data/README.md`).
16pub const LUATEX_NODE_TYPES: &str = include_str!("../data/luatex-node-types.txt");
17
18/// A reference to a node in the node arena; `NodeRef::NULL` is the empty
19/// list.
20#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, PartialOrd, Ord)]
21pub struct NodeRef(pub u32);
22
23impl NodeRef {
24    /// The null pointer.
25    pub const NULL: NodeRef = NodeRef(0);
26
27    /// Whether this is the null pointer.
28    #[inline]
29    pub const fn is_null(self) -> bool {
30        self.0 == 0
31    }
32}
33
34/// A "running" rule dimension (TeX's `null_flag`, −2³⁰).
35pub const RUNNING: i32 = -0o10000000000;
36
37/// Node type ids, numbered as LuaTeX's `node.types()`.
38#[allow(missing_docs)]
39pub mod id {
40    pub const HLIST: u8 = 0;
41    pub const VLIST: u8 = 1;
42    pub const RULE: u8 = 2;
43    pub const INS: u8 = 3;
44    pub const MARK: u8 = 4;
45    pub const ADJUST: u8 = 5;
46    pub const BOUNDARY: u8 = 6;
47    pub const DISC: u8 = 7;
48    pub const WHATSIT: u8 = 8;
49    pub const LOCAL_PAR: u8 = 9;
50    pub const DIR: u8 = 10;
51    pub const MATH: u8 = 11;
52    pub const GLUE: u8 = 12;
53    pub const KERN: u8 = 13;
54    pub const PENALTY: u8 = 14;
55    pub const UNSET: u8 = 15;
56    pub const STYLE: u8 = 16;
57    pub const CHOICE: u8 = 17;
58    pub const NOAD: u8 = 18;
59    pub const RADICAL: u8 = 19;
60    pub const FRACTION: u8 = 20;
61    pub const ACCENT: u8 = 21;
62    pub const FENCE: u8 = 22;
63    pub const MATH_CHAR: u8 = 23;
64    pub const SUB_BOX: u8 = 24;
65    pub const SUB_MLIST: u8 = 25;
66    pub const MATH_TEXT_CHAR: u8 = 26;
67    pub const DELIM: u8 = 27;
68    pub const MARGIN_KERN: u8 = 28;
69    pub const GLYPH: u8 = 29;
70    pub const ALIGN_RECORD: u8 = 30;
71    pub const PAGE_INSERT: u8 = 33;
72    pub const SPLIT_INSERT: u8 = 34;
73    pub const TEMP: u8 = 41;
74}
75
76/// Glue subtypes (LuaTeX numbering).
77#[allow(missing_docs)]
78pub mod glue_sub {
79    pub const USER: u16 = 0;
80    pub const LINE_SKIP: u16 = 1;
81    pub const BASELINE_SKIP: u16 = 2;
82    pub const PAR_SKIP: u16 = 3;
83    pub const ABOVE_DISPLAY: u16 = 4;
84    pub const BELOW_DISPLAY: u16 = 5;
85    pub const ABOVE_DISPLAY_SHORT: u16 = 6;
86    pub const BELOW_DISPLAY_SHORT: u16 = 7;
87    pub const LEFT_SKIP: u16 = 8;
88    pub const RIGHT_SKIP: u16 = 9;
89    pub const TOP_SKIP: u16 = 10;
90    pub const SPLIT_TOP_SKIP: u16 = 11;
91    pub const TAB_SKIP: u16 = 12;
92    pub const SPACE_SKIP: u16 = 13;
93    pub const XSPACE_SKIP: u16 = 14;
94    pub const PAR_FILL_SKIP: u16 = 15;
95    pub const MATH_SKIP: u16 = 16;
96    pub const THIN_MU_SKIP: u16 = 17;
97    pub const MED_MU_SKIP: u16 = 18;
98    pub const THICK_MU_SKIP: u16 = 19;
99    pub const COND_MATH_GLUE: u16 = 98;
100    pub const MU_GLUE: u16 = 99;
101    pub const A_LEADERS: u16 = 100;
102    pub const C_LEADERS: u16 = 101;
103    pub const X_LEADERS: u16 = 102;
104    pub const G_LEADERS: u16 = 103;
105}
106
107/// Kern subtypes.
108#[allow(missing_docs)]
109pub mod kern_sub {
110    pub const FONT: u16 = 0;
111    pub const USER: u16 = 1;
112    pub const ACCENT: u16 = 2;
113    pub const ITALIC: u16 = 3;
114}
115
116/// Glyph subtypes (bit flags).
117#[allow(missing_docs)]
118pub mod glyph_sub {
119    pub const CHARACTER: u16 = 1;
120    pub const LIGATURE: u16 = 2;
121    pub const GHOST: u16 = 4;
122    pub const LEFT: u16 = 8;
123    pub const RIGHT: u16 = 16;
124}
125
126/// Whatsit subtypes.
127#[allow(missing_docs)]
128pub mod whatsit_sub {
129    pub const OPEN: u16 = 0;
130    pub const WRITE: u16 = 1;
131    pub const CLOSE: u16 = 2;
132    pub const SPECIAL: u16 = 3;
133    pub const LATE_SPECIAL: u16 = 4;
134    pub const SAVE_POS: u16 = 7;
135    pub const LATE_LUA: u16 = 8;
136    pub const USER_DEFINED: u16 = 9;
137    pub const PDF_LITERAL: u16 = 16;
138    pub const PDF_LATE_LITERAL: u16 = 17;
139    pub const PDF_REFOBJ: u16 = 18;
140    pub const PDF_ANNOT: u16 = 19;
141    pub const PDF_START_LINK: u16 = 20;
142    pub const PDF_END_LINK: u16 = 21;
143    pub const PDF_DEST: u16 = 22;
144    pub const PDF_ACTION: u16 = 23;
145    pub const PDF_THREAD: u16 = 24;
146    pub const PDF_START_THREAD: u16 = 25;
147    pub const PDF_END_THREAD: u16 = 26;
148    pub const PDF_COLORSTACK: u16 = 29;
149    pub const PDF_SETMATRIX: u16 = 30;
150    pub const PDF_SAVE: u16 = 31;
151    pub const PDF_RESTORE: u16 = 32;
152    pub const PDF_LINK_STATE: u16 = 33;
153}
154
155/// A list of attribute (number, value) pairs, sorted by number.
156pub type AttrList = Rc<[(u32, i32)]>;
157
158/// Box fields shared by hlist and vlist nodes.
159#[derive(Clone, Debug, Default, PartialEq)]
160pub struct BoxData {
161    /// Width.
162    pub width: i32,
163    /// Depth.
164    pub depth: i32,
165    /// Height.
166    pub height: i32,
167    /// Direction (0 = TLT).
168    pub dir: i8,
169    /// Shift amount.
170    pub shift: i32,
171    /// Glue order of the setting.
172    pub glue_order: u8,
173    /// Glue sign: 0 normal, 1 stretching, 2 shrinking.
174    pub glue_sign: u8,
175    /// Glue set ratio. LuaTeX keeps it in single precision, so computed
176    /// ratios are rounded to `f32` (see [`glue_ratio`]).
177    pub glue_set: f64,
178    /// The list.
179    pub head: NodeRef,
180}
181
182/// Fields of a glyph node.
183#[derive(Clone, Debug, Default, PartialEq)]
184pub struct GlyphData {
185    /// The character.
186    pub chr: u32,
187    /// The font.
188    pub font: u32,
189    /// The language.
190    pub lang: u16,
191    /// `\lefthyphenmin` for this glyph.
192    pub left: u8,
193    /// `\righthyphenmin` for this glyph.
194    pub right: u8,
195    /// `\uchyph`.
196    pub uchyph: bool,
197    /// Ligature components.
198    pub components: NodeRef,
199    /// Horizontal offset.
200    pub xoffset: i32,
201    /// Vertical offset.
202    pub yoffset: i32,
203    /// Font expansion factor.
204    pub expansion_factor: i32,
205    /// User data.
206    pub data: i32,
207}
208
209/// Type-specific node data.
210#[derive(Clone, Debug, PartialEq)]
211pub enum NodeData {
212    /// A list head or other temporary node.
213    Temp,
214    /// An hlist or vlist (`id` tells which).
215    Box(Box<BoxData>),
216    /// A rule.
217    Rule {
218        /// Width (or "running").
219        width: i32,
220        /// Depth.
221        depth: i32,
222        /// Height.
223        height: i32,
224        /// Direction.
225        dir: i8,
226        /// Resource index (box/image rules).
227        index: i32,
228        /// Left offset.
229        left: i32,
230        /// Right offset.
231        right: i32,
232    },
233    /// An insertion.
234    Ins {
235        /// `\floatingpenalty`.
236        cost: i32,
237        /// Depth.
238        depth: i32,
239        /// Natural height plus depth.
240        height: i32,
241        /// `\splittopskip`.
242        spec: Glue,
243        /// The vertical list.
244        head: NodeRef,
245    },
246    /// A mark.
247    Mark {
248        /// The marks class.
249        class: u32,
250        /// The token list.
251        mark: TokenList,
252    },
253    /// A `\vadjust`.
254    Adjust {
255        /// The vertical list.
256        head: NodeRef,
257    },
258    /// A boundary.
259    Boundary {
260        /// The value.
261        value: i32,
262    },
263    /// A discretionary.
264    Disc {
265        /// Pre-break list.
266        pre: NodeRef,
267        /// Post-break list.
268        post: NodeRef,
269        /// Replacement list.
270        replace: NodeRef,
271        /// Penalty.
272        penalty: i32,
273    },
274    /// A whatsit.
275    Whatsit(Box<Whatsit>),
276    /// A local paragraph node.
277    LocalPar {
278        /// `\localinterlinepenalty`.
279        pen_inter: i32,
280        /// `\localbrokenpenalty`.
281        pen_broken: i32,
282        /// Paragraph direction.
283        dir: i8,
284        /// `\localleftbox`.
285        box_left: NodeRef,
286        /// Its width.
287        box_left_width: i32,
288        /// `\localrightbox`.
289        box_right: NodeRef,
290        /// Its width.
291        box_right_width: i32,
292    },
293    /// A direction change.
294    Dir {
295        /// The direction.
296        dir: i8,
297        /// The group level.
298        level: i32,
299    },
300    /// Math on/off.
301    Math {
302        /// `\mathsurround`.
303        surround: i32,
304        /// `\mathsurroundskip` as glue.
305        glue: Glue,
306    },
307    /// Glue.
308    Glue {
309        /// The specification.
310        spec: Glue,
311        /// Leader box or rule.
312        leader: NodeRef,
313    },
314    /// A kern.
315    Kern {
316        /// The amount.
317        kern: i32,
318        /// Font expansion factor.
319        expansion_factor: i32,
320    },
321    /// A penalty.
322    Penalty {
323        /// The penalty.
324        penalty: i32,
325    },
326    /// An unset box in an alignment.
327    Unset {
328        /// Box fields (glue_set unused).
329        b: Box<BoxData>,
330        /// Number of spanned columns minus one.
331        span_count: u16,
332        /// Total stretch.
333        stretch: i32,
334        /// Total shrink.
335        shrink: i32,
336        /// Stretch order.
337        stretch_order: u8,
338        /// Shrink order.
339        shrink_order: u8,
340    },
341    /// A glyph (stored inline: glyphs are the most frequent nodes).
342    Glyph(GlyphData),
343    /// A margin kern.
344    MarginKern {
345        /// Width.
346        width: i32,
347        /// The glyph it belongs to.
348        glyph: NodeRef,
349    },
350    /// A noad (`noad`, `radical` and `accent` ids).
351    Noad(Box<NoadData>),
352    /// A generalized fraction noad.
353    Fraction(Box<FractionData>),
354    /// A `\left`, `\middle` or `\right` noad.
355    Fence(Box<FenceData>),
356    /// A style node (`\displaystyle` …); the style is 0–7 as in TeX.
357    Style {
358        /// The style.
359        style: u8,
360    },
361    /// A `\mathchoice` node: display, text, script and scriptscript lists.
362    Choice(Box<[NodeRef; 4]>),
363    /// A `math_char` or `math_text_char` kernel.
364    MathChar {
365        /// The family.
366        fam: u32,
367        /// The character.
368        chr: u32,
369    },
370    /// A `sub_box` or `sub_mlist` kernel.
371    SubList {
372        /// The box (sub_box) or the mlist (sub_mlist).
373        head: NodeRef,
374    },
375    /// A delimiter specification (`delim` node).
376    Delim {
377        /// Family of the small variant.
378        small_fam: u32,
379        /// Character of the small variant.
380        small_char: u32,
381        /// Family of the large variant.
382        large_fam: u32,
383        /// Character of the large variant.
384        large_char: u32,
385    },
386    /// Nodes not modelled in detail.
387    Other(Vec<i64>),
388}
389
390/// Fields of a noad (LuaTeX's `noad`, `radical` and `accent` nodes). The
391/// nucleus and the scripts are kernel nodes (`math_char`,
392/// `math_text_char`, `sub_box`, `sub_mlist`), or null when empty.
393#[derive(Clone, Debug, Default, PartialEq)]
394pub struct NoadData {
395    /// The nucleus.
396    pub nucleus: NodeRef,
397    /// The subscript.
398    pub sub: NodeRef,
399    /// The superscript.
400    pub sup: NodeRef,
401    /// Rendering options (LuaTeX's option bits).
402    pub options: u32,
403    /// Radicals: the delimiter (a `delim` node).
404    pub left: NodeRef,
405    /// Radicals: the degree of `\Uroot`.
406    pub degree: NodeRef,
407    /// Radicals: the requested width (`\Uhextensible`, `width` keyword).
408    pub width: i32,
409    /// Accents: the top accent (a `math_char` kernel).
410    pub accent: NodeRef,
411    /// Accents: the bottom accent.
412    pub bot_accent: NodeRef,
413    /// Accents: the `fraction` criterion (0 when not given).
414    pub fraction: i32,
415    /// The translation into an hlist (`new_hlist`), during
416    /// `mlist_to_hlist`.
417    pub new_hlist: NodeRef,
418}
419
420/// Fields of a generalized fraction noad.
421#[derive(Clone, Debug, PartialEq)]
422pub struct FractionData {
423    /// Rule thickness, or [`DEFAULT_CODE`].
424    pub thickness: i32,
425    /// The numerator (a `sub_mlist` kernel).
426    pub num: NodeRef,
427    /// The denominator (a `sub_mlist` kernel).
428    pub denom: NodeRef,
429    /// Left delimiter (`delim` node) or null.
430    pub left: NodeRef,
431    /// Right delimiter or null.
432    pub right: NodeRef,
433    /// Middle delimiter (`\Uskewed`) or null.
434    pub middle: NodeRef,
435    /// Rendering options.
436    pub options: u32,
437    /// The translation (`new_hlist`).
438    pub new_hlist: NodeRef,
439}
440
441/// Fields of a fence noad (`\left`, `\middle`, `\right`).
442#[derive(Clone, Debug, Default, PartialEq)]
443pub struct FenceData {
444    /// The delimiter (a `delim` node).
445    pub delim: NodeRef,
446    /// Italic correction.
447    pub italic: i32,
448    /// Requested height (0 when not given).
449    pub height: i32,
450    /// Requested depth.
451    pub depth: i32,
452    /// Rendering options.
453    pub options: u32,
454    /// Spacing class (−1 when not given).
455    pub class: i32,
456    /// The translation (`new_hlist`).
457    pub new_hlist: NodeRef,
458}
459
460/// The fraction thickness meaning "the default rule thickness"
461/// (`default_code`).
462pub const DEFAULT_CODE: i32 = 0o10000000000;
463
464/// Noad subtypes (LuaTeX numbering).
465#[allow(missing_docs)]
466pub mod noad_sub {
467    pub const ORD: u16 = 0;
468    pub const OP_DISPLAY_LIMITS: u16 = 1;
469    pub const OP_LIMITS: u16 = 2;
470    pub const OP_NO_LIMITS: u16 = 3;
471    pub const BIN: u16 = 4;
472    pub const REL: u16 = 5;
473    pub const OPEN: u16 = 6;
474    pub const CLOSE: u16 = 7;
475    pub const PUNCT: u16 = 8;
476    pub const INNER: u16 = 9;
477    pub const UNDER: u16 = 10;
478    pub const OVER: u16 = 11;
479    pub const VCENTER: u16 = 12;
480}
481
482/// Radical subtypes.
483#[allow(missing_docs)]
484pub mod radical_sub {
485    pub const RADICAL: u16 = 0;
486    pub const URADICAL: u16 = 1;
487    pub const UROOT: u16 = 2;
488    pub const UUNDERDELIMITER: u16 = 3;
489    pub const UOVERDELIMITER: u16 = 4;
490    pub const UDELIMITERUNDER: u16 = 5;
491    pub const UDELIMITEROVER: u16 = 6;
492    pub const UHEXTENSIBLE: u16 = 7;
493}
494
495/// Fence subtypes.
496#[allow(missing_docs)]
497pub mod fence_sub {
498    pub const UNSET: u16 = 0;
499    pub const LEFT: u16 = 1;
500    pub const MIDDLE: u16 = 2;
501    pub const RIGHT: u16 = 3;
502    pub const NO: u16 = 4;
503}
504
505/// Accent subtypes.
506#[allow(missing_docs)]
507pub mod accent_sub {
508    pub const BOTH_FLEXIBLE: u16 = 0;
509    pub const FIXED_TOP: u16 = 1;
510    pub const FIXED_BOTTOM: u16 = 2;
511    pub const FIXED_BOTH: u16 = 3;
512}
513
514/// Noad option bits (LuaTeX manual, "Math core nodes").
515#[allow(missing_docs)]
516pub mod noad_opt {
517    pub const SET: u32 = 0x08;
518    pub const AXIS: u32 = 0x02 | SET;
519    pub const NO_AXIS: u32 = 0x04 | SET;
520    pub const EXACT: u32 = 0x10 | SET;
521    pub const LEFT: u32 = 0x11 | SET;
522    pub const MIDDLE: u32 = 0x12 | SET;
523    pub const RIGHT: u32 = 0x14 | SET;
524    pub const NO_SUB_SCRIPT: u32 = 0x21 | SET;
525    pub const NO_SUPER_SCRIPT: u32 = 0x22 | SET;
526    /// retex: an overlay accent (`\Umathaccent overlay`).
527    pub const OVERLAY: u32 = 0x100;
528}
529
530/// Whatsit payloads.
531#[derive(Clone, Debug, PartialEq)]
532pub enum Whatsit {
533    /// `\openout`.
534    Open {
535        /// Stream number.
536        stream: u32,
537        /// File name.
538        name: Vec<u8>,
539    },
540    /// `\write`.
541    Write {
542        /// Stream number.
543        stream: i32,
544        /// Unexpanded token list.
545        data: TokenList,
546    },
547    /// `\closeout`.
548    Close {
549        /// Stream number.
550        stream: u32,
551    },
552    /// `\special`.
553    Special {
554        /// The text.
555        data: Vec<u8>,
556    },
557    /// `\latelua`.
558    LateLua {
559        /// Token list or string.
560        data: LateData,
561        /// Chunk name.
562        name: Vec<u8>,
563    },
564    /// `\pdfextension literal` and friends.
565    PdfLiteral {
566        /// Mode (0 origin, 1 page, 2 direct, …).
567        mode: u8,
568        /// Data.
569        data: LateData,
570        /// Whether this is a late literal.
571        late: bool,
572    },
573    /// `\savepos`.
574    SavePos,
575    /// `\pdfextension colorstack`.
576    PdfColorstack {
577        /// Stack number.
578        stack: i32,
579        /// Command (set, push, pop, current).
580        cmd: u8,
581        /// Data.
582        data: Vec<u8>,
583    },
584    /// `\pdfextension setmatrix`.
585    PdfSetmatrix {
586        /// The matrix text.
587        data: Vec<u8>,
588    },
589    /// `\pdfextension save`.
590    PdfSave,
591    /// `\pdfextension restore`.
592    PdfRestore,
593    /// `\pdfextension annot`.
594    PdfAnnot {
595        /// `width`, `height`, `depth` ([`RUNNING`] when not given).
596        dims: [i32; 3],
597        /// The annotation's object number.
598        objnum: i32,
599        /// The annotation's text.
600        data: Vec<u8>,
601    },
602    /// `\pdfextension startlink`.
603    PdfStartLink {
604        /// `width`, `height`, `depth` ([`RUNNING`] when not given).
605        dims: [i32; 3],
606        /// The object number of the link's first annotation.
607        objnum: i32,
608        /// `attr {…}`.
609        attr: Vec<u8>,
610        /// The action.
611        action: crate::pdfext::PdfAction,
612    },
613    /// `\pdfextension endlink`.
614    PdfEndLink,
615    /// `\pdfextension dest`.
616    PdfDest {
617        /// The destination's identifier.
618        id: crate::pdfext::DestId,
619        /// The view.
620        view: crate::pdfext::DestView,
621    },
622    /// `\pdfextension refobj`.
623    PdfRefobj {
624        /// The object number.
625        objnum: i32,
626    },
627    /// Other whatsits, kept opaque for now.
628    Other {
629        /// Raw fields.
630        fields: Vec<i64>,
631        /// Raw data.
632        data: Vec<u8>,
633    },
634}
635
636/// Data of late whatsits: an unexpanded token list or a string.
637#[derive(Clone, Debug, PartialEq)]
638pub enum LateData {
639    /// Tokens, expanded at shipout.
640    Tokens(TokenList),
641    /// An already expanded string.
642    Bytes(Vec<u8>),
643}
644
645/// A node.
646#[derive(Clone, Debug, PartialEq)]
647pub struct Node {
648    /// The type id.
649    pub id: u8,
650    /// The subtype.
651    pub subtype: u16,
652    /// Next node in the list.
653    pub next: NodeRef,
654    /// Previous node in the list.
655    pub prev: NodeRef,
656    /// Attributes.
657    pub attr: Option<AttrList>,
658    /// Type-specific data.
659    pub data: NodeData,
660}
661
662/// The node arena.
663#[derive(Debug, Clone)]
664pub struct Nodes {
665    nodes: Vec<Node>,
666    free: Vec<u32>,
667    /// Number of nodes in use.
668    pub in_use: usize,
669}
670
671impl Default for Nodes {
672    fn default() -> Self {
673        Self::new()
674    }
675}
676
677impl Nodes {
678    /// An arena with only the null node.
679    pub fn new() -> Self {
680        Nodes {
681            nodes: vec![Node {
682                id: id::TEMP,
683                subtype: 0,
684                next: NodeRef::NULL,
685                prev: NodeRef::NULL,
686                attr: None,
687                data: NodeData::Temp,
688            }],
689            free: Vec::new(),
690            in_use: 0,
691        }
692    }
693
694    /// The number of node slots in the arena.
695    pub fn capacity(&self) -> usize {
696        self.nodes.len()
697    }
698
699    /// Allocates a node.
700    pub fn alloc(&mut self, id: u8, subtype: u16, data: NodeData) -> NodeRef {
701        let node = Node {
702            id,
703            subtype,
704            next: NodeRef::NULL,
705            prev: NodeRef::NULL,
706            attr: None,
707            data,
708        };
709        self.in_use += 1;
710        if let Some(i) = self.free.pop() {
711            self.nodes[i as usize] = node;
712            NodeRef(i)
713        } else {
714            self.nodes.push(node);
715            NodeRef(self.nodes.len() as u32 - 1)
716        }
717    }
718
719    /// Frees a single node (not its sublists).
720    pub fn free(&mut self, p: NodeRef) {
721        if p.is_null() {
722            return;
723        }
724        self.nodes[p.0 as usize].data = NodeData::Temp;
725        self.nodes[p.0 as usize].attr = None;
726        self.free.push(p.0);
727        self.in_use -= 1;
728    }
729
730    /// The node at `p`.
731    #[inline]
732    pub fn get(&self, p: NodeRef) -> &Node {
733        &self.nodes[p.0 as usize]
734    }
735
736    /// The node at `p`, mutably.
737    #[inline]
738    pub fn get_mut(&mut self, p: NodeRef) -> &mut Node {
739        &mut self.nodes[p.0 as usize]
740    }
741
742    /// The type id of `p`.
743    #[inline]
744    pub fn id(&self, p: NodeRef) -> u8 {
745        self.nodes[p.0 as usize].id
746    }
747
748    /// The `next` link of `p`.
749    #[inline]
750    pub fn next(&self, p: NodeRef) -> NodeRef {
751        self.nodes[p.0 as usize].next
752    }
753
754    /// Links `q` after `p` (sets `p.next` and `q.prev`).
755    #[inline]
756    pub fn link(&mut self, p: NodeRef, q: NodeRef) {
757        self.nodes[p.0 as usize].next = q;
758        if !q.is_null() {
759            self.nodes[q.0 as usize].prev = p;
760        }
761    }
762
763    /// The box data of an hlist/vlist node.
764    pub fn box_data(&self, p: NodeRef) -> Option<&BoxData> {
765        match &self.nodes[p.0 as usize].data {
766            NodeData::Box(b) => Some(b),
767            NodeData::Unset { b, .. } => Some(b),
768            _ => None,
769        }
770    }
771
772    /// The box data of an hlist/vlist node, mutably.
773    pub fn box_data_mut(&mut self, p: NodeRef) -> Option<&mut BoxData> {
774        match &mut self.nodes[p.0 as usize].data {
775            NodeData::Box(b) => Some(b),
776            NodeData::Unset { b, .. } => Some(b),
777            _ => None,
778        }
779    }
780
781    /// The last node of the list starting at `p`.
782    pub fn tail_of(&self, mut p: NodeRef) -> NodeRef {
783        if p.is_null() {
784            return p;
785        }
786        loop {
787            let n = self.next(p);
788            if n.is_null() {
789                return p;
790            }
791            p = n;
792        }
793    }
794
795    /// Frees a whole node list, including sublists (`flush_node_list`).
796    pub fn flush_list(&mut self, p: NodeRef) {
797        let mut stack: Vec<NodeRef> = Vec::new();
798        let mut p = p;
799        loop {
800            while !p.is_null() {
801                let next = self.next(p);
802                match &self.nodes[p.0 as usize].data {
803                    NodeData::Box(b) => stack.push(b.head),
804                    NodeData::Unset { b, .. } => stack.push(b.head),
805                    NodeData::Ins { head, .. } | NodeData::Adjust { head } => stack.push(*head),
806                    NodeData::Disc {
807                        pre, post, replace, ..
808                    } => {
809                        stack.push(*pre);
810                        stack.push(*post);
811                        stack.push(*replace);
812                    }
813                    NodeData::Glue { leader, .. } => stack.push(*leader),
814                    NodeData::Glyph(g) => {
815                        if !g.components.is_null() {
816                            stack.push(g.components);
817                        }
818                    }
819                    NodeData::LocalPar {
820                        box_left,
821                        box_right,
822                        ..
823                    } => {
824                        stack.push(*box_left);
825                        stack.push(*box_right);
826                    }
827                    NodeData::Noad(n) => stack.extend([
828                        n.nucleus,
829                        n.sub,
830                        n.sup,
831                        n.left,
832                        n.degree,
833                        n.accent,
834                        n.bot_accent,
835                        n.new_hlist,
836                    ]),
837                    NodeData::Fraction(f) => {
838                        stack.extend([f.num, f.denom, f.left, f.right, f.middle, f.new_hlist])
839                    }
840                    NodeData::Fence(f) => stack.extend([f.delim, f.new_hlist]),
841                    NodeData::Choice(c) => stack.extend(c.iter().copied()),
842                    NodeData::SubList { head } => stack.push(*head),
843                    _ => {}
844                }
845                self.free(p);
846                p = next;
847            }
848            match stack.pop() {
849                Some(q) => p = q,
850                None => return,
851            }
852        }
853    }
854
855    /// Copies a whole node list, including sublists (`copy_node_list`).
856    pub fn copy_list(&mut self, mut p: NodeRef) -> NodeRef {
857        let mut head = NodeRef::NULL;
858        let mut tail = NodeRef::NULL;
859        while !p.is_null() {
860            let q = self.copy_node(p);
861            if head.is_null() {
862                head = q;
863            } else {
864                self.link(tail, q);
865            }
866            tail = q;
867            p = self.next(p);
868        }
869        head
870    }
871
872    /// Copies one node with its sublists; the copy's links are null.
873    pub fn copy_node(&mut self, p: NodeRef) -> NodeRef {
874        let mut node = self.nodes[p.0 as usize].clone();
875        node.next = NodeRef::NULL;
876        node.prev = NodeRef::NULL;
877        match &mut node.data {
878            NodeData::Box(b) => b.head = self.copy_list(b.head),
879            NodeData::Unset { b, .. } => b.head = self.copy_list(b.head),
880            NodeData::Ins { head, .. } | NodeData::Adjust { head } => *head = self.copy_list(*head),
881            NodeData::Disc {
882                pre, post, replace, ..
883            } => {
884                *pre = self.copy_list(*pre);
885                *post = self.copy_list(*post);
886                *replace = self.copy_list(*replace);
887            }
888            NodeData::Glue { leader, .. } => *leader = self.copy_list(*leader),
889            NodeData::Glyph(g) => g.components = self.copy_list(g.components),
890            NodeData::LocalPar {
891                box_left,
892                box_right,
893                ..
894            } => {
895                *box_left = self.copy_list(*box_left);
896                *box_right = self.copy_list(*box_right);
897            }
898            NodeData::Noad(n) => {
899                for f in [
900                    &mut n.nucleus,
901                    &mut n.sub,
902                    &mut n.sup,
903                    &mut n.left,
904                    &mut n.degree,
905                    &mut n.accent,
906                    &mut n.bot_accent,
907                    &mut n.new_hlist,
908                ] {
909                    *f = self.copy_list(*f);
910                }
911            }
912            NodeData::Fraction(fr) => {
913                for f in [
914                    &mut fr.num,
915                    &mut fr.denom,
916                    &mut fr.left,
917                    &mut fr.right,
918                    &mut fr.middle,
919                    &mut fr.new_hlist,
920                ] {
921                    *f = self.copy_list(*f);
922                }
923            }
924            NodeData::Fence(fe) => {
925                fe.delim = self.copy_list(fe.delim);
926                fe.new_hlist = self.copy_list(fe.new_hlist);
927            }
928            NodeData::Choice(c) => {
929                for f in c.iter_mut() {
930                    *f = self.copy_list(*f);
931                }
932            }
933            NodeData::SubList { head } => *head = self.copy_list(*head),
934            _ => {}
935        }
936        self.in_use += 1;
937        if let Some(i) = self.free.pop() {
938            self.nodes[i as usize] = node;
939            NodeRef(i)
940        } else {
941            self.nodes.push(node);
942            NodeRef(self.nodes.len() as u32 - 1)
943        }
944    }
945
946    /// A new empty box of the given type (`new_null_box`).
947    pub fn new_null_box(&mut self, hlist: bool) -> NodeRef {
948        self.alloc(
949            if hlist { id::HLIST } else { id::VLIST },
950            0,
951            NodeData::Box(Box::default()),
952        )
953    }
954
955    /// A new glue node.
956    pub fn new_glue(&mut self, spec: Glue, subtype: u16) -> NodeRef {
957        self.alloc(
958            id::GLUE,
959            subtype,
960            NodeData::Glue {
961                spec,
962                leader: NodeRef::NULL,
963            },
964        )
965    }
966
967    /// A new kern node.
968    pub fn new_kern(&mut self, w: i32, subtype: u16) -> NodeRef {
969        self.alloc(
970            id::KERN,
971            subtype,
972            NodeData::Kern {
973                kern: w,
974                expansion_factor: 0,
975            },
976        )
977    }
978
979    /// A new penalty node.
980    pub fn new_penalty(&mut self, m: i32, subtype: u16) -> NodeRef {
981        self.alloc(id::PENALTY, subtype, NodeData::Penalty { penalty: m })
982    }
983
984    /// A new temporary list head.
985    pub fn new_temp(&mut self) -> NodeRef {
986        self.alloc(id::TEMP, 0, NodeData::Temp)
987    }
988
989    /// A new glyph node.
990    pub fn new_glyph(&mut self, font: u32, chr: u32) -> NodeRef {
991        self.alloc(
992            id::GLYPH,
993            0,
994            NodeData::Glyph(GlyphData {
995                chr,
996                font,
997                ..GlyphData::default()
998            }),
999        )
1000    }
1001
1002    /// A new rule node with the given dimensions.
1003    pub fn new_rule(&mut self, width: i32, height: i32, depth: i32) -> NodeRef {
1004        self.alloc(
1005            id::RULE,
1006            0,
1007            NodeData::Rule {
1008                width,
1009                depth,
1010                height,
1011                dir: 0,
1012                index: 0,
1013                left: 0,
1014                right: 0,
1015            },
1016        )
1017    }
1018
1019    /// A new empty discretionary node.
1020    pub fn new_disc(&mut self, subtype: u16, penalty: i32) -> NodeRef {
1021        self.alloc(
1022            id::DISC,
1023            subtype,
1024            NodeData::Disc {
1025                pre: NodeRef::NULL,
1026                post: NodeRef::NULL,
1027                replace: NodeRef::NULL,
1028                penalty,
1029            },
1030        )
1031    }
1032
1033    /// A new math node.
1034    pub fn new_math(&mut self, surround: i32, subtype: u16) -> NodeRef {
1035        self.alloc(
1036            id::MATH,
1037            subtype,
1038            NodeData::Math {
1039                surround,
1040                glue: Glue::ZERO,
1041            },
1042        )
1043    }
1044
1045    /// The type-specific data of `p`.
1046    #[inline]
1047    pub fn data(&self, p: NodeRef) -> &NodeData {
1048        &self.nodes[p.0 as usize].data
1049    }
1050
1051    /// The type-specific data of `p`, mutably.
1052    #[inline]
1053    pub fn data_mut(&mut self, p: NodeRef) -> &mut NodeData {
1054        &mut self.nodes[p.0 as usize].data
1055    }
1056
1057    /// The subtype of `p`.
1058    #[inline]
1059    pub fn subtype(&self, p: NodeRef) -> u16 {
1060        self.nodes[p.0 as usize].subtype
1061    }
1062
1063    /// Sets the subtype of `p`.
1064    #[inline]
1065    pub fn set_subtype(&mut self, p: NodeRef, s: u16) {
1066        self.nodes[p.0 as usize].subtype = s;
1067    }
1068
1069    /// The `prev` link of `p`.
1070    #[inline]
1071    pub fn prev(&self, p: NodeRef) -> NodeRef {
1072        self.nodes[p.0 as usize].prev
1073    }
1074
1075    /// Sets only the `next` link of `p`.
1076    #[inline]
1077    pub fn set_next(&mut self, p: NodeRef, q: NodeRef) {
1078        self.nodes[p.0 as usize].next = q;
1079    }
1080
1081    /// Sets only the `prev` link of `p`.
1082    #[inline]
1083    pub fn set_prev(&mut self, p: NodeRef, q: NodeRef) {
1084        self.nodes[p.0 as usize].prev = q;
1085    }
1086
1087    /// Whether `p` is a glyph node.
1088    #[inline]
1089    pub fn is_glyph(&self, p: NodeRef) -> bool {
1090        self.nodes[p.0 as usize].id == id::GLYPH
1091    }
1092
1093    /// The glyph data of a glyph node.
1094    #[inline]
1095    pub fn glyph(&self, p: NodeRef) -> Option<&GlyphData> {
1096        match &self.nodes[p.0 as usize].data {
1097            NodeData::Glyph(g) => Some(g),
1098            _ => None,
1099        }
1100    }
1101
1102    /// The glyph data of a glyph node, mutably.
1103    #[inline]
1104    pub fn glyph_mut(&mut self, p: NodeRef) -> Option<&mut GlyphData> {
1105        match &mut self.nodes[p.0 as usize].data {
1106            NodeData::Glyph(g) => Some(g),
1107            _ => None,
1108        }
1109    }
1110
1111    /// The glue specification of a glue node.
1112    #[inline]
1113    pub fn glue_spec(&self, p: NodeRef) -> Glue {
1114        match &self.nodes[p.0 as usize].data {
1115            NodeData::Glue { spec, .. } => *spec,
1116            NodeData::Math { glue, .. } => *glue,
1117            _ => Glue::ZERO,
1118        }
1119    }
1120
1121    /// The width of a node that has one (boxes, rules, glue, kerns, math,
1122    /// margin kerns, unset nodes); zero otherwise. Glyph widths need the
1123    /// font and are not handled here.
1124    pub fn width(&self, p: NodeRef) -> i32 {
1125        match &self.nodes[p.0 as usize].data {
1126            NodeData::Box(b) => b.width,
1127            NodeData::Unset { b, .. } => b.width,
1128            NodeData::Rule { width, .. } => *width,
1129            NodeData::Glue { spec, .. } => spec.width,
1130            NodeData::Kern {
1131                kern,
1132                expansion_factor,
1133            } => *kern + *expansion_factor,
1134            NodeData::Math { surround, glue } => {
1135                if glue.width != 0 || glue.stretch != 0 || glue.shrink != 0 {
1136                    glue.width
1137                } else {
1138                    *surround
1139                }
1140            }
1141            NodeData::MarginKern { width, .. } => *width,
1142            _ => 0,
1143        }
1144    }
1145
1146    /// The penalty of a penalty node (0 for other nodes).
1147    pub fn penalty(&self, p: NodeRef) -> i32 {
1148        match &self.nodes[p.0 as usize].data {
1149            NodeData::Penalty { penalty } => *penalty,
1150            NodeData::Disc { penalty, .. } => *penalty,
1151            _ => 0,
1152        }
1153    }
1154
1155    /// The (pre, post, replace) lists of a discretionary.
1156    pub fn disc_lists(&self, p: NodeRef) -> (NodeRef, NodeRef, NodeRef) {
1157        match &self.nodes[p.0 as usize].data {
1158            NodeData::Disc {
1159                pre, post, replace, ..
1160            } => (*pre, *post, *replace),
1161            _ => (NodeRef::NULL, NodeRef::NULL, NodeRef::NULL),
1162        }
1163    }
1164
1165    /// Sets the lists of a discretionary.
1166    pub fn set_disc_lists(&mut self, p: NodeRef, l: (NodeRef, NodeRef, NodeRef)) {
1167        if let NodeData::Disc {
1168            pre, post, replace, ..
1169        } = &mut self.nodes[p.0 as usize].data
1170        {
1171            *pre = l.0;
1172            *post = l.1;
1173            *replace = l.2;
1174        }
1175        for q in [l.0, l.1, l.2] {
1176            if !q.is_null() {
1177                self.nodes[q.0 as usize].prev = NodeRef::NULL;
1178            }
1179        }
1180    }
1181
1182    /// The list of a box, unset node, insertion or adjust node.
1183    pub fn list_ptr(&self, p: NodeRef) -> NodeRef {
1184        match &self.nodes[p.0 as usize].data {
1185            NodeData::Box(b) => b.head,
1186            NodeData::Unset { b, .. } => b.head,
1187            NodeData::Ins { head, .. } | NodeData::Adjust { head } => *head,
1188            _ => NodeRef::NULL,
1189        }
1190    }
1191
1192    /// Sets the list of a box, unset node, insertion or adjust node.
1193    pub fn set_list_ptr(&mut self, p: NodeRef, l: NodeRef) {
1194        match &mut self.nodes[p.0 as usize].data {
1195            NodeData::Box(b) => b.head = l,
1196            NodeData::Unset { b, .. } => b.head = l,
1197            NodeData::Ins { head, .. } | NodeData::Adjust { head } => *head = l,
1198            _ => {}
1199        }
1200    }
1201
1202    /// The attribute list of `p`.
1203    #[inline]
1204    pub fn attr(&self, p: NodeRef) -> Option<&AttrList> {
1205        self.nodes[p.0 as usize].attr.as_ref()
1206    }
1207
1208    /// Sets the attribute list of `p`.
1209    #[inline]
1210    pub fn set_attr(&mut self, p: NodeRef, a: Option<AttrList>) {
1211        self.nodes[p.0 as usize].attr = a;
1212    }
1213
1214    /// The noad fields of a noad, radical or accent node.
1215    #[inline]
1216    pub fn noad(&self, p: NodeRef) -> Option<&NoadData> {
1217        match &self.nodes[p.0 as usize].data {
1218            NodeData::Noad(n) => Some(n),
1219            _ => None,
1220        }
1221    }
1222
1223    /// The noad fields of a noad, radical or accent node, mutably.
1224    #[inline]
1225    pub fn noad_mut(&mut self, p: NodeRef) -> Option<&mut NoadData> {
1226        match &mut self.nodes[p.0 as usize].data {
1227            NodeData::Noad(n) => Some(n),
1228            _ => None,
1229        }
1230    }
1231
1232    /// The list of a `sub_box` or `sub_mlist` kernel (null otherwise).
1233    pub fn list_ptr_kernel(&self, p: NodeRef) -> NodeRef {
1234        if p.is_null() {
1235            return NodeRef::NULL;
1236        }
1237        match &self.nodes[p.0 as usize].data {
1238            NodeData::SubList { head } => *head,
1239            _ => NodeRef::NULL,
1240        }
1241    }
1242
1243    /// Sets the list of a `sub_box` or `sub_mlist` kernel.
1244    pub fn set_kernel_list(&mut self, p: NodeRef, l: NodeRef) {
1245        if p.is_null() {
1246            return;
1247        }
1248        if let NodeData::SubList { head } = &mut self.nodes[p.0 as usize].data {
1249            *head = l;
1250        }
1251    }
1252
1253    /// Whether `p` is a noad that can carry scripts (`scripts_allowed`).
1254    pub fn scripts_allowed(&self, p: NodeRef) -> bool {
1255        matches!(self.nodes[p.0 as usize].data, NodeData::Noad(_))
1256            && matches!(self.id(p), id::NOAD | id::RADICAL | id::ACCENT)
1257    }
1258
1259    /// The number of nodes in the list starting at `p`.
1260    pub fn list_len(&self, mut p: NodeRef) -> usize {
1261        let mut n = 0;
1262        while !p.is_null() {
1263            n += 1;
1264            p = self.next(p);
1265        }
1266        n
1267    }
1268}
1269
1270/// The glue set ratio `num / den` as LuaTeX stores it: the quotient is
1271/// computed in double precision and kept as a C `float` (observed through
1272/// `tex.box[n].glue_set`). The rounding shows at shipout, where the ratio
1273/// multiplies the accumulated stretch or shrink (§625).
1274pub fn glue_ratio(num: i32, den: i32) -> f64 {
1275    f64::from((f64::from(num) / f64::from(den)) as f32)
1276}
1277
1278#[cfg(test)]
1279mod tests {
1280    use super::*;
1281
1282    #[test]
1283    fn glue_ratio_is_single_precision() {
1284        // `\hbox to 1021537sp{\hskip 0pt plus 873808sp}` in LuaTeX.
1285        assert_eq!(glue_ratio(1021537, 873808), 1.1690634489059448);
1286    }
1287
1288    #[test]
1289    fn alloc_link_copy_flush() {
1290        let mut n = Nodes::new();
1291        let b = n.new_null_box(true);
1292        let k = n.new_kern(5, kern_sub::USER);
1293        let g = n.new_glue(Glue::fixed(7), glue_sub::USER);
1294        n.link(k, g);
1295        n.box_data_mut(b).unwrap().head = k;
1296        assert_eq!(n.in_use, 3);
1297        let c = n.copy_node(b);
1298        assert_eq!(n.in_use, 6);
1299        let ch = n.box_data(c).unwrap().head;
1300        assert_ne!(ch, k);
1301        assert_eq!(n.get(n.next(ch)).data, n.get(g).data);
1302        n.flush_list(c);
1303        n.flush_list(b);
1304        assert_eq!(n.in_use, 0);
1305    }
1306}