1use crate::commands::primitives::PRIMITIVES;
3use crate::engine::filesystem::SourceRef;
4use crate::engine::fontsystem::Font;
5use crate::engine::state::State;
6use crate::engine::EngineTypes;
7use crate::tex::nodes::boxes::{TeXBox, ToOrSpread};
8use crate::tex::nodes::vertical::VNode;
9use crate::tex::nodes::{display_do_indent, Leaders, ListTarget, NodeTrait, NodeType, WhatsitNode};
10use crate::tex::numerics::NumSet;
11use crate::tex::numerics::{MuSkip, Skip, TeXDimen};
12use crate::tex::tokens::token_lists::TokenList;
13use either::Either;
14use std::cell::OnceCell;
15use std::fmt::{Debug, Formatter, Write};
16use std::marker::PhantomData;
17
18#[derive(Clone, Debug)]
25pub enum MathNode<ET: EngineTypes, S: MathFontStyleT<ET>> {
26 Atom(MathAtom<ET, S>),
28 Penalty(i32),
30 Mark(usize, TokenList<ET::Token>),
32 Whatsit(WhatsitNode<ET>),
34 HSkip(Skip<ET::Dim>),
36 MSkip { skip: MuSkip<ET::MuDim>, style: S },
38 HFil,
40 HFill,
42 HFilneg,
44 Hss,
46 Space,
48 HKern(ET::Dim),
50 MKern { kern: ET::MuDim, style: S },
52 Leaders(Leaders<ET>),
54 VRule {
56 width: Option<ET::Dim>,
58 height: Option<ET::Dim>,
60 depth: Option<ET::Dim>,
62 start: SourceRef<ET>,
64 end: SourceRef<ET>,
66 },
67 Over {
70 start: SourceRef<ET>,
72 end: SourceRef<ET>,
74 top: Box<[MathNode<ET, S>]>,
76 sep: Option<ET::Dim>,
78 bottom: Box<[MathNode<ET, S>]>,
80 left: Option<(ET::Char, S)>,
82 right: Option<(ET::Char, S)>,
84 },
85 Choice(S::Choice),
87 Marker(S::Markers),
89 Custom(ET::CustomNode),
91}
92impl<ET: EngineTypes> MathNode<ET, UnresolvedMathFontStyle<ET>> {
93 pub fn nodetype(&self) -> NodeType {
95 match self {
96 MathNode::Penalty(_) => NodeType::Penalty,
97 MathNode::VRule { .. } => NodeType::Rule,
98 MathNode::HKern(_) | MathNode::MKern { .. } => NodeType::Kern,
99 MathNode::Mark(_, _) => NodeType::Mark,
100 MathNode::Whatsit(_) => NodeType::WhatsIt,
101 MathNode::HSkip(_)
102 | MathNode::MSkip { .. }
103 | MathNode::Space
104 | MathNode::HFil
105 | MathNode::HFill
106 | MathNode::HFilneg
107 | MathNode::Hss => NodeType::Glue,
108 MathNode::Leaders(_) => NodeType::Glue,
109 MathNode::Custom(n) => n.nodetype(),
110 _ => NodeType::Math,
111 }
112 }
113 pub fn opaque(&self) -> bool {
115 match self {
116 MathNode::Mark(_, _) => true,
117 MathNode::Custom(n) => n.opaque(),
118 _ => false,
119 }
120 }
121}
122impl<ET: EngineTypes> NodeTrait<ET> for MathNode<ET, MathFontStyle<ET>> {
123 fn display_fmt(&self, indent: usize, f: &mut Formatter<'_>) -> std::fmt::Result {
124 match self {
125 MathNode::Penalty(p) => {
126 display_do_indent(indent, f)?;
127 write!(f, "<penalty:{}>", p)
128 }
129 MathNode::Mark(i, _) => {
130 display_do_indent(indent, f)?;
131 write!(f, "<mark:{}>", i)
132 }
133 MathNode::Over {
134 top,
135 sep,
136 bottom,
137 left,
138 right,
139 ..
140 } => {
141 display_do_indent(indent, f)?;
142 write!(f, "<over")?;
143 if let Some(s) = sep {
144 write!(f, " sep={}", s)?;
145 }
146 f.write_char('>')?;
147 if let Some((l, _)) = left {
148 display_do_indent(indent + 2, f)?;
149 write!(f, "<left-delim = {}/>", l)?;
150 }
151 display_do_indent(indent + 2, f)?;
152 f.write_str("<top>")?;
153 for c in top.iter() {
154 c.display_fmt(indent + 4, f)?;
155 }
156 display_do_indent(indent + 2, f)?;
157 f.write_str("</top>")?;
158 display_do_indent(indent + 2, f)?;
159 f.write_str("<bottom>")?;
160 for c in bottom.iter() {
161 c.display_fmt(indent + 4, f)?;
162 }
163 display_do_indent(indent + 2, f)?;
164 f.write_str("</bottom>")?;
165 if let Some((r, _)) = right {
166 display_do_indent(indent + 2, f)?;
167 write!(f, "<right-delim = {}/>", r)?;
168 }
169 display_do_indent(indent, f)?;
170 write!(f, "</over>")
171 }
172 MathNode::Marker(m) => m.display_fmt(indent, f),
173 MathNode::Choice(c) => c.display_fmt(indent, f),
174 MathNode::Leaders(l) => l.display_fmt(indent, f),
175 MathNode::VRule {
176 width,
177 height,
178 depth,
179 ..
180 } => {
181 write!(f, "<vrule")?;
182 if let Some(w) = width {
183 write!(f, " width={}", w)?;
184 }
185 if let Some(h) = height {
186 write!(f, " height={}", h)?;
187 }
188 if let Some(d) = depth {
189 write!(f, " depth={}", d)?;
190 }
191 write!(f, ">")
192 }
193 MathNode::Whatsit(w) => {
194 display_do_indent(indent, f)?;
195 write!(f, "{:?}", w)
196 }
197 MathNode::HSkip(s) => write!(f, "<hskip:{}>", s),
198 MathNode::MSkip { skip, .. } => write!(f, "<mskip:{}>", skip),
199 MathNode::MKern { kern, .. } => write!(f, "<mkern:{}>", kern),
200 MathNode::HFil => write!(f, "<hfil>"),
201 MathNode::HFill => write!(f, "<hfill>"),
202 MathNode::HFilneg => write!(f, "<hfilneg>"),
203 MathNode::Hss => write!(f, "<hss>"),
204 MathNode::Space => write!(f, "<space>"),
205 MathNode::HKern(d) => write!(f, "<hkern:{}>", d),
206 MathNode::Custom(n) => n.display_fmt(indent, f),
207 MathNode::Atom(a) => a.display_fmt(indent, f),
208 }
209 }
210 fn height(&self) -> ET::Dim {
211 match self {
212 MathNode::VRule { height, .. } => height.unwrap_or_default(),
213 MathNode::Custom(n) => n.height(),
214 MathNode::Atom(a) => a.height(),
215 MathNode::Leaders(l) => l.height(),
216 MathNode::Choice(c) => c.height(),
217 MathNode::Over { top, sep, .. } => {
218 let mut inner = top
219 .iter()
220 .map(|c| c.height() + c.depth())
221 .max()
222 .unwrap_or_default();
223 match sep {
224 None => (),
225 Some(s) => inner = inner + s.scale_float(0.5) + ET::Dim::from_sp(65536 * 3), }
227 inner
228 }
229 _ => ET::Dim::default(),
230 }
231 }
232 fn width(&self) -> ET::Dim {
233 match self {
234 MathNode::VRule { width, .. } => width.unwrap_or(ET::Dim::from_sp(26214)),
235 MathNode::Custom(n) => n.width(),
236 MathNode::HKern(d) => *d,
237 MathNode::MKern { kern, style } => ET::Num::mudim_to_dim(*kern, style.get_em()),
238 MathNode::MSkip { skip, style } => ET::Num::mudim_to_dim(skip.base, style.get_em()),
239 MathNode::HSkip(s) => s.base,
240 MathNode::Space => ET::Dim::from_sp(65536 * 5), MathNode::Leaders(l) => l.width(),
242 MathNode::Atom(a) => a.width(),
243 MathNode::Choice(c) => c.width(),
244 MathNode::Over { top, bottom, .. } => {
245 let top: ET::Dim = top.iter().map(|c| c.width()).sum();
246 let bot: ET::Dim = bottom.iter().map(|c| c.width()).sum();
247 top.max(bot)
248 }
249 _ => ET::Dim::default(),
250 }
251 }
252 fn depth(&self) -> ET::Dim {
253 match self {
254 MathNode::VRule { depth, .. } => depth.unwrap_or_default(),
255 MathNode::Custom(n) => n.depth(),
256 MathNode::Atom(a) => a.depth(),
257 MathNode::Leaders(l) => l.depth(),
258 MathNode::Choice(c) => c.depth(),
259 MathNode::Over { bottom, sep, .. } => {
260 let mut inner = bottom
261 .iter()
262 .map(|c| c.height() + c.depth())
263 .max()
264 .unwrap_or_default();
265 match sep {
266 None => (),
267 Some(s) => inner = inner + s.scale_float(0.5) + ET::Dim::from_sp(65536 * 3), }
269 inner
270 }
271 _ => ET::Dim::default(),
272 }
273 }
274 fn nodetype(&self) -> NodeType {
275 match self {
276 MathNode::Penalty(_) => NodeType::Penalty,
277 MathNode::VRule { .. } => NodeType::Rule,
278 MathNode::HKern(_) | MathNode::MKern { .. } => NodeType::Kern,
279 MathNode::Mark(_, _) => NodeType::Mark,
280 MathNode::Whatsit(_) => NodeType::WhatsIt,
281 MathNode::HSkip(_)
282 | MathNode::MSkip { .. }
283 | MathNode::Space
284 | MathNode::HFil
285 | MathNode::HFill
286 | MathNode::HFilneg
287 | MathNode::Hss => NodeType::Glue,
288 MathNode::Leaders(_) => NodeType::Glue,
289 MathNode::Custom(n) => n.nodetype(),
290 _ => NodeType::Math,
291 }
292 }
293 fn opaque(&self) -> bool {
294 match self {
295 MathNode::Mark(_, _) => true,
296 MathNode::Custom(n) => n.opaque(),
297 _ => false,
298 }
299 }
300}
301
302#[derive(Clone, Copy, Eq, PartialEq, Debug)]
305pub struct MathStyle {
306 pub cramped: bool,
308 pub style: MathStyleType,
310}
311impl MathStyle {
312 pub fn sup(self) -> Self {
314 match self.style {
315 MathStyleType::Text | MathStyleType::Display => MathStyle {
316 cramped: self.cramped,
317 style: MathStyleType::Script,
318 },
319 MathStyleType::Script | MathStyleType::ScriptScript => MathStyle {
320 cramped: self.cramped,
321 style: MathStyleType::ScriptScript,
322 },
323 }
324 }
325 pub fn cramp(mut self) -> Self {
327 self.cramped = true;
328 self
329 }
330 pub fn sub(self) -> Self {
332 self.sup().cramp()
333 }
334 pub fn numerator(self) -> Self {
336 match self.style {
337 MathStyleType::Display => MathStyle {
338 cramped: self.cramped,
339 style: MathStyleType::Text,
340 },
341 MathStyleType::Text => MathStyle {
342 cramped: self.cramped,
343 style: MathStyleType::Script,
344 },
345 MathStyleType::Script | MathStyleType::ScriptScript => MathStyle {
346 cramped: self.cramped,
347 style: MathStyleType::ScriptScript,
348 },
349 }
350 }
351 pub fn denominator(self) -> Self {
353 self.numerator().cramp()
354 }
355}
356
357#[derive(Clone, Copy, Eq, PartialEq, Debug)]
359pub enum MathStyleType {
360 Display,
361 Text,
362 Script,
363 ScriptScript,
364}
365
366#[derive(Debug, Clone, Copy, PartialEq, Eq)]
368pub enum MathClass {
369 Ord = 0,
371 Op = 1,
373 Bin = 2,
375 Rel = 3,
377 Open = 4,
379 Close = 5,
381 Punct = 6,
383}
384impl From<u8> for MathClass {
385 fn from(v: u8) -> Self {
386 match v {
387 0 => MathClass::Ord,
388 1 => MathClass::Op,
389 2 => MathClass::Bin,
390 3 => MathClass::Rel,
391 4 => MathClass::Open,
392 5 => MathClass::Close,
393 6 => MathClass::Punct,
394 _ => panic!("Invalid math class {}", v),
395 }
396 }
397}
398
399pub trait MathFontStyleT<ET: EngineTypes>: Clone + Debug {
403 type Choice: MathChoiceT<ET>;
405 type Markers: Clone + Debug + NodeTrait<ET>;
407}
408#[derive(Debug, Clone)]
412pub struct UnresolvedMathFontStyle<ET: EngineTypes>(u8, PhantomData<ET>);
413impl<ET: EngineTypes> MathFontStyleT<ET> for UnresolvedMathFontStyle<ET> {
414 type Choice = UnresolvedMathChoice<ET>;
415 type Markers = UnresolvedMarkers;
416 }
418impl<ET: EngineTypes> UnresolvedMathFontStyle<ET> {
419 pub fn of_fam(fam: u8) -> Self {
421 Self(fam, PhantomData)
422 }
423 pub fn fam(&self) -> u8 {
425 self.0
426 }
427}
428
429#[derive(Debug, Clone)]
432pub struct MathFontStyle<ET: EngineTypes> {
433 pub style: MathStyleType,
434 pub cramped: bool,
435 pub font: ET::Font,
436}
437impl<ET: EngineTypes> MathFontStyleT<ET> for MathFontStyle<ET> {
438 type Choice = ResolvedChoice<ET>;
439 type Markers = PhantomData<ET>;
440}
441impl<ET: EngineTypes> MathFontStyle<ET> {
442 pub fn get_em(&self) -> ET::Dim {
444 self.font.get_dim(5)
445 }
446 pub fn get_font(&self) -> &ET::Font {
448 &self.font
449 }
450}
451impl<ET: EngineTypes> NodeTrait<ET> for PhantomData<ET> {
452 fn display_fmt(&self, _indent: usize, _f: &mut Formatter<'_>) -> std::fmt::Result {
453 Ok(())
454 }
455 fn height(&self) -> ET::Dim {
456 ET::Dim::default()
457 }
458 fn width(&self) -> ET::Dim {
459 ET::Dim::default()
460 }
461 fn depth(&self) -> ET::Dim {
462 ET::Dim::default()
463 }
464 fn nodetype(&self) -> NodeType {
465 NodeType::Math
466 }
467}
468
469pub trait MathChoiceT<ET: EngineTypes>: Clone + Debug {}
473
474#[derive(Clone, Debug)]
478pub struct UnresolvedMathChoice<ET: EngineTypes> {
479 pub display: Box<[MathNode<ET, UnresolvedMathFontStyle<ET>>]>,
480 pub text: Box<[MathNode<ET, UnresolvedMathFontStyle<ET>>]>,
481 pub script: Box<[MathNode<ET, UnresolvedMathFontStyle<ET>>]>,
482 pub scriptscript: Box<[MathNode<ET, UnresolvedMathFontStyle<ET>>]>,
483}
484impl<ET: EngineTypes> MathChoiceT<ET> for UnresolvedMathChoice<ET> {}
485
486pub struct ResolvedChoice<ET: EngineTypes>(pub Box<[MathNode<ET, MathFontStyle<ET>>]>);
489impl<ET: EngineTypes> Debug for ResolvedChoice<ET> {
490 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
491 f.write_str("<resolved_choice>")?;
492 for c in self.0.iter() {
493 c.display_fmt(2, f)?;
494 }
495 f.write_str("</resolved_choice>")
496 }
497}
498impl<ET: EngineTypes> Clone for ResolvedChoice<ET> {
499 fn clone(&self) -> Self {
500 Self(self.0.clone())
501 }
502}
503impl<ET: EngineTypes> MathChoiceT<ET> for ResolvedChoice<ET> {}
504impl<ET: EngineTypes> ResolvedChoice<ET> {
505 pub fn display_fmt(&self, indent: usize, f: &mut Formatter<'_>) -> std::fmt::Result {
507 for c in self.0.iter() {
508 c.display_fmt(indent, f)?;
509 }
510 Ok(())
511 }
512 pub fn width(&self) -> ET::Dim {
514 self.0.iter().map(|c| c.width()).sum()
515 }
516 pub fn height(&self) -> ET::Dim {
518 self.0.iter().map(|c| c.height()).max().unwrap_or_default()
519 }
520 pub fn depth(&self) -> ET::Dim {
522 self.0.iter().map(|c| c.depth()).max().unwrap_or_default()
523 }
524}
525
526#[derive(Debug, Copy, Clone)]
530pub enum UnresolvedMarkers {
531 Display,
532 Text,
533 Script,
534 ScriptScript,
535}
536impl<ET: EngineTypes> NodeTrait<ET> for UnresolvedMarkers {
537 fn display_fmt(&self, _indent: usize, f: &mut Formatter<'_>) -> std::fmt::Result {
538 match self {
539 UnresolvedMarkers::Display => f.write_str("<display>"),
540 UnresolvedMarkers::Text => f.write_str("<text>"),
541 UnresolvedMarkers::Script => f.write_str("<script>"),
542 UnresolvedMarkers::ScriptScript => f.write_str("<scriptscript>"),
543 }
544 }
545 fn height(&self) -> ET::Dim {
546 ET::Dim::default()
547 }
548 fn width(&self) -> ET::Dim {
549 ET::Dim::default()
550 }
551 fn depth(&self) -> ET::Dim {
552 ET::Dim::default()
553 }
554 fn nodetype(&self) -> NodeType {
555 NodeType::Math
556 }
557}
558
559#[derive(Clone, Debug)]
562pub struct MathAtom<ET: EngineTypes, S: MathFontStyleT<ET>> {
563 pub nucleus: MathNucleus<ET, S>,
564 pub sup: Option<Box<[MathNode<ET, S>]>>,
565 pub sub: Option<Box<[MathNode<ET, S>]>>,
566}
567impl<ET: EngineTypes, S: MathFontStyleT<ET>> MathAtom<ET, S> {
568 pub fn empty() -> Self {
570 Self {
571 nucleus: MathNucleus::Simple {
572 cls: MathClass::Ord,
573 kernel: MathKernel::Empty,
574 limits: None,
575 },
576 sup: None,
577 sub: None,
578 }
579 }
580}
581impl<ET: EngineTypes> NodeTrait<ET> for MathAtom<ET, MathFontStyle<ET>> {
582 fn display_fmt(&self, indent: usize, f: &mut Formatter<'_>) -> std::fmt::Result {
583 display_do_indent(indent, f)?;
584 if self.sub.is_none() || self.sup.is_none() {
585 return self.nucleus.display_fmt(indent, f);
586 }
587 f.write_str("<atom>")?;
588 self.nucleus.display_fmt(indent + 2, f)?;
589 if let Some(sup) = &self.sup {
590 display_do_indent(indent + 2, f)?;
591 f.write_str("<sup>")?;
592 for c in sup.iter() {
593 c.display_fmt(indent + 4, f)?;
594 }
595 display_do_indent(indent + 2, f)?;
596 f.write_str("</sup>")?;
597 }
598 if let Some(sub) = &self.sub {
599 display_do_indent(indent + 2, f)?;
600 f.write_str("<sub>")?;
601 for c in sub.iter() {
602 c.display_fmt(indent + 4, f)?;
603 }
604 display_do_indent(indent + 2, f)?;
605 f.write_str("</sub>")?;
606 }
607 display_do_indent(indent, f)?;
608 f.write_str("</atom>")
609 }
610 fn height(&self) -> ET::Dim {
611 if self.sup.is_none() {
612 return self.nucleus.height();
613 }
614 let h = self.nucleus.height();
615 let limits = matches!(
616 self.nucleus,
617 MathNucleus::Simple {
618 cls: MathClass::Op,
619 limits: Some(true),
620 ..
621 }
622 );
623 let sup = self
624 .sup
625 .as_ref()
626 .unwrap()
627 .iter()
628 .map(|c| c.height() + c.depth())
629 .max()
630 .unwrap_or_default();
631 if limits {
632 h + sup + ET::Dim::from_sp(65536 * 3) } else {
634 h + sup.scale_float(0.75) }
636 }
637 fn width(&self) -> ET::Dim {
638 if self.sup.is_none() && self.sub.is_none() {
639 return self.nucleus.width();
640 }
641 let w = self.nucleus.width();
642 let sup = match self.sup {
643 Some(ref ls) => ls.iter().map(|c| c.width()).sum(),
644 _ => ET::Dim::default(),
645 };
646 let sub = match self.sub {
647 Some(ref ls) => ls.iter().map(|c| c.width()).sum(),
648 _ => ET::Dim::default(),
649 };
650 let limits = matches!(
651 self.nucleus,
652 MathNucleus::Simple {
653 cls: MathClass::Op,
654 limits: Some(true),
655 ..
656 }
657 );
658 if limits {
659 w.max(sup).max(sub)
660 } else {
661 w + sup.max(sub) + ET::Dim::from_sp(65536 * 3) }
663 }
664 fn depth(&self) -> ET::Dim {
665 if self.sub.is_none() {
666 return self.nucleus.depth();
667 }
668 let h = self.nucleus.depth();
669 let limits = matches!(
670 self.nucleus,
671 MathNucleus::Simple {
672 cls: MathClass::Op,
673 limits: Some(true),
674 ..
675 }
676 );
677 let sub = self
678 .sub
679 .as_ref()
680 .unwrap()
681 .iter()
682 .map(|c| c.depth() + c.height())
683 .max()
684 .unwrap_or_default();
685 if limits {
686 h + sub + ET::Dim::from_sp(65536 * 3) } else {
688 h + sub.scale_float(0.75) }
691 }
692
693 fn nodetype(&self) -> NodeType {
694 NodeType::Math
695 }
696}
697
698#[derive(Clone, Debug)]
700pub enum MathNucleus<ET: EngineTypes, S: MathFontStyleT<ET>> {
701 Simple {
705 cls: MathClass,
706 kernel: MathKernel<ET, S>,
707 limits: Option<bool>,
708 },
709 Inner(MathKernel<ET, S>),
711 LeftRight {
713 start: SourceRef<ET>,
714 left: Option<(ET::Char, S)>,
715 children: Box<[MathNode<ET, S>]>,
716 right: Option<(ET::Char, S)>,
717 end: SourceRef<ET>,
718 },
719 Middle(ET::Char, S),
721 Overline(MathKernel<ET, S>),
723 Underline(MathKernel<ET, S>),
725 Accent {
727 accent: (ET::Char, S),
728 inner: Box<[MathNode<ET, S>]>,
729 },
730 Radical {
732 rad: (ET::Char, S),
733 inner: Box<[MathNode<ET, S>]>,
734 },
735 VCenter {
737 start: SourceRef<ET>,
738 end: SourceRef<ET>,
739 children: Box<[VNode<ET>]>,
740 scaled: ToOrSpread<ET::Dim>,
741 },
742}
743impl<ET: EngineTypes> NodeTrait<ET> for MathNucleus<ET, MathFontStyle<ET>> {
744 fn display_fmt(&self, indent: usize, f: &mut Formatter<'_>) -> std::fmt::Result {
745 display_do_indent(indent, f)?;
746 match self {
747 MathNucleus::Simple {
748 cls: MathClass::Op,
749 kernel,
750 limits,
751 } => {
752 write!(f, "<mathop limits={:?}>", limits)?;
753 kernel.display_fmt(indent + 2, f)?;
754 display_do_indent(indent, f)?;
755 f.write_str("</mathop>")
756 }
757 MathNucleus::Simple { cls, kernel, .. } => {
758 write!(f, "<math{:?}>", cls)?;
759 kernel.display_fmt(indent + 2, f)?;
760 display_do_indent(indent, f)?;
761 write!(f, "</math{:?}>", cls)
762 }
763 MathNucleus::Inner(k) => {
764 write!(f, "<mathinner>")?;
765 k.display_fmt(indent + 2, f)?;
766 display_do_indent(indent, f)?;
767 f.write_str("</mathinner>")
768 }
769 MathNucleus::LeftRight {
770 left,
771 right,
772 children,
773 ..
774 } => {
775 write!(f, "<leftright>")?;
776 if let Some((l, _)) = left {
777 write!(f, "<left = {}/>", l)?;
778 }
779 for c in children.iter() {
780 c.display_fmt(indent + 2, f)?;
781 }
782 if let Some((r, _)) = right {
783 write!(f, "<right = {}/>", r)?;
784 }
785 display_do_indent(indent, f)?;
786 f.write_str("</leftright>")
787 }
788 MathNucleus::Middle(c, _) => {
789 write!(f, "<middle = {}/>", c)
790 }
791 MathNucleus::Overline(k) => {
792 write!(f, "<overline>")?;
793 k.display_fmt(indent + 2, f)?;
794 display_do_indent(indent, f)?;
795 f.write_str("</overline>")
796 }
797 MathNucleus::Underline(k) => {
798 write!(f, "<underline>")?;
799 k.display_fmt(indent + 2, f)?;
800 display_do_indent(indent, f)?;
801 f.write_str("</underline>")
802 }
803 MathNucleus::Accent { accent, inner } => {
804 write!(f, "<accent char=\"{}\">", accent.0)?;
805 for i in inner.iter() {
806 i.display_fmt(indent + 2, f)?;
807 }
808 display_do_indent(indent, f)?;
809 f.write_str("</accent>")
810 }
811 MathNucleus::Radical { rad, inner } => {
812 write!(f, "<radical char=\"{}\">", rad.0)?;
813 for i in inner.iter() {
814 i.display_fmt(indent + 2, f)?;
815 }
816 display_do_indent(indent, f)?;
817 f.write_str("</radical>")
818 }
819 MathNucleus::VCenter { children, .. } => {
820 write!(f, "<vcenter>")?;
821 for c in children.iter() {
822 c.display_fmt(indent + 2, f)?;
823 }
824 display_do_indent(indent, f)?;
825 f.write_str("</vcenter>")
826 }
827 }
828 }
829 fn height(&self) -> ET::Dim {
830 match self {
831 MathNucleus::Simple {
832 cls: MathClass::Op,
833 kernel,
834 ..
835 } => (kernel.height() + kernel.depth()).scale_float(0.5),
836 MathNucleus::Simple { kernel, .. } => kernel.height(),
837 MathNucleus::Inner(k) => k.height(),
838 MathNucleus::LeftRight { children, .. } => children
839 .iter()
840 .map(|c| c.height())
841 .max()
842 .unwrap_or_default(),
843 MathNucleus::Overline(k) => k.height(),
844 MathNucleus::Underline(k) => k.height(),
845 MathNucleus::Middle(c, s) => s.get_font().get_ht(*c),
846 MathNucleus::Accent {
847 inner,
848 accent: (c, f),
849 } => {
850 inner.iter().map(|c| c.height()).max().unwrap_or_default()
851 + f.get_font().get_ht(*c)
852 + f.get_font().get_dp(*c)
853 }
854 MathNucleus::Radical { inner, rad: (c, f) } => {
855 inner.iter().map(|c| c.height()).max().unwrap_or_default() + f.get_font().get_ht(*c)
856 } MathNucleus::VCenter { children, .. } => {
858 children
859 .iter()
860 .map(|c| c.height() + c.depth())
861 .sum::<ET::Dim>()
862 + -children
863 .iter()
864 .last()
865 .map(|c| c.depth())
866 .unwrap_or_default()
867 }
868 }
869 }
870 fn width(&self) -> ET::Dim {
871 match self {
872 MathNucleus::Simple { kernel, .. } => kernel.width() + ET::Dim::from_sp(65536 * 2), MathNucleus::Inner(k) => k.width(),
874 MathNucleus::LeftRight { children, .. } => {
875 children.iter().map(|c| c.width()).sum::<ET::Dim>() + ET::Dim::from_sp(65536 * 3)
876 } MathNucleus::Overline(k) => k.width(),
878 MathNucleus::Underline(k) => k.width(),
879 MathNucleus::Middle(c, s) => s.get_font().get_wd(*c),
880 MathNucleus::Accent { inner, .. } => inner.iter().map(|c| c.width()).sum(),
881 MathNucleus::Radical { inner, rad, .. } => {
882 inner.iter().map(|c| c.width()).sum::<ET::Dim>() + rad.1.get_font().get_wd(rad.0)
883 }
884 MathNucleus::VCenter { children, .. } => {
885 children.iter().map(|c| c.width()).max().unwrap_or_default()
886 }
887 }
888 }
889 fn depth(&self) -> ET::Dim {
890 match self {
891 MathNucleus::Simple {
892 cls: MathClass::Op,
893 kernel,
894 ..
895 } => (kernel.height() + kernel.depth()).scale_float(0.5),
896 MathNucleus::Simple { kernel, .. } => kernel.depth(),
897 MathNucleus::LeftRight { children, .. } => {
898 children.iter().map(|c| c.depth()).max().unwrap_or_default()
899 }
900 MathNucleus::Inner(k) => k.depth(),
901 MathNucleus::Overline(k) => k.depth(),
902 MathNucleus::Underline(k) => k.depth(),
903 MathNucleus::Middle(c, s) => s.get_font().get_dp(*c),
904 MathNucleus::Accent { inner, .. } => {
905 inner.iter().map(|c| c.depth()).max().unwrap_or_default()
906 }
907 MathNucleus::Radical { inner, .. } => {
908 inner.iter().map(|c| c.depth()).max().unwrap_or_default()
909 }
910 MathNucleus::VCenter { children, .. } => children
911 .iter()
912 .last()
913 .map(|c| c.depth())
914 .unwrap_or_default(),
915 }
916 }
917
918 fn nodetype(&self) -> NodeType {
919 NodeType::Math
920 }
921}
922
923#[derive(Clone, Debug, Default)]
925pub enum MathKernel<ET: EngineTypes, S: MathFontStyleT<ET>> {
926 #[default]
928 Empty,
929 Char { char: ET::Char, style: S },
931 Box(TeXBox<ET>),
933 List {
935 start: SourceRef<ET>,
936 children: Box<[MathNode<ET, S>]>,
937 end: SourceRef<ET>,
938 },
939}
940impl<ET: EngineTypes> NodeTrait<ET> for MathKernel<ET, MathFontStyle<ET>> {
941 fn display_fmt(&self, indent: usize, f: &mut Formatter<'_>) -> std::fmt::Result {
942 match self {
943 MathKernel::Empty => Ok(()),
944 MathKernel::Char { char, .. } => {
945 display_do_indent(indent, f)?;
946 write!(f, "<char:{}/>", char)
947 }
948 MathKernel::Box(b) => b.display_fmt(indent, f),
949 MathKernel::List { children, .. } => {
950 for c in children.iter() {
951 c.display_fmt(indent + 2, f)?;
952 }
953 Ok(())
954 }
955 }
956 }
957 fn height(&self) -> ET::Dim {
958 match self {
959 MathKernel::Empty => ET::Dim::default(),
960 MathKernel::Char { style, char } => style.get_font().get_ht(*char),
961 MathKernel::Box(b) => b.height(),
962 MathKernel::List { children, .. } => children
963 .iter()
964 .map(|c| c.height())
965 .max()
966 .unwrap_or_default(),
967 }
968 }
969 fn width(&self) -> ET::Dim {
970 match self {
971 MathKernel::Empty => ET::Dim::default(),
972 MathKernel::Char { style, char } => style.get_font().get_wd(*char),
973 MathKernel::Box(b) => b.width(),
974 MathKernel::List { children, .. } => children.iter().map(|c| c.width()).sum(),
975 }
976 }
977 fn depth(&self) -> ET::Dim {
978 match self {
979 MathKernel::Empty => ET::Dim::default(),
980 MathKernel::Char { style, char } => style.get_font().get_dp(*char),
981 MathKernel::Box(b) => b.depth(),
982 MathKernel::List { children, .. } => {
983 children.iter().map(|c| c.depth()).max().unwrap_or_default()
984 }
985 }
986 }
987 fn nodetype(&self) -> NodeType {
988 match self {
989 MathKernel::Empty => NodeType::Math,
990 MathKernel::Char { .. } => NodeType::MathChar,
991 MathKernel::Box(b) => b.nodetype(),
992 MathKernel::List { .. } => NodeType::Math,
993 }
994 }
995}
996
997#[derive(Debug, Clone)]
999pub struct MathGroup<ET: EngineTypes> {
1000 pub display: Option<(Skip<ET::Dim>, Skip<ET::Dim>)>,
1003 pub children: Box<[MathNode<ET, MathFontStyle<ET>>]>,
1005 pub start: SourceRef<ET>,
1007 pub end: SourceRef<ET>,
1009 pub eqno: Option<(EqNoPosition, Box<[MathNode<ET, MathFontStyle<ET>>]>)>,
1012 pub computed_width: OnceCell<ET::Dim>,
1014 pub computed_height: OnceCell<ET::Dim>,
1016 pub computed_depth: OnceCell<ET::Dim>,
1018}
1019impl<ET: EngineTypes> NodeTrait<ET> for MathGroup<ET> {
1020 fn display_fmt(&self, indent: usize, f: &mut Formatter<'_>) -> std::fmt::Result {
1021 display_do_indent(indent, f)?;
1022 write!(
1023 f,
1024 "<{}math>",
1025 if self.display.is_some() {
1026 "display"
1027 } else {
1028 ""
1029 }
1030 )?;
1031 for c in self.children.iter() {
1032 c.display_fmt(indent + 2, f)?;
1033 }
1034 display_do_indent(indent, f)?;
1035 write!(
1036 f,
1037 "</{}math>",
1038 if self.display.is_some() {
1039 "display"
1040 } else {
1041 ""
1042 }
1043 )
1044 }
1045 fn height(&self) -> ET::Dim {
1046 *self.computed_height.get_or_init(|| {
1047 self.children
1048 .iter()
1049 .map(|c| c.height())
1050 .max()
1051 .unwrap_or_default()
1052 })
1053 }
1054 fn width(&self) -> ET::Dim {
1055 *self
1056 .computed_width
1057 .get_or_init(|| self.children.iter().map(|c| c.width()).sum())
1058 }
1059 fn depth(&self) -> ET::Dim {
1060 *self.computed_depth.get_or_init(|| {
1061 self.children
1062 .iter()
1063 .map(|c| c.depth())
1064 .max()
1065 .unwrap_or_default()
1066 })
1067 }
1068 fn nodetype(&self) -> NodeType {
1069 NodeType::Math
1070 }
1071 fn sourceref(&self) -> Option<(&SourceRef<ET>, &SourceRef<ET>)> {
1072 Some((&self.start, &self.end))
1073 }
1074}
1075
1076impl<ET: EngineTypes> MathGroup<ET> {
1077 pub fn close(
1083 state: &ET::State,
1084 display: Option<(Skip<ET::Dim>, Skip<ET::Dim>)>,
1085 start: SourceRef<ET>,
1086 end: SourceRef<ET>,
1087 children: Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>>,
1088 eqno: Option<(EqNoPosition, Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>>)>,
1089 ) -> Self {
1090 let style = if display.is_some() {
1091 MathStyle {
1092 style: MathStyleType::Display,
1093 cramped: false,
1094 }
1095 } else {
1096 MathStyle {
1097 style: MathStyleType::Text,
1098 cramped: false,
1099 }
1100 };
1101 let nch = Self::close_i(state, children, style);
1102 MathGroup {
1103 display,
1104 children: nch.into(),
1105 start,
1106 end,
1107 computed_width: OnceCell::new(),
1108 computed_height: OnceCell::new(),
1109 computed_depth: OnceCell::new(),
1110 eqno: eqno.map(|(pos, ch)| {
1111 (
1112 pos,
1113 Self::close_i(
1114 state,
1115 ch,
1116 MathStyle {
1117 style: MathStyleType::Text,
1118 cramped: false,
1119 },
1120 )
1121 .into(),
1122 )
1123 }),
1124 }
1125 }
1126 fn close_i(
1127 state: &ET::State,
1128 ls: Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>>,
1129 mut style: MathStyle,
1130 ) -> Vec<MathNode<ET, MathFontStyle<ET>>> {
1131 ls.into_iter()
1132 .flat_map(|n| match n {
1133 MathNode::HSkip(s) => Some(MathNode::HSkip(s)),
1134 MathNode::HFil => Some(MathNode::HFil),
1135 MathNode::HFill => Some(MathNode::HFill),
1136 MathNode::HFilneg => Some(MathNode::HFilneg),
1137 MathNode::Hss => Some(MathNode::Hss),
1138 MathNode::Marker(UnresolvedMarkers::Display) => {
1139 style.style = MathStyleType::Display;
1140 None
1141 }
1142 MathNode::Marker(UnresolvedMarkers::Text) => {
1143 style.style = MathStyleType::Text;
1144 None
1145 }
1146 MathNode::Marker(UnresolvedMarkers::Script) => {
1147 style.style = MathStyleType::Script;
1148 None
1149 }
1150 MathNode::Marker(UnresolvedMarkers::ScriptScript) => {
1151 style.style = MathStyleType::ScriptScript;
1152 None
1153 }
1154 MathNode::Over {
1155 start,
1156 end,
1157 top,
1158 sep,
1159 bottom,
1160 left,
1161 right,
1162 } => Some(MathNode::Over {
1163 start,
1164 end,
1165 top: Self::close_i(state, top.into_vec(), style.numerator()).into(),
1166 sep,
1167 bottom: Self::close_i(state, bottom.into_vec(), style.denominator()).into(),
1168 left: left.map(|(c, s)| (c, Self::resolve_style(state, style, s))),
1169 right: right.map(|(c, s)| (c, Self::resolve_style(state, style, s))),
1170 }),
1171 MathNode::Choice(c) => Some(match style {
1172 MathStyle {
1173 style: MathStyleType::Display,
1174 ..
1175 } => MathNode::Choice(ResolvedChoice(
1176 Self::close_i(state, c.display.into_vec(), style).into(),
1177 )),
1178 MathStyle {
1179 style: MathStyleType::Text,
1180 ..
1181 } => MathNode::Choice(ResolvedChoice(
1182 Self::close_i(state, c.text.into_vec(), style).into(),
1183 )),
1184 MathStyle {
1185 style: MathStyleType::Script,
1186 ..
1187 } => MathNode::Choice(ResolvedChoice(
1188 Self::close_i(state, c.script.into_vec(), style).into(),
1189 )),
1190 MathStyle {
1191 style: MathStyleType::ScriptScript,
1192 ..
1193 } => MathNode::Choice(ResolvedChoice(
1194 Self::close_i(state, c.scriptscript.into_vec(), style).into(),
1195 )),
1196 }),
1197 MathNode::Space => Some(MathNode::Space),
1198 MathNode::Leaders(l) => Some(MathNode::Leaders(l)),
1199 MathNode::HKern(d) => Some(MathNode::HKern(d)),
1200 MathNode::Penalty(p) => Some(MathNode::Penalty(p)),
1201 MathNode::Mark(i, tl) => Some(MathNode::Mark(i, tl)),
1202 MathNode::VRule {
1203 width,
1204 height,
1205 depth,
1206 start,
1207 end,
1208 } => Some(MathNode::VRule {
1209 width,
1210 height,
1211 depth,
1212 start,
1213 end,
1214 }),
1215 MathNode::Whatsit(w) => Some(MathNode::Whatsit(w)),
1216 MathNode::Custom(n) => Some(MathNode::Custom(n)),
1217 MathNode::MSkip {
1218 skip,
1219 style: unresolved,
1220 } => Some(MathNode::MSkip {
1221 skip,
1222 style: Self::resolve_style(state, style, unresolved),
1223 }),
1224 MathNode::MKern {
1225 kern,
1226 style: unresolved,
1227 } => Some(MathNode::MKern {
1228 kern,
1229 style: Self::resolve_style(state, style, unresolved),
1230 }),
1231 MathNode::Atom(a) => Some(MathNode::Atom(MathAtom {
1232 nucleus: Self::resolve_nucleus(state, a.nucleus, style),
1233 sup: a
1234 .sup
1235 .map(|l| Self::close_i(state, l.into_vec(), style.sup()).into()),
1236 sub: a
1237 .sub
1238 .map(|l| Self::close_i(state, l.into_vec(), style.sub()).into()),
1239 })),
1240 })
1241 .collect()
1242 }
1243 fn resolve_nucleus(
1244 state: &ET::State,
1245 n: MathNucleus<ET, UnresolvedMathFontStyle<ET>>,
1246 style: MathStyle,
1247 ) -> MathNucleus<ET, MathFontStyle<ET>> {
1248 match n {
1249 MathNucleus::Simple {
1250 cls: MathClass::Op,
1251 kernel,
1252 limits,
1253 } => MathNucleus::Simple {
1254 cls: MathClass::Op,
1255 kernel: Self::resolve_kernel(state, kernel, style),
1256 limits: match limits {
1257 Some(l) => Some(l),
1258 None => {
1259 if style.style == MathStyleType::Display {
1260 Some(true)
1261 } else {
1262 Some(false)
1263 }
1264 }
1265 },
1266 },
1267 MathNucleus::LeftRight {
1268 start,
1269 left,
1270 children,
1271 right,
1272 end,
1273 } => MathNucleus::LeftRight {
1274 start,
1275 left: left.map(|(c, s)| (c, Self::resolve_style(state, style, s))),
1276 children: Self::close_i(state, children.into_vec(), style).into(),
1277 right: right.map(|(c, s)| (c, Self::resolve_style(state, style, s))),
1278 end,
1279 },
1280 MathNucleus::Middle(c, f) => {
1281 MathNucleus::Middle(c, Self::resolve_style(state, style, f))
1282 }
1283 MathNucleus::Simple {
1284 cls,
1285 kernel,
1286 limits,
1287 } => MathNucleus::Simple {
1288 cls,
1289 kernel: Self::resolve_kernel(state, kernel, style),
1290 limits,
1291 },
1292 MathNucleus::Inner(k) => MathNucleus::Inner(Self::resolve_kernel(state, k, style)),
1293 MathNucleus::Overline(k) => {
1294 MathNucleus::Overline(Self::resolve_kernel(state, k, style))
1295 }
1296 MathNucleus::Underline(k) => {
1297 MathNucleus::Underline(Self::resolve_kernel(state, k, style))
1298 }
1299 MathNucleus::Accent {
1300 accent: (c, f),
1301 inner,
1302 } => MathNucleus::Accent {
1303 accent: (c, Self::resolve_style(state, style, f)),
1304 inner: Self::close_i(state, inner.into_vec(), style).into(),
1305 },
1306 MathNucleus::Radical { rad: (c, f), inner } => MathNucleus::Radical {
1307 rad: (c, Self::resolve_style(state, style, f)),
1308 inner: Self::close_i(state, inner.into_vec(), style).into(),
1309 },
1310 MathNucleus::VCenter {
1311 start,
1312 end,
1313 children,
1314 scaled,
1315 } => MathNucleus::VCenter {
1316 start,
1317 end,
1318 children,
1319 scaled,
1320 },
1321 }
1322 }
1323 fn resolve_kernel(
1324 state: &ET::State,
1325 n: MathKernel<ET, UnresolvedMathFontStyle<ET>>,
1326 style: MathStyle,
1327 ) -> MathKernel<ET, MathFontStyle<ET>> {
1328 match n {
1329 MathKernel::Empty => MathKernel::Empty,
1330 MathKernel::Char {
1331 char,
1332 style: unresolved,
1333 } => MathKernel::Char {
1334 char,
1335 style: Self::resolve_style(state, style, unresolved),
1336 },
1337 MathKernel::Box(b) => MathKernel::Box(b),
1338 MathKernel::List {
1339 start,
1340 children,
1341 end,
1342 } => MathKernel::List {
1343 start,
1344 children: Self::close_i(state, children.into_vec(), style).into(),
1345 end,
1346 },
1347 }
1348 }
1349 fn resolve_style(
1350 state: &ET::State,
1351 style: MathStyle,
1352 unresolved: UnresolvedMathFontStyle<ET>,
1353 ) -> MathFontStyle<ET> {
1354 match style.style {
1355 MathStyleType::Script => MathFontStyle {
1356 style: style.style,
1357 cramped: style.cramped,
1358 font: state.get_scriptfont(unresolved.fam()).clone(),
1359 },
1360 MathStyleType::ScriptScript => MathFontStyle {
1361 style: style.style,
1362 cramped: style.cramped,
1363 font: state.get_scriptscriptfont(unresolved.fam()).clone(),
1364 },
1365 _ => MathFontStyle {
1366 style: style.style,
1367 cramped: style.cramped,
1368 font: state.get_textfont(unresolved.fam()).clone(),
1369 },
1370 }
1371 }
1372}
1373
1374#[derive(Debug, Copy, Clone)]
1376pub enum EqNoPosition {
1377 Left,
1378 Right,
1379}
1380
1381#[derive(Debug, Clone)]
1383pub struct MathChar<ET: EngineTypes> {
1384 pub char: ET::Char,
1386 pub cls: MathClass,
1388 pub style: UnresolvedMathFontStyle<ET>,
1390}
1391impl<ET: EngineTypes> MathChar<ET> {
1392 pub fn to_atom(self) -> MathAtom<ET, UnresolvedMathFontStyle<ET>> {
1394 MathAtom {
1395 nucleus: self.to_nucleus(),
1396 sup: None,
1397 sub: None,
1398 }
1399 }
1400 pub fn to_nucleus(self) -> MathNucleus<ET, UnresolvedMathFontStyle<ET>> {
1401 MathNucleus::Simple {
1402 cls: self.cls,
1403 kernel: MathKernel::Char {
1404 char: self.char,
1405 style: self.style,
1406 },
1407 limits: None,
1408 }
1409 }
1410 pub fn from_u32(mathcode: u32, state: &ET::State, source: Option<ET::Char>) -> Self {
1414 let (mut cls, mut fam, pos) = {
1415 if mathcode == 0 {
1416 (
1417 0,
1418 0,
1419 match source {
1420 Some(c) => c.try_into().ok().unwrap(),
1421 _ => 0,
1422 },
1423 )
1424 } else {
1425 let char = (mathcode & 0xFF) as u8; let fam = ((mathcode >> 8) & 0xF) as u8; let rest_fam_shifted = (mathcode >> 12) & 0xF; (rest_fam_shifted as u8, fam, char)
1429 }
1430 };
1431 if cls == 7 {
1432 let i = state.get_primitive_int(PRIMITIVES.fam).into();
1433 match i {
1434 i if !(0..=15).contains(&i) => {
1435 cls = 0;
1436 }
1437 i => {
1438 cls = 0;
1439 fam = i as u8;
1440 }
1441 }
1442 }
1443 if cls > 7 {
1444 panic!("Invalid math class: {mathcode}({source:?}): {cls} {pos} {fam}");
1445 }
1446 let cls = MathClass::from(cls);
1447 let char = ET::Char::from(pos);
1448 MathChar {
1449 char,
1450 cls,
1451 style: UnresolvedMathFontStyle::of_fam(fam),
1452 }
1453 }
1454}
1455
1456#[derive(Clone, Debug)]
1458pub struct Delimiter<ET: EngineTypes> {
1459 pub small: MathChar<ET>,
1461 pub large: MathChar<ET>,
1463}
1464impl<ET: EngineTypes> Delimiter<ET> {
1465 fn default() -> Self {
1466 Delimiter {
1467 small: MathChar {
1468 char: ET::Char::from(0),
1469 cls: MathClass::Ord,
1470 style: UnresolvedMathFontStyle::of_fam(0),
1471 },
1472 large: MathChar {
1473 char: ET::Char::from(0),
1474 cls: MathClass::Ord,
1475 style: UnresolvedMathFontStyle::of_fam(0),
1476 },
1477 }
1478 }
1479 pub fn from_int(num: ET::Int, state: &ET::State) -> Either<Self, (Self, i64)> {
1481 let num = num.into();
1482 if num < 0 || num > u32::MAX.into() {
1483 return either::Right((Self::default(), num));
1484 }
1485 let num = num as u32;
1486 let large = num & 0xFFF;
1487 let small = num >> 12;
1488 either::Left(Delimiter {
1489 small: MathChar::from_u32(small, state, None),
1490 large: MathChar::from_u32(large, state, None),
1491 })
1492 }
1493}
1494
1495#[derive(Clone, Debug)]
1498pub enum MathNodeList<ET: EngineTypes> {
1499 Simple(Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>>),
1501 Over {
1505 top: Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>>,
1506 sep: Option<ET::Dim>,
1507 bottom: Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>>,
1508 left: Option<(ET::Char, UnresolvedMathFontStyle<ET>)>,
1509 right: Option<(ET::Char, UnresolvedMathFontStyle<ET>)>,
1510 },
1511 EqNo {
1517 pos: EqNoPosition,
1518 main: Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>>,
1519 eqno: Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>>,
1520 },
1521}
1522impl<ET: EngineTypes> Default for MathNodeList<ET> {
1523 fn default() -> Self {
1524 MathNodeList::Simple(Vec::new())
1525 }
1526}
1527impl<ET: EngineTypes> MathNodeList<ET> {
1528 pub fn push(&mut self, n: MathNode<ET, UnresolvedMathFontStyle<ET>>) {
1530 match self {
1531 MathNodeList::Simple(v) => v.push(n),
1532 MathNodeList::Over { bottom, .. } => bottom.push(n),
1533 MathNodeList::EqNo { eqno, .. } => eqno.push(n),
1534 }
1535 }
1536 pub fn close(
1538 self,
1539 start: SourceRef<ET>,
1540 end: SourceRef<ET>,
1541 ) -> (
1542 Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>>,
1543 Option<(EqNoPosition, Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>>)>,
1544 ) {
1545 match self {
1546 MathNodeList::Simple(v) => (v, None),
1547 MathNodeList::Over {
1548 top,
1549 sep,
1550 bottom,
1551 left,
1552 right,
1553 } => (
1554 vec![MathNode::Over {
1555 start,
1556 end,
1557 top: top.into(),
1558 bottom: bottom.into(),
1559 sep,
1560 left,
1561 right,
1562 }],
1563 None,
1564 ),
1565 MathNodeList::EqNo { main, eqno, pos } => (main, Some((pos, eqno))),
1566 }
1567 }
1568 pub fn list_mut(&mut self) -> &mut Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>> {
1570 match self {
1571 MathNodeList::Simple(v) => v,
1572 MathNodeList::Over { bottom, .. } => bottom,
1573 MathNodeList::EqNo { eqno, .. } => eqno,
1574 }
1575 }
1576 pub fn list(&self) -> &Vec<MathNode<ET, UnresolvedMathFontStyle<ET>>> {
1578 match self {
1579 MathNodeList::Simple(v) => v,
1580 MathNodeList::Over { bottom, .. } => bottom,
1581 MathNodeList::EqNo { eqno, .. } => eqno,
1582 }
1583 }
1584}
1585
1586#[derive(Clone, Debug)]
1588pub enum MathNodeListType<ET: EngineTypes> {
1589 Top {
1591 display: bool,
1593 },
1594 Target(ListTarget<ET, MathNode<ET, UnresolvedMathFontStyle<ET>>>),
1596 LeftRight(Option<Delimiter<ET>>),
1598}