1use std::rc::Rc;
9
10use crate::glue::Glue;
11use crate::token::TokenList;
12
13pub const LUATEX_NODE_TYPES: &str = include_str!("../data/luatex-node-types.txt");
17
18#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, PartialOrd, Ord)]
21pub struct NodeRef(pub u32);
22
23impl NodeRef {
24 pub const NULL: NodeRef = NodeRef(0);
26
27 #[inline]
29 pub const fn is_null(self) -> bool {
30 self.0 == 0
31 }
32}
33
34pub const RUNNING: i32 = -0o10000000000;
36
37#[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#[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#[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#[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#[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
155pub type AttrList = Rc<[(u32, i32)]>;
157
158#[derive(Clone, Debug, Default, PartialEq)]
160pub struct BoxData {
161 pub width: i32,
163 pub depth: i32,
165 pub height: i32,
167 pub dir: i8,
169 pub shift: i32,
171 pub glue_order: u8,
173 pub glue_sign: u8,
175 pub glue_set: f64,
178 pub head: NodeRef,
180}
181
182#[derive(Clone, Debug, Default, PartialEq)]
184pub struct GlyphData {
185 pub chr: u32,
187 pub font: u32,
189 pub lang: u16,
191 pub left: u8,
193 pub right: u8,
195 pub uchyph: bool,
197 pub components: NodeRef,
199 pub xoffset: i32,
201 pub yoffset: i32,
203 pub expansion_factor: i32,
205 pub data: i32,
207}
208
209#[derive(Clone, Debug, PartialEq)]
211pub enum NodeData {
212 Temp,
214 Box(Box<BoxData>),
216 Rule {
218 width: i32,
220 depth: i32,
222 height: i32,
224 dir: i8,
226 index: i32,
228 left: i32,
230 right: i32,
232 },
233 Ins {
235 cost: i32,
237 depth: i32,
239 height: i32,
241 spec: Glue,
243 head: NodeRef,
245 },
246 Mark {
248 class: u32,
250 mark: TokenList,
252 },
253 Adjust {
255 head: NodeRef,
257 },
258 Boundary {
260 value: i32,
262 },
263 Disc {
265 pre: NodeRef,
267 post: NodeRef,
269 replace: NodeRef,
271 penalty: i32,
273 },
274 Whatsit(Box<Whatsit>),
276 LocalPar {
278 pen_inter: i32,
280 pen_broken: i32,
282 dir: i8,
284 box_left: NodeRef,
286 box_left_width: i32,
288 box_right: NodeRef,
290 box_right_width: i32,
292 },
293 Dir {
295 dir: i8,
297 level: i32,
299 },
300 Math {
302 surround: i32,
304 glue: Glue,
306 },
307 Glue {
309 spec: Glue,
311 leader: NodeRef,
313 },
314 Kern {
316 kern: i32,
318 expansion_factor: i32,
320 },
321 Penalty {
323 penalty: i32,
325 },
326 Unset {
328 b: Box<BoxData>,
330 span_count: u16,
332 stretch: i32,
334 shrink: i32,
336 stretch_order: u8,
338 shrink_order: u8,
340 },
341 Glyph(GlyphData),
343 MarginKern {
345 width: i32,
347 glyph: NodeRef,
349 },
350 Noad(Box<NoadData>),
352 Fraction(Box<FractionData>),
354 Fence(Box<FenceData>),
356 Style {
358 style: u8,
360 },
361 Choice(Box<[NodeRef; 4]>),
363 MathChar {
365 fam: u32,
367 chr: u32,
369 },
370 SubList {
372 head: NodeRef,
374 },
375 Delim {
377 small_fam: u32,
379 small_char: u32,
381 large_fam: u32,
383 large_char: u32,
385 },
386 Other(Vec<i64>),
388}
389
390#[derive(Clone, Debug, Default, PartialEq)]
394pub struct NoadData {
395 pub nucleus: NodeRef,
397 pub sub: NodeRef,
399 pub sup: NodeRef,
401 pub options: u32,
403 pub left: NodeRef,
405 pub degree: NodeRef,
407 pub width: i32,
409 pub accent: NodeRef,
411 pub bot_accent: NodeRef,
413 pub fraction: i32,
415 pub new_hlist: NodeRef,
418}
419
420#[derive(Clone, Debug, PartialEq)]
422pub struct FractionData {
423 pub thickness: i32,
425 pub num: NodeRef,
427 pub denom: NodeRef,
429 pub left: NodeRef,
431 pub right: NodeRef,
433 pub middle: NodeRef,
435 pub options: u32,
437 pub new_hlist: NodeRef,
439}
440
441#[derive(Clone, Debug, Default, PartialEq)]
443pub struct FenceData {
444 pub delim: NodeRef,
446 pub italic: i32,
448 pub height: i32,
450 pub depth: i32,
452 pub options: u32,
454 pub class: i32,
456 pub new_hlist: NodeRef,
458}
459
460pub const DEFAULT_CODE: i32 = 0o10000000000;
463
464#[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#[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#[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#[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#[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 pub const OVERLAY: u32 = 0x100;
528}
529
530#[derive(Clone, Debug, PartialEq)]
532pub enum Whatsit {
533 Open {
535 stream: u32,
537 name: Vec<u8>,
539 },
540 Write {
542 stream: i32,
544 data: TokenList,
546 },
547 Close {
549 stream: u32,
551 },
552 Special {
554 data: Vec<u8>,
556 },
557 LateLua {
559 data: LateData,
561 name: Vec<u8>,
563 },
564 PdfLiteral {
566 mode: u8,
568 data: LateData,
570 late: bool,
572 },
573 SavePos,
575 PdfColorstack {
577 stack: i32,
579 cmd: u8,
581 data: Vec<u8>,
583 },
584 PdfSetmatrix {
586 data: Vec<u8>,
588 },
589 PdfSave,
591 PdfRestore,
593 PdfAnnot {
595 dims: [i32; 3],
597 objnum: i32,
599 data: Vec<u8>,
601 },
602 PdfStartLink {
604 dims: [i32; 3],
606 objnum: i32,
608 attr: Vec<u8>,
610 action: crate::pdfext::PdfAction,
612 },
613 PdfEndLink,
615 PdfDest {
617 id: crate::pdfext::DestId,
619 view: crate::pdfext::DestView,
621 },
622 PdfRefobj {
624 objnum: i32,
626 },
627 Other {
629 fields: Vec<i64>,
631 data: Vec<u8>,
633 },
634}
635
636#[derive(Clone, Debug, PartialEq)]
638pub enum LateData {
639 Tokens(TokenList),
641 Bytes(Vec<u8>),
643}
644
645#[derive(Clone, Debug, PartialEq)]
647pub struct Node {
648 pub id: u8,
650 pub subtype: u16,
652 pub next: NodeRef,
654 pub prev: NodeRef,
656 pub attr: Option<AttrList>,
658 pub data: NodeData,
660}
661
662#[derive(Debug, Clone)]
664pub struct Nodes {
665 nodes: Vec<Node>,
666 free: Vec<u32>,
667 pub in_use: usize,
669}
670
671impl Default for Nodes {
672 fn default() -> Self {
673 Self::new()
674 }
675}
676
677impl Nodes {
678 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 pub fn capacity(&self) -> usize {
696 self.nodes.len()
697 }
698
699 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 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 #[inline]
732 pub fn get(&self, p: NodeRef) -> &Node {
733 &self.nodes[p.0 as usize]
734 }
735
736 #[inline]
738 pub fn get_mut(&mut self, p: NodeRef) -> &mut Node {
739 &mut self.nodes[p.0 as usize]
740 }
741
742 #[inline]
744 pub fn id(&self, p: NodeRef) -> u8 {
745 self.nodes[p.0 as usize].id
746 }
747
748 #[inline]
750 pub fn next(&self, p: NodeRef) -> NodeRef {
751 self.nodes[p.0 as usize].next
752 }
753
754 #[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 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 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 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 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 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 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 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 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 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 pub fn new_penalty(&mut self, m: i32, subtype: u16) -> NodeRef {
981 self.alloc(id::PENALTY, subtype, NodeData::Penalty { penalty: m })
982 }
983
984 pub fn new_temp(&mut self) -> NodeRef {
986 self.alloc(id::TEMP, 0, NodeData::Temp)
987 }
988
989 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 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 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 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 #[inline]
1047 pub fn data(&self, p: NodeRef) -> &NodeData {
1048 &self.nodes[p.0 as usize].data
1049 }
1050
1051 #[inline]
1053 pub fn data_mut(&mut self, p: NodeRef) -> &mut NodeData {
1054 &mut self.nodes[p.0 as usize].data
1055 }
1056
1057 #[inline]
1059 pub fn subtype(&self, p: NodeRef) -> u16 {
1060 self.nodes[p.0 as usize].subtype
1061 }
1062
1063 #[inline]
1065 pub fn set_subtype(&mut self, p: NodeRef, s: u16) {
1066 self.nodes[p.0 as usize].subtype = s;
1067 }
1068
1069 #[inline]
1071 pub fn prev(&self, p: NodeRef) -> NodeRef {
1072 self.nodes[p.0 as usize].prev
1073 }
1074
1075 #[inline]
1077 pub fn set_next(&mut self, p: NodeRef, q: NodeRef) {
1078 self.nodes[p.0 as usize].next = q;
1079 }
1080
1081 #[inline]
1083 pub fn set_prev(&mut self, p: NodeRef, q: NodeRef) {
1084 self.nodes[p.0 as usize].prev = q;
1085 }
1086
1087 #[inline]
1089 pub fn is_glyph(&self, p: NodeRef) -> bool {
1090 self.nodes[p.0 as usize].id == id::GLYPH
1091 }
1092
1093 #[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 #[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 #[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 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 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 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 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 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 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 #[inline]
1204 pub fn attr(&self, p: NodeRef) -> Option<&AttrList> {
1205 self.nodes[p.0 as usize].attr.as_ref()
1206 }
1207
1208 #[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 #[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 #[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 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 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 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 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
1270pub 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 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}