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
18pub fn type_name(t: u8) -> String {
20 LUATEX_NODE_TYPES
21 .lines()
22 .filter_map(|l| l.strip_prefix("type "))
23 .find_map(|l| {
24 let mut it = l.split_whitespace();
25 let n: u8 = it.next()?.parse().ok()?;
26 (n == t).then(|| it.next().unwrap_or("").to_owned())
27 })
28 .unwrap_or_default()
29}
30
31#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, PartialOrd, Ord)]
34pub struct NodeRef(pub u32);
35
36impl NodeRef {
37 pub const NULL: NodeRef = NodeRef(0);
39
40 #[inline]
42 pub const fn is_null(self) -> bool {
43 self.0 == 0
44 }
45}
46
47pub const RUNNING: i32 = -0o10000000000;
49
50#[allow(missing_docs)]
52pub mod id {
53 pub const HLIST: u8 = 0;
54 pub const VLIST: u8 = 1;
55 pub const RULE: u8 = 2;
56 pub const INS: u8 = 3;
57 pub const MARK: u8 = 4;
58 pub const ADJUST: u8 = 5;
59 pub const BOUNDARY: u8 = 6;
60 pub const DISC: u8 = 7;
61 pub const WHATSIT: u8 = 8;
62 pub const LOCAL_PAR: u8 = 9;
63 pub const DIR: u8 = 10;
64 pub const MATH: u8 = 11;
65 pub const GLUE: u8 = 12;
66 pub const KERN: u8 = 13;
67 pub const PENALTY: u8 = 14;
68 pub const UNSET: u8 = 15;
69 pub const STYLE: u8 = 16;
70 pub const CHOICE: u8 = 17;
71 pub const NOAD: u8 = 18;
72 pub const RADICAL: u8 = 19;
73 pub const FRACTION: u8 = 20;
74 pub const ACCENT: u8 = 21;
75 pub const FENCE: u8 = 22;
76 pub const MATH_CHAR: u8 = 23;
77 pub const SUB_BOX: u8 = 24;
78 pub const SUB_MLIST: u8 = 25;
79 pub const MATH_TEXT_CHAR: u8 = 26;
80 pub const DELIM: u8 = 27;
81 pub const MARGIN_KERN: u8 = 28;
82 pub const GLYPH: u8 = 29;
83 pub const ALIGN_RECORD: u8 = 30;
84 pub const PAGE_INSERT: u8 = 33;
85 pub const SPLIT_INSERT: u8 = 34;
86 pub const GLUE_SPEC: u8 = 39;
89 pub const TEMP: u8 = 41;
90 pub const FREE: u8 = 255;
92}
93
94pub const MAX_NESTING: u32 = 50_000;
98
99#[allow(missing_docs)]
101pub mod glue_sub {
102 pub const USER: u16 = 0;
103 pub const LINE_SKIP: u16 = 1;
104 pub const BASELINE_SKIP: u16 = 2;
105 pub const PAR_SKIP: u16 = 3;
106 pub const ABOVE_DISPLAY: u16 = 4;
107 pub const BELOW_DISPLAY: u16 = 5;
108 pub const ABOVE_DISPLAY_SHORT: u16 = 6;
109 pub const BELOW_DISPLAY_SHORT: u16 = 7;
110 pub const LEFT_SKIP: u16 = 8;
111 pub const RIGHT_SKIP: u16 = 9;
112 pub const TOP_SKIP: u16 = 10;
113 pub const SPLIT_TOP_SKIP: u16 = 11;
114 pub const TAB_SKIP: u16 = 12;
115 pub const SPACE_SKIP: u16 = 13;
116 pub const XSPACE_SKIP: u16 = 14;
117 pub const PAR_FILL_SKIP: u16 = 15;
118 pub const MATH_SKIP: u16 = 16;
119 pub const THIN_MU_SKIP: u16 = 17;
120 pub const MED_MU_SKIP: u16 = 18;
121 pub const THICK_MU_SKIP: u16 = 19;
122 pub const COND_MATH_GLUE: u16 = 98;
123 pub const MU_GLUE: u16 = 99;
124 pub const A_LEADERS: u16 = 100;
125 pub const C_LEADERS: u16 = 101;
126 pub const X_LEADERS: u16 = 102;
127 pub const G_LEADERS: u16 = 103;
128}
129
130pub mod list_sub {
133 pub const MATH_CHAR: u16 = 9;
135 pub const H_EXTENSIBLE: u16 = 10;
137 pub const V_EXTENSIBLE: u16 = 11;
139 pub const V_DELIMITER: u16 = 13;
141 pub const OVER_DELIMITER: u16 = 14;
143 pub const UNDER_DELIMITER: u16 = 15;
145 pub const NUMERATOR: u16 = 16;
147 pub const DENOMINATOR: u16 = 17;
149 pub const LIMITS: u16 = 18;
151 pub const FRACTION: u16 = 19;
153 pub const NUCLEUS: u16 = 20;
155 pub const SUP: u16 = 21;
157 pub const SUB: u16 = 22;
159 pub const DEGREE: u16 = 23;
161 pub const SCRIPTS: u16 = 24;
163 pub const OVER: u16 = 25;
165 pub const UNDER: u16 = 26;
167 pub const ACCENT: u16 = 27;
169 pub const RADICAL: u16 = 28;
171}
172
173#[allow(missing_docs)]
175pub mod kern_sub {
176 pub const FONT: u16 = 0;
177 pub const USER: u16 = 1;
178 pub const ACCENT: u16 = 2;
179 pub const ITALIC: u16 = 3;
180}
181
182#[allow(missing_docs)]
184pub mod glyph_sub {
185 pub const CHARACTER: u16 = 1;
186 pub const LIGATURE: u16 = 2;
187 pub const GHOST: u16 = 4;
188 pub const LEFT: u16 = 8;
189 pub const RIGHT: u16 = 16;
190}
191
192#[allow(missing_docs)]
194pub mod whatsit_sub {
195 pub const OPEN: u16 = 0;
196 pub const WRITE: u16 = 1;
197 pub const CLOSE: u16 = 2;
198 pub const SPECIAL: u16 = 3;
199 pub const LATE_SPECIAL: u16 = 4;
200 pub const SAVE_POS: u16 = 7;
201 pub const LATE_LUA: u16 = 8;
202 pub const USER_DEFINED: u16 = 9;
203 pub const PDF_LITERAL: u16 = 16;
204 pub const PDF_LATE_LITERAL: u16 = 17;
205 pub const PDF_REFOBJ: u16 = 18;
206 pub const PDF_ANNOT: u16 = 19;
207 pub const PDF_START_LINK: u16 = 20;
208 pub const PDF_END_LINK: u16 = 21;
209 pub const PDF_DEST: u16 = 22;
210 pub const PDF_ACTION: u16 = 23;
211 pub const PDF_THREAD: u16 = 24;
212 pub const PDF_START_THREAD: u16 = 25;
213 pub const PDF_END_THREAD: u16 = 26;
214 pub const PDF_COLORSTACK: u16 = 29;
215 pub const PDF_SETMATRIX: u16 = 30;
216 pub const PDF_SAVE: u16 = 31;
217 pub const PDF_RESTORE: u16 = 32;
218 pub const PDF_LINK_STATE: u16 = 33;
219}
220
221pub type AttrList = Rc<[(u32, i32)]>;
223
224#[derive(Clone, Debug, Default, PartialEq)]
226pub struct BoxData {
227 pub width: i32,
229 pub depth: i32,
231 pub height: i32,
233 pub dir: i8,
235 pub shift: i32,
237 pub glue_order: u8,
239 pub glue_sign: u8,
241 pub glue_set: f64,
244 pub head: NodeRef,
246}
247
248#[derive(Clone, Debug, Default, PartialEq)]
250pub struct GlyphData {
251 pub chr: u32,
253 pub font: u32,
255 pub lang: u16,
257 pub left: u8,
259 pub right: u8,
261 pub uchyph: bool,
263 pub components: NodeRef,
265 pub xoffset: i32,
267 pub yoffset: i32,
269 pub expansion_factor: i32,
271 pub data: i32,
273}
274
275#[derive(Clone, Debug, PartialEq)]
277pub enum NodeData {
278 Temp,
280 Box(Box<BoxData>),
282 Rule {
284 width: i32,
286 depth: i32,
288 height: i32,
290 dir: i8,
292 index: i32,
294 left: i32,
296 right: i32,
298 },
299 Ins {
301 cost: i32,
303 depth: i32,
305 height: i32,
307 spec: Glue,
309 head: NodeRef,
311 },
312 Mark {
314 class: u32,
316 mark: TokenList,
318 },
319 Adjust {
321 head: NodeRef,
323 },
324 Boundary {
326 value: i32,
328 },
329 Disc {
331 pre: NodeRef,
333 post: NodeRef,
335 replace: NodeRef,
337 penalty: i32,
339 },
340 Whatsit(Box<Whatsit>),
342 LocalPar {
344 pen_inter: i32,
346 pen_broken: i32,
348 dir: i8,
350 box_left: NodeRef,
352 box_left_width: i32,
354 box_right: NodeRef,
356 box_right_width: i32,
358 },
359 Dir {
361 dir: i8,
363 level: i32,
365 },
366 Math {
368 surround: i32,
370 glue: Glue,
372 },
373 Glue {
375 spec: Glue,
377 leader: NodeRef,
379 },
380 Kern {
382 kern: i32,
384 expansion_factor: i32,
386 },
387 Penalty {
389 penalty: i32,
391 },
392 Unset {
394 b: Box<BoxData>,
396 span_count: u16,
398 stretch: i32,
400 shrink: i32,
402 stretch_order: u8,
404 shrink_order: u8,
406 },
407 Glyph(GlyphData),
409 MarginKern {
411 width: i32,
413 glyph: NodeRef,
415 },
416 Noad(Box<NoadData>),
418 Fraction(Box<FractionData>),
420 Fence(Box<FenceData>),
422 Style {
424 style: u8,
426 },
427 Choice(Box<[NodeRef; 4]>),
429 MathChar {
431 fam: u32,
433 chr: u32,
435 },
436 SubList {
438 head: NodeRef,
440 },
441 Delim {
443 small_fam: u32,
445 small_char: u32,
447 large_fam: u32,
449 large_char: u32,
451 },
452 Other(Vec<i64>),
454}
455
456#[derive(Clone, Debug, Default, PartialEq)]
460pub struct NoadData {
461 pub nucleus: NodeRef,
463 pub sub: NodeRef,
465 pub sup: NodeRef,
467 pub options: u32,
469 pub left: NodeRef,
471 pub degree: NodeRef,
473 pub width: i32,
475 pub accent: NodeRef,
477 pub bot_accent: NodeRef,
479 pub fraction: i32,
481 pub new_hlist: NodeRef,
484}
485
486#[derive(Clone, Debug, PartialEq)]
488pub struct FractionData {
489 pub thickness: i32,
491 pub num: NodeRef,
493 pub denom: NodeRef,
495 pub left: NodeRef,
497 pub right: NodeRef,
499 pub middle: NodeRef,
501 pub options: u32,
503 pub new_hlist: NodeRef,
505}
506
507#[derive(Clone, Debug, Default, PartialEq)]
509pub struct FenceData {
510 pub delim: NodeRef,
512 pub italic: i32,
514 pub height: i32,
516 pub depth: i32,
518 pub options: u32,
520 pub class: i32,
522 pub new_hlist: NodeRef,
524}
525
526pub const DEFAULT_CODE: i32 = 0o10000000000;
529
530#[allow(missing_docs)]
532pub mod noad_sub {
533 pub const ORD: u16 = 0;
534 pub const OP_DISPLAY_LIMITS: u16 = 1;
535 pub const OP_LIMITS: u16 = 2;
536 pub const OP_NO_LIMITS: u16 = 3;
537 pub const BIN: u16 = 4;
538 pub const REL: u16 = 5;
539 pub const OPEN: u16 = 6;
540 pub const CLOSE: u16 = 7;
541 pub const PUNCT: u16 = 8;
542 pub const INNER: u16 = 9;
543 pub const UNDER: u16 = 10;
544 pub const OVER: u16 = 11;
545 pub const VCENTER: u16 = 12;
546}
547
548#[allow(missing_docs)]
550pub mod radical_sub {
551 pub const RADICAL: u16 = 0;
552 pub const URADICAL: u16 = 1;
553 pub const UROOT: u16 = 2;
554 pub const UUNDERDELIMITER: u16 = 3;
555 pub const UOVERDELIMITER: u16 = 4;
556 pub const UDELIMITERUNDER: u16 = 5;
557 pub const UDELIMITEROVER: u16 = 6;
558 pub const UHEXTENSIBLE: u16 = 7;
559}
560
561#[allow(missing_docs)]
563pub mod fence_sub {
564 pub const UNSET: u16 = 0;
565 pub const LEFT: u16 = 1;
566 pub const MIDDLE: u16 = 2;
567 pub const RIGHT: u16 = 3;
568 pub const NO: u16 = 4;
569}
570
571#[allow(missing_docs)]
573pub mod accent_sub {
574 pub const BOTH_FLEXIBLE: u16 = 0;
575 pub const FIXED_TOP: u16 = 1;
576 pub const FIXED_BOTTOM: u16 = 2;
577 pub const FIXED_BOTH: u16 = 3;
578}
579
580#[allow(missing_docs)]
582pub mod noad_opt {
583 pub const SET: u32 = 0x08;
584 pub const AXIS: u32 = 0x02 | SET;
585 pub const NO_AXIS: u32 = 0x04 | SET;
586 pub const EXACT: u32 = 0x10 | SET;
587 pub const LEFT: u32 = 0x11 | SET;
588 pub const MIDDLE: u32 = 0x12 | SET;
589 pub const RIGHT: u32 = 0x14 | SET;
590 pub const NO_SUB_SCRIPT: u32 = 0x21 | SET;
591 pub const NO_SUPER_SCRIPT: u32 = 0x22 | SET;
592 pub const OVERLAY: u32 = 0x100;
594}
595
596#[derive(Clone, Debug, PartialEq)]
598pub enum Whatsit {
599 Open {
601 stream: u32,
603 name: Vec<u8>,
605 },
606 Write {
608 stream: i32,
610 data: TokenList,
612 },
613 Close {
615 stream: u32,
617 },
618 Special {
620 data: Vec<u8>,
622 },
623 LateLua {
625 data: LateData,
627 name: Vec<u8>,
629 },
630 PdfLiteral {
632 mode: u8,
634 data: LateData,
636 late: bool,
638 },
639 SavePos,
641 PdfColorstack {
643 stack: i32,
645 cmd: u8,
647 data: Vec<u8>,
649 },
650 PdfSetmatrix {
652 data: Vec<u8>,
654 },
655 PdfSave,
657 PdfRestore,
659 PdfAnnot {
661 dims: [i32; 3],
663 objnum: i32,
665 data: Vec<u8>,
667 },
668 PdfStartLink {
670 dims: [i32; 3],
672 objnum: i32,
674 attr: Vec<u8>,
676 action: crate::pdfext::PdfAction,
678 },
679 PdfEndLink,
681 PdfDest {
683 id: crate::pdfext::DestId,
685 view: crate::pdfext::DestView,
687 structure: Option<i32>,
690 },
691 PdfRefobj {
693 objnum: i32,
695 },
696 PdfLinkState {
698 state: i32,
700 },
701 UserDefined {
703 user_id: i32,
705 value: UserValue,
707 },
708 Other {
710 fields: Vec<i64>,
712 data: Vec<u8>,
714 },
715}
716
717#[derive(Clone, Debug, PartialEq)]
719pub enum LateData {
720 Tokens(TokenList),
722 Bytes(Vec<u8>),
724 Lua {
727 data: Vec<u8>,
729 reference: i32,
731 },
732 Function {
736 reference: i32,
738 },
739}
740
741impl LateData {
742 pub fn bytes(&self) -> Option<&[u8]> {
744 match self {
745 LateData::Bytes(b) | LateData::Lua { data: b, .. } => Some(b),
746 LateData::Tokens(_) | LateData::Function { .. } => None,
747 }
748 }
749}
750
751#[derive(Clone, Debug, PartialEq)]
754pub enum UserValue {
755 Int(i32),
757 Str(Vec<u8>),
759 Tokens(TokenList),
761 Nodes(NodeRef),
763 Lua(i32),
765 Attr,
767}
768
769#[derive(Clone, Debug, PartialEq)]
771pub struct Node {
772 pub id: u8,
774 pub subtype: u16,
776 pub next: NodeRef,
778 pub prev: NodeRef,
780 pub attr: Option<AttrList>,
782 pub data: NodeData,
784}
785
786impl Node {
787 fn temp() -> Node {
789 Node {
790 id: id::TEMP,
791 subtype: 0,
792 next: NodeRef::NULL,
793 prev: NodeRef::NULL,
794 attr: None,
795 data: NodeData::Temp,
796 }
797 }
798}
799
800#[derive(Debug, Clone, Copy, PartialEq, Eq)]
803pub enum PropEvent {
804 Flush(u32),
806 Copy(u32, u32),
808}
809
810#[derive(Debug, Clone, Default)]
814pub struct Properties {
815 pub nodes: std::collections::HashSet<u32>,
817 pub flush: bool,
819 pub copy: bool,
821 pub events: Vec<PropEvent>,
823}
824
825#[derive(Debug, Clone)]
827pub struct Nodes {
828 nodes: Vec<Node>,
829 copy_depth: u32,
831 sink: Node,
834 free: Vec<u32>,
835 pub in_use: usize,
837 pub props: Properties,
839 pub sync: Option<Box<SyncFields>>,
842 pub double_free: Option<(u8, u32)>,
846 pub par_temp: NodeRef,
849 pub lua_refs: LuaRefs,
851}
852
853#[derive(Debug, Clone, Default)]
860pub struct LuaRefs {
861 pub next: i32,
863 pub free: Vec<i32>,
865 pub copies: Vec<(i32, i32)>,
868}
869
870impl LuaRefs {
871 pub fn take(&mut self) -> i32 {
873 if let Some(r) = self.free.pop() {
874 return r;
875 }
876 if self.next == 0 {
877 self.next = 780;
878 }
879 let r = self.next;
880 self.next += 1;
881 r
882 }
883
884 pub fn release(&mut self, r: i32) {
886 if r > 0 {
887 self.free.push(r);
888 }
889 }
890
891 pub fn font_defined(&mut self, temporary: bool) {
894 if temporary {
895 let t = self.take();
896 self.take();
897 self.release(t);
898 } else {
899 self.take();
900 }
901 }
902}
903
904fn lua_ref_mut(data: &mut NodeData) -> Option<&mut i32> {
906 match data {
907 NodeData::Whatsit(w) => match &mut **w {
908 Whatsit::LateLua {
909 data: LateData::Lua { reference, .. } | LateData::Function { reference },
910 ..
911 }
912 | Whatsit::PdfLiteral {
913 data: LateData::Lua { reference, .. },
914 ..
915 } => Some(reference),
916 Whatsit::UserDefined {
917 value: UserValue::Lua(r),
918 ..
919 } if *r > 0 => Some(r),
920 _ => None,
921 },
922 _ => None,
923 }
924}
925
926#[derive(Debug, Clone, Default)]
934pub struct SyncFields {
935 pub cur: (u32, i32),
937 fields: Vec<(u32, i32)>,
938}
939
940impl SyncFields {
941 #[inline]
942 fn set(&mut self, i: u32, f: (u32, i32)) {
943 let i = i as usize;
944 if i >= self.fields.len() {
945 self.fields.resize(i + 1, (0, 0));
946 }
947 self.fields[i] = f;
948 }
949}
950
951impl Default for Nodes {
952 fn default() -> Self {
953 Self::new()
954 }
955}
956
957impl Nodes {
958 pub fn new() -> Self {
960 Nodes {
961 nodes: vec![Node::temp()],
962 copy_depth: 0,
963 sink: Node::temp(),
964 free: Vec::new(),
965 in_use: 0,
966 props: Properties::default(),
967 sync: None,
968 lua_refs: LuaRefs::default(),
969 double_free: None,
970 par_temp: NodeRef::NULL,
971 }
972 }
973
974 pub fn enable_sync(&mut self) {
976 if self.sync.is_none() {
977 self.sync = Some(Box::default());
978 }
979 }
980
981 #[inline]
983 pub fn sync_fields(&self, p: NodeRef) -> (u32, i32) {
984 self.sync
985 .as_ref()
986 .and_then(|s| s.fields.get(p.0 as usize).copied())
987 .unwrap_or((0, 0))
988 }
989
990 pub fn set_sync_fields(&mut self, p: NodeRef, f: (u32, i32)) {
992 if p.0 as usize >= self.nodes.len() {
993 return;
994 }
995 if let Some(s) = self.sync.as_deref_mut() {
996 s.set(p.0, f);
997 }
998 }
999
1000 pub fn sync_as_copied(&mut self, p: NodeRef) {
1004 if let Some(s) = self.sync.as_deref_mut() {
1005 let cur = s.cur;
1006 s.set(p.0, cur);
1007 }
1008 }
1009
1010 #[inline]
1012 fn at(&self, p: NodeRef) -> &Node {
1013 self.nodes.get(p.0 as usize).unwrap_or(&self.nodes[0])
1014 }
1015
1016 #[inline]
1019 fn at_mut(&mut self, p: NodeRef) -> &mut Node {
1020 match self.nodes.get_mut(p.0 as usize) {
1021 Some(n) => n,
1022 None => {
1023 self.sink = Node::temp();
1024 &mut self.sink
1025 }
1026 }
1027 }
1028
1029 pub fn capacity(&self) -> usize {
1031 self.nodes.len()
1032 }
1033
1034 pub fn alloc(&mut self, id: u8, subtype: u16, data: NodeData) -> NodeRef {
1036 let node = Node {
1037 id,
1038 subtype,
1039 next: NodeRef::NULL,
1040 prev: NodeRef::NULL,
1041 attr: None,
1042 data,
1043 };
1044 self.in_use += 1;
1045 let p = if let Some(i) = self.free.pop() {
1046 self.nodes[i as usize] = node;
1047 NodeRef(i)
1048 } else {
1049 self.nodes.push(node);
1050 NodeRef(self.nodes.len() as u32 - 1)
1051 };
1052 if let Some(s) = self.sync.as_deref_mut() {
1053 let f = if id == id::KERN || id == id::GLYPH {
1054 (0, 0)
1055 } else {
1056 s.cur
1057 };
1058 s.set(p.0, f);
1059 }
1060 p
1061 }
1062
1063 pub fn free(&mut self, p: NodeRef) {
1065 if p.is_null() || p.0 as usize >= self.nodes.len() {
1068 return;
1069 }
1070 if self.is_free(p) {
1071 if self.double_free.is_none() {
1072 self.double_free = Some((self.at(p).subtype as u8, p.0));
1073 }
1074 return;
1075 }
1076 let t = self.at(p).id;
1078 self.at_mut(p).subtype = u16::from(t);
1079 if let Some(r) = lua_ref_mut(&mut self.at_mut(p).data) {
1080 let r = *r;
1081 self.lua_refs.release(r);
1082 }
1083 self.at_mut(p).id = id::FREE;
1084 self.at_mut(p).data = NodeData::Temp;
1085 self.at_mut(p).attr = None;
1086 self.free.push(p.0);
1087 self.in_use -= 1;
1088 if !self.props.nodes.is_empty() && self.props.nodes.remove(&p.0) && self.props.flush {
1089 self.props.events.push(PropEvent::Flush(p.0));
1090 }
1091 }
1092
1093 pub fn lua_ref_of(&mut self, p: NodeRef) -> Option<i32> {
1095 lua_ref_mut(&mut self.at_mut(p).data).map(|r| *r)
1096 }
1097
1098 #[inline]
1100 pub fn is_free(&self, p: NodeRef) -> bool {
1101 self.at(p).id == id::FREE
1102 }
1103
1104 #[inline]
1106 pub fn get(&self, p: NodeRef) -> &Node {
1107 self.at(p)
1108 }
1109
1110 #[inline]
1112 pub fn get_mut(&mut self, p: NodeRef) -> &mut Node {
1113 self.at_mut(p)
1114 }
1115
1116 #[inline]
1118 pub fn id(&self, p: NodeRef) -> u8 {
1119 self.at(p).id
1120 }
1121
1122 #[inline]
1124 pub fn next(&self, p: NodeRef) -> NodeRef {
1125 self.at(p).next
1126 }
1127
1128 #[inline]
1130 pub fn link(&mut self, p: NodeRef, q: NodeRef) {
1131 self.at_mut(p).next = q;
1132 if !q.is_null() {
1133 self.at_mut(q).prev = p;
1134 }
1135 }
1136
1137 pub fn box_data(&self, p: NodeRef) -> Option<&BoxData> {
1139 match &self.at(p).data {
1140 NodeData::Box(b) => Some(b),
1141 NodeData::Unset { b, .. } => Some(b),
1142 _ => None,
1143 }
1144 }
1145
1146 pub fn box_data_mut(&mut self, p: NodeRef) -> Option<&mut BoxData> {
1148 match &mut self.at_mut(p).data {
1149 NodeData::Box(b) => Some(b),
1150 NodeData::Unset { b, .. } => Some(b),
1151 _ => None,
1152 }
1153 }
1154
1155 pub fn tail_of(&self, mut p: NodeRef) -> NodeRef {
1157 if p.is_null() {
1158 return p;
1159 }
1160 loop {
1161 let n = self.next(p);
1162 if n.is_null() {
1163 return p;
1164 }
1165 p = n;
1166 }
1167 }
1168
1169 pub fn bounded_tail(&self, mut p: NodeRef) -> Option<NodeRef> {
1172 if p.is_null() {
1173 return Some(p);
1174 }
1175 for _ in 0..self.nodes.len() {
1176 let n = self.next(p);
1177 if n.is_null() {
1178 return Some(p);
1179 }
1180 p = n;
1181 }
1182 None
1183 }
1184
1185 pub fn flush_list(&mut self, p: NodeRef) {
1187 let mut stack: Vec<NodeRef> = Vec::new();
1188 let mut p = p;
1189 loop {
1190 while !p.is_null() {
1191 if self.is_free(p) {
1192 self.free(p);
1195 break;
1196 }
1197 let next = self.next(p);
1198 match &self.at(p).data {
1199 NodeData::Box(b) => stack.push(b.head),
1200 NodeData::Unset { b, .. } => stack.push(b.head),
1201 NodeData::Ins { head, .. } | NodeData::Adjust { head } => stack.push(*head),
1202 NodeData::Disc {
1203 pre, post, replace, ..
1204 } => {
1205 stack.push(*pre);
1206 stack.push(*post);
1207 stack.push(*replace);
1208 }
1209 NodeData::Glue { leader, .. } => stack.push(*leader),
1210 NodeData::Glyph(g) => {
1211 if !g.components.is_null() {
1212 stack.push(g.components);
1213 }
1214 }
1215 NodeData::LocalPar {
1216 box_left,
1217 box_right,
1218 ..
1219 } => {
1220 stack.push(*box_left);
1221 stack.push(*box_right);
1222 }
1223 NodeData::Noad(n) => stack.extend([
1224 n.nucleus,
1225 n.sub,
1226 n.sup,
1227 n.left,
1228 n.degree,
1229 n.accent,
1230 n.bot_accent,
1231 n.new_hlist,
1232 ]),
1233 NodeData::Fraction(f) => {
1234 stack.extend([f.num, f.denom, f.left, f.right, f.middle, f.new_hlist])
1235 }
1236 NodeData::Fence(f) => stack.extend([f.delim, f.new_hlist]),
1237 NodeData::Choice(c) => stack.extend(c.iter().copied()),
1238 NodeData::SubList { head } => stack.push(*head),
1239 _ => {}
1240 }
1241 self.free(p);
1242 p = next;
1243 }
1244 match stack.pop() {
1245 Some(q) => p = q,
1246 None => return,
1247 }
1248 }
1249 }
1250
1251 pub fn copy_list(&mut self, mut p: NodeRef) -> NodeRef {
1253 let mut head = NodeRef::NULL;
1254 let mut tail = NodeRef::NULL;
1255 if self.copy_depth >= MAX_NESTING {
1258 return head;
1259 }
1260 self.copy_depth += 1;
1261 let mut left = self.nodes.len();
1264 while !p.is_null() && left > 0 {
1265 left -= 1;
1266 let q = self.copy_node(p);
1267 if head.is_null() {
1268 head = q;
1269 } else {
1270 self.link(tail, q);
1271 }
1272 tail = q;
1273 p = self.next(p);
1274 }
1275 self.copy_depth -= 1;
1276 head
1277 }
1278
1279 pub fn copy_node(&mut self, p: NodeRef) -> NodeRef {
1281 let mut node = self.at(p).clone();
1282 node.next = NodeRef::NULL;
1283 node.prev = NodeRef::NULL;
1284 match &mut node.data {
1285 NodeData::Box(b) => b.head = self.copy_list(b.head),
1286 NodeData::Unset { b, .. } => b.head = self.copy_list(b.head),
1287 NodeData::Ins { head, .. } | NodeData::Adjust { head } => *head = self.copy_list(*head),
1288 NodeData::Disc {
1289 pre, post, replace, ..
1290 } => {
1291 *pre = self.copy_list(*pre);
1292 *post = self.copy_list(*post);
1293 *replace = self.copy_list(*replace);
1294 }
1295 NodeData::Glue { leader, .. } => *leader = self.copy_list(*leader),
1296 NodeData::Glyph(g) => g.components = self.copy_list(g.components),
1297 NodeData::LocalPar {
1298 box_left,
1299 box_right,
1300 ..
1301 } => {
1302 *box_left = self.copy_list(*box_left);
1303 *box_right = self.copy_list(*box_right);
1304 }
1305 NodeData::Noad(n) => {
1306 for f in [
1307 &mut n.nucleus,
1308 &mut n.sub,
1309 &mut n.sup,
1310 &mut n.left,
1311 &mut n.degree,
1312 &mut n.accent,
1313 &mut n.bot_accent,
1314 &mut n.new_hlist,
1315 ] {
1316 *f = self.copy_list(*f);
1317 }
1318 }
1319 NodeData::Fraction(fr) => {
1320 for f in [
1321 &mut fr.num,
1322 &mut fr.denom,
1323 &mut fr.left,
1324 &mut fr.right,
1325 &mut fr.middle,
1326 &mut fr.new_hlist,
1327 ] {
1328 *f = self.copy_list(*f);
1329 }
1330 }
1331 NodeData::Fence(fe) => {
1332 fe.delim = self.copy_list(fe.delim);
1333 fe.new_hlist = self.copy_list(fe.new_hlist);
1334 }
1335 NodeData::Choice(c) => {
1336 for f in c.iter_mut() {
1337 *f = self.copy_list(*f);
1338 }
1339 }
1340 NodeData::SubList { head } => *head = self.copy_list(*head),
1341 _ => {}
1342 }
1343 if let Some(r) = lua_ref_mut(&mut node.data) {
1344 let old = *r;
1345 let new = self.lua_refs.take();
1346 *r = new;
1347 self.lua_refs.copies.push((new, old));
1348 }
1349 self.in_use += 1;
1350 let q = if let Some(i) = self.free.pop() {
1351 self.nodes[i as usize] = node;
1352 NodeRef(i)
1353 } else {
1354 self.nodes.push(node);
1355 NodeRef(self.nodes.len() as u32 - 1)
1356 };
1357 if self.props.copy && self.props.nodes.contains(&p.0) {
1358 self.props.nodes.insert(q.0);
1359 self.props.events.push(PropEvent::Copy(p.0, q.0));
1360 }
1361 if self.sync.is_some() {
1362 let id = self.at(q).id;
1363 let f = if id == id::KERN || id == id::MATH {
1364 self.sync.as_ref().map_or((0, 0), |s| s.cur)
1365 } else {
1366 self.sync_fields(p)
1367 };
1368 self.set_sync_fields(q, f);
1369 }
1370 q
1371 }
1372
1373 pub fn new_null_box(&mut self, hlist: bool) -> NodeRef {
1375 self.alloc(
1376 if hlist { id::HLIST } else { id::VLIST },
1377 0,
1378 NodeData::Box(Box::default()),
1379 )
1380 }
1381
1382 pub fn new_glue(&mut self, spec: Glue, subtype: u16) -> NodeRef {
1384 self.alloc(
1385 id::GLUE,
1386 subtype,
1387 NodeData::Glue {
1388 spec,
1389 leader: NodeRef::NULL,
1390 },
1391 )
1392 }
1393
1394 pub fn new_kern(&mut self, w: i32, subtype: u16) -> NodeRef {
1396 self.alloc(
1397 id::KERN,
1398 subtype,
1399 NodeData::Kern {
1400 kern: w,
1401 expansion_factor: 0,
1402 },
1403 )
1404 }
1405
1406 pub fn new_penalty(&mut self, m: i32, subtype: u16) -> NodeRef {
1408 self.alloc(id::PENALTY, subtype, NodeData::Penalty { penalty: m })
1409 }
1410
1411 pub fn new_temp(&mut self) -> NodeRef {
1413 self.alloc(id::TEMP, 0, NodeData::Temp)
1414 }
1415
1416 pub fn new_glyph(&mut self, font: u32, chr: u32) -> NodeRef {
1418 self.alloc(
1419 id::GLYPH,
1420 0,
1421 NodeData::Glyph(GlyphData {
1422 chr,
1423 font,
1424 ..GlyphData::default()
1425 }),
1426 )
1427 }
1428
1429 pub fn new_rule(&mut self, width: i32, height: i32, depth: i32) -> NodeRef {
1431 self.alloc(
1432 id::RULE,
1433 0,
1434 NodeData::Rule {
1435 width,
1436 depth,
1437 height,
1438 dir: 0,
1439 index: 0,
1440 left: 0,
1441 right: 0,
1442 },
1443 )
1444 }
1445
1446 pub fn new_disc(&mut self, subtype: u16, penalty: i32) -> NodeRef {
1448 self.alloc(
1449 id::DISC,
1450 subtype,
1451 NodeData::Disc {
1452 pre: NodeRef::NULL,
1453 post: NodeRef::NULL,
1454 replace: NodeRef::NULL,
1455 penalty,
1456 },
1457 )
1458 }
1459
1460 pub fn new_math(&mut self, surround: i32, subtype: u16) -> NodeRef {
1462 self.alloc(
1463 id::MATH,
1464 subtype,
1465 NodeData::Math {
1466 surround,
1467 glue: Glue::ZERO,
1468 },
1469 )
1470 }
1471
1472 #[inline]
1474 pub fn data(&self, p: NodeRef) -> &NodeData {
1475 &self.at(p).data
1476 }
1477
1478 #[inline]
1480 pub fn data_mut(&mut self, p: NodeRef) -> &mut NodeData {
1481 &mut self.at_mut(p).data
1482 }
1483
1484 #[inline]
1486 pub fn subtype(&self, p: NodeRef) -> u16 {
1487 self.at(p).subtype
1488 }
1489
1490 #[inline]
1492 pub fn set_subtype(&mut self, p: NodeRef, s: u16) {
1493 self.at_mut(p).subtype = s;
1494 }
1495
1496 #[inline]
1498 pub fn prev(&self, p: NodeRef) -> NodeRef {
1499 self.at(p).prev
1500 }
1501
1502 #[inline]
1504 pub fn set_next(&mut self, p: NodeRef, q: NodeRef) {
1505 self.at_mut(p).next = q;
1506 }
1507
1508 #[inline]
1510 pub fn set_prev(&mut self, p: NodeRef, q: NodeRef) {
1511 self.at_mut(p).prev = q;
1512 }
1513
1514 #[inline]
1516 pub fn is_glyph(&self, p: NodeRef) -> bool {
1517 self.at(p).id == id::GLYPH
1518 }
1519
1520 #[inline]
1522 pub fn glyph(&self, p: NodeRef) -> Option<&GlyphData> {
1523 match &self.at(p).data {
1524 NodeData::Glyph(g) => Some(g),
1525 _ => None,
1526 }
1527 }
1528
1529 #[inline]
1531 pub fn glyph_mut(&mut self, p: NodeRef) -> Option<&mut GlyphData> {
1532 match &mut self.at_mut(p).data {
1533 NodeData::Glyph(g) => Some(g),
1534 _ => None,
1535 }
1536 }
1537
1538 #[inline]
1540 pub fn glue_spec(&self, p: NodeRef) -> Glue {
1541 match &self.at(p).data {
1542 NodeData::Glue { spec, .. } => *spec,
1543 NodeData::Math { glue, .. } => *glue,
1544 _ => Glue::ZERO,
1545 }
1546 }
1547
1548 pub fn width(&self, p: NodeRef) -> i32 {
1552 match &self.at(p).data {
1553 NodeData::Box(b) => b.width,
1554 NodeData::Unset { b, .. } => b.width,
1555 NodeData::Rule { width, .. } => *width,
1556 NodeData::Glue { spec, .. } => spec.width,
1557 NodeData::Kern {
1558 kern,
1559 expansion_factor,
1560 } => *kern + *expansion_factor,
1561 NodeData::Math { surround, glue } => {
1562 if glue.width != 0 || glue.stretch != 0 || glue.shrink != 0 {
1563 glue.width
1564 } else {
1565 *surround
1566 }
1567 }
1568 NodeData::MarginKern { width, .. } => *width,
1569 _ => 0,
1570 }
1571 }
1572
1573 pub fn penalty(&self, p: NodeRef) -> i32 {
1575 match &self.at(p).data {
1576 NodeData::Penalty { penalty } => *penalty,
1577 NodeData::Disc { penalty, .. } => *penalty,
1578 _ => 0,
1579 }
1580 }
1581
1582 pub fn disc_lists(&self, p: NodeRef) -> (NodeRef, NodeRef, NodeRef) {
1584 match &self.at(p).data {
1585 NodeData::Disc {
1586 pre, post, replace, ..
1587 } => (*pre, *post, *replace),
1588 _ => (NodeRef::NULL, NodeRef::NULL, NodeRef::NULL),
1589 }
1590 }
1591
1592 pub fn set_disc_lists(&mut self, p: NodeRef, l: (NodeRef, NodeRef, NodeRef)) {
1594 if let NodeData::Disc {
1595 pre, post, replace, ..
1596 } = &mut self.at_mut(p).data
1597 {
1598 *pre = l.0;
1599 *post = l.1;
1600 *replace = l.2;
1601 }
1602 for q in [l.0, l.1, l.2] {
1603 if !q.is_null() {
1604 self.at_mut(q).prev = NodeRef::NULL;
1605 }
1606 }
1607 }
1608
1609 pub fn list_ptr(&self, p: NodeRef) -> NodeRef {
1611 match &self.at(p).data {
1612 NodeData::Box(b) => b.head,
1613 NodeData::Unset { b, .. } => b.head,
1614 NodeData::Ins { head, .. } | NodeData::Adjust { head } => *head,
1615 _ => NodeRef::NULL,
1616 }
1617 }
1618
1619 pub fn set_list_ptr(&mut self, p: NodeRef, l: NodeRef) {
1621 match &mut self.at_mut(p).data {
1622 NodeData::Box(b) => b.head = l,
1623 NodeData::Unset { b, .. } => b.head = l,
1624 NodeData::Ins { head, .. } | NodeData::Adjust { head } => *head = l,
1625 _ => {}
1626 }
1627 }
1628
1629 #[inline]
1631 pub fn attr(&self, p: NodeRef) -> Option<&AttrList> {
1632 self.at(p).attr.as_ref()
1633 }
1634
1635 #[inline]
1637 pub fn set_attr(&mut self, p: NodeRef, a: Option<AttrList>) {
1638 self.at_mut(p).attr = a;
1639 }
1640
1641 #[inline]
1643 pub fn noad(&self, p: NodeRef) -> Option<&NoadData> {
1644 match &self.at(p).data {
1645 NodeData::Noad(n) => Some(n),
1646 _ => None,
1647 }
1648 }
1649
1650 #[inline]
1652 pub fn noad_mut(&mut self, p: NodeRef) -> Option<&mut NoadData> {
1653 match &mut self.at_mut(p).data {
1654 NodeData::Noad(n) => Some(n),
1655 _ => None,
1656 }
1657 }
1658
1659 pub fn list_ptr_kernel(&self, p: NodeRef) -> NodeRef {
1661 if p.is_null() {
1662 return NodeRef::NULL;
1663 }
1664 match &self.at(p).data {
1665 NodeData::SubList { head } => *head,
1666 _ => NodeRef::NULL,
1667 }
1668 }
1669
1670 pub fn set_kernel_list(&mut self, p: NodeRef, l: NodeRef) {
1672 if p.is_null() {
1673 return;
1674 }
1675 if let NodeData::SubList { head } = &mut self.at_mut(p).data {
1676 *head = l;
1677 }
1678 }
1679
1680 pub fn scripts_allowed(&self, p: NodeRef) -> bool {
1682 matches!(self.at(p).data, NodeData::Noad(_))
1683 && matches!(self.id(p), id::NOAD | id::RADICAL | id::ACCENT)
1684 }
1685
1686 pub fn list_len(&self, mut p: NodeRef) -> usize {
1688 let mut n = 0;
1689 while !p.is_null() {
1690 n += 1;
1691 p = self.next(p);
1692 }
1693 n
1694 }
1695}
1696
1697pub fn glue_ratio(num: i32, den: i32) -> f64 {
1702 f64::from((f64::from(num) / f64::from(den)) as f32)
1703}
1704
1705#[cfg(test)]
1706mod tests {
1707 use super::*;
1708
1709 #[test]
1710 fn glue_ratio_is_single_precision() {
1711 assert_eq!(glue_ratio(1021537, 873808), 1.1690634489059448);
1713 }
1714
1715 #[test]
1716 fn alloc_link_copy_flush() {
1717 let mut n = Nodes::new();
1718 let b = n.new_null_box(true);
1719 let k = n.new_kern(5, kern_sub::USER);
1720 let g = n.new_glue(Glue::fixed(7), glue_sub::USER);
1721 n.link(k, g);
1722 n.box_data_mut(b).unwrap().head = k;
1723 assert_eq!(n.in_use, 3);
1724 let c = n.copy_node(b);
1725 assert_eq!(n.in_use, 6);
1726 let ch = n.box_data(c).unwrap().head;
1727 assert_ne!(ch, k);
1728 assert_eq!(n.get(n.next(ch)).data, n.get(g).data);
1729 n.flush_list(c);
1730 n.flush_list(b);
1731 assert_eq!(n.in_use, 0);
1732 }
1733
1734 #[test]
1737 fn circular_list() {
1738 let mut n = Nodes::new();
1739 let a = n.new_kern(1, kern_sub::USER);
1740 let b = n.new_glue(Glue::fixed(2), glue_sub::USER);
1741 n.link(a, b);
1742 n.link(b, a);
1743 assert_eq!(n.bounded_tail(a), None);
1744 let c = n.copy_list(a);
1745 assert!(!c.is_null());
1746 assert_eq!(n.double_free, None);
1747 n.flush_list(a);
1748 assert_eq!(n.double_free, Some((id::KERN, a.0)));
1749 assert_eq!(type_name(id::KERN), "kern");
1750 }
1751}