1pub mod boxes;
7pub mod horizontal;
8pub mod math;
9pub mod vertical;
10
11use crate::commands::primitives::PrimitiveIdentifier;
12use crate::engine::filesystem::SourceRef;
13use crate::engine::{EngineReferences, EngineTypes};
14use crate::tex::nodes::boxes::TeXBox;
15use crate::tex::nodes::horizontal::{HNode, HorizontalNodeListType};
16use crate::tex::nodes::math::{MathNode, MathNodeList, MathNodeListType, UnresolvedMathFontStyle};
17use crate::tex::nodes::vertical::{VNode, VerticalNodeListType};
18use crate::tex::numerics::Skip;
19use crate::utils::errors::TeXResult;
20use crate::utils::Ptr;
21use std::convert::Infallible;
22use std::fmt::{Debug, Display, Formatter, Write};
23use std::marker::PhantomData;
24
25pub trait NodeTrait<ET: EngineTypes>: Debug + Clone {
27 fn height(&self) -> ET::Dim;
29 fn depth(&self) -> ET::Dim;
31 fn width(&self) -> ET::Dim;
33 fn nodetype(&self) -> NodeType;
35 fn display_fmt(&self, indent: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
38
39 fn display(&self) -> DisplayNode<ET, Self> {
42 DisplayNode(self, PhantomData)
43 }
44 fn opaque(&self) -> bool {
49 false
50 }
51 fn sourceref(&self) -> Option<(&SourceRef<ET>, &SourceRef<ET>)> {
52 None
53 }
54}
55
56pub fn display_do_indent(indent: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 f.write_char('\n')?;
60 for _ in 0..indent {
61 f.write_char(' ')?;
62 }
63 Ok(())
64}
65
66pub struct DisplayNode<'a, ET: EngineTypes, N: NodeTrait<ET>>(&'a N, PhantomData<ET>);
69impl<'a, ET: EngineTypes, N: NodeTrait<ET>> Display for DisplayNode<'a, ET, N> {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 self.0.display_fmt(0, f)
72 }
73}
74
75pub trait CustomNodeTrait<ET: EngineTypes>: NodeTrait<ET>
79where
80 Self: Into<ET::CustomNode>,
81{
82 fn into_v(self) -> VNode<ET> {
84 VNode::Custom(self.into())
85 }
86 fn into_h(self) -> HNode<ET> {
88 HNode::Custom(self.into())
89 }
90 fn into_math(self) -> MathNode<ET, UnresolvedMathFontStyle<ET>> {
92 MathNode::Custom(self.into())
93 }
94}
95
96impl<ET: EngineTypes<CustomNode = Infallible>> NodeTrait<ET> for Infallible {
97 fn height(&self) -> ET::Dim {
98 ET::Dim::default()
99 }
100 fn depth(&self) -> ET::Dim {
101 ET::Dim::default()
102 }
103 fn width(&self) -> ET::Dim {
104 ET::Dim::default()
105 }
106 fn nodetype(&self) -> NodeType {
107 NodeType::WhatsIt
108 }
109 fn display_fmt(&self, _indent: usize, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 Ok(())
111 }
112 fn opaque(&self) -> bool {
113 true
114 }
115}
116impl<ET: EngineTypes<CustomNode = Infallible>> CustomNodeTrait<ET> for Infallible {}
117
118#[cfg(feature = "multithreaded")]
119pub type WhatsitFunction<ET> =
120 dyn FnOnce(&mut EngineReferences<ET>) -> TeXResult<(), ET> + Send + Sync;
121#[cfg(not(feature = "multithreaded"))]
122pub type WhatsitFunction<ET> = dyn FnOnce(&mut EngineReferences<ET>) -> TeXResult<(), ET>;
123
124#[cfg(feature = "multithreaded")]
125type WhatsitF<ET> = Ptr<std::sync::RwLock<Option<Box<WhatsitFunction<ET>>>>>;
126#[cfg(not(feature = "multithreaded"))]
127type WhatsitF<ET> = Ptr<std::cell::RefCell<Option<Box<WhatsitFunction<ET>>>>>;
128#[derive(Clone)]
131pub struct WhatsitNode<ET: EngineTypes>(String, WhatsitF<ET>);
132impl<ET: EngineTypes> std::fmt::Debug for WhatsitNode<ET> {
133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134 write!(f, "<whatsit {}>", self.0)
135 }
136}
137impl<ET: EngineTypes> WhatsitNode<ET> {
138 pub fn new(f: Box<WhatsitFunction<ET>>, name: PrimitiveIdentifier) -> Self {
142 #[cfg(feature = "multithreaded")]
143 let i = std::sync::RwLock::new(Some(f));
144 #[cfg(not(feature = "multithreaded"))]
145 let i = std::cell::RefCell::new(Some(f));
146 WhatsitNode(name.display::<ET::Char>(None).to_string(), Ptr::new(i))
147 }
148 #[cfg(feature = "multithreaded")]
152 pub fn call(self, engine: &mut EngineReferences<ET>) -> TeXResult<(), ET> {
153 let mut lock = self.1.write().unwrap();
154 if let Some(f) = std::mem::take(&mut *lock) {
155 f(engine)
156 } else {
157 Ok(())
158 }
159 }
160 #[cfg(not(feature = "multithreaded"))]
161 pub fn call(self, engine: &mut EngineReferences<ET>) -> TeXResult<(), ET> {
162 if let Some(f) = self.1.replace(None) {
163 f(engine)
164 } else {
165 Ok(())
166 }
167 }
168}
169
170#[derive(Clone, Debug)]
172pub struct Leaders<ET: EngineTypes> {
173 pub tp: LeaderType,
175 pub body: LeaderBody<ET>,
177 pub skip: LeaderSkip<ET>,
179}
180impl<ET: EngineTypes> NodeTrait<ET> for Leaders<ET> {
181 fn display_fmt(&self, indent: usize, f: &mut Formatter<'_>) -> std::fmt::Result {
182 display_do_indent(indent, f)?;
183 write!(f, "<leaders")?;
184 match self.tp {
185 LeaderType::Normal => {}
186 LeaderType::C => write!(f, " type=c")?,
187 LeaderType::X => write!(f, " type=x")?,
188 }
189 match self.skip {
190 LeaderSkip::HSkip(s) => write!(f, " hskip={}", s)?,
191 LeaderSkip::HFil => write!(f, " hfil")?,
192 LeaderSkip::HFill => write!(f, " hfill")?,
193 LeaderSkip::VSkip(s) => write!(f, " vskip={}", s)?,
194 LeaderSkip::VFil => write!(f, " vfil")?,
195 LeaderSkip::VFill => write!(f, " vfill")?,
196 }
197 write!(f, ">")?;
198 display_do_indent(indent, f)?;
200 write!(f, "</leaders>")
201 }
202 fn height(&self) -> ET::Dim {
203 if self.skip.is_h() {
204 ET::Dim::default() } else {
206 match self.skip {
207 LeaderSkip::VSkip(s) => s.base,
208 _ => ET::Dim::default(),
209 }
210 }
211 }
212 fn width(&self) -> ET::Dim {
213 if self.skip.is_h() {
214 match self.skip {
215 LeaderSkip::HSkip(s) => s.base,
216 _ => ET::Dim::default(),
217 }
218 } else {
219 ET::Dim::default() }
221 }
222 fn depth(&self) -> ET::Dim {
223 ET::Dim::default()
224 }
226 fn nodetype(&self) -> NodeType {
227 NodeType::Glue
228 }
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq)]
234pub enum LeaderType {
235 Normal,
236 C,
237 X,
238}
239
240#[derive(Clone, Debug)]
243pub enum LeaderBody<ET: EngineTypes> {
244 Box(TeXBox<ET>),
245 Rule {
246 width: Option<ET::Dim>,
247 height: Option<ET::Dim>,
248 depth: Option<ET::Dim>,
249 },
250}
251
252#[derive(Clone, Debug)]
255pub enum LeaderSkip<ET: EngineTypes> {
256 HSkip(Skip<ET::Dim>),
257 HFil,
258 HFill,
259 VSkip(Skip<ET::Dim>),
260 VFil,
261 VFill,
262}
263impl<ET: EngineTypes> LeaderSkip<ET> {
264 pub fn is_h(&self) -> bool {
266 use LeaderSkip::*;
267 matches!(self, HSkip(_) | HFil | HFill)
268 }
269}
270
271#[derive(Clone, Copy, Eq, PartialEq, Debug)]
274pub enum NodeType {
275 Char = 0,
277 HList = 1,
279 VList = 2,
281 Rule = 3,
283 Insertion = 4,
285 Mark = 5,
287 Adjust = 6,
289 Ligature = 7,
291 Discretionary = 8,
293 WhatsIt = 9,
295 Math = 10,
297 Glue = 11,
299 Kern = 12,
301 Penalty = 13,
303 Unset = 14,
305 MathChar = 15,
307}
308impl NodeType {
309 pub fn to_u8(&self) -> u8 {
311 *self as u8
312 }
313}
314
315#[derive(Clone, Debug)]
318pub enum NodeList<ET: EngineTypes> {
319 Vertical {
321 tp: VerticalNodeListType<ET>,
322 children: Vec<VNode<ET>>,
323 },
324 Horizontal {
326 tp: HorizontalNodeListType<ET>,
327 children: Vec<HNode<ET>>,
328 },
329 Math {
331 children: MathNodeList<ET>,
332 start: SourceRef<ET>,
333 tp: MathNodeListType<ET>,
334 },
335}
336impl<ET: EngineTypes> NodeList<ET> {
337 pub fn new_math(start: SourceRef<ET>) -> Self {
339 NodeList::Math {
340 children: MathNodeList::default(),
341 start,
342 tp: MathNodeListType::Target(ListTarget::none()),
343 }
344 }
345}
346
347pub struct BoxTarget<ET: EngineTypes>(
354 Option<Box<dyn FnOnce(&mut EngineReferences<ET>, TeXBox<ET>) -> TeXResult<(), ET>>>,
355);
356impl<ET: EngineTypes> crate::tex::nodes::BoxTarget<ET> {
357 pub fn new<F: FnOnce(&mut EngineReferences<ET>, TeXBox<ET>) -> TeXResult<(), ET> + 'static>(
359 f: F,
360 ) -> Self {
361 crate::tex::nodes::BoxTarget(Some(Box::new(f)))
362 }
363 pub fn call(self, engine: &mut EngineReferences<ET>, bx: TeXBox<ET>) -> TeXResult<(), ET> {
365 match self.0 {
366 Some(f) => f(engine, bx),
367 None => unreachable!(),
368 }
369 }
370 pub fn none() -> Self {
372 crate::tex::nodes::BoxTarget(None)
373 }
374 pub fn is_some(&self) -> bool {
376 self.0.is_some()
377 }
378}
379impl<ET: EngineTypes> Debug for crate::tex::nodes::BoxTarget<ET> {
380 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
381 match self.0 {
382 None => f.write_str("BoxTarget(None)"),
383 Some(_) => f.write_str("BoxTarget(Some(_))"),
384 }
385 }
386}
387impl<ET: EngineTypes> Clone for crate::tex::nodes::BoxTarget<ET> {
388 fn clone(&self) -> Self {
389 crate::tex::nodes::BoxTarget(None)
390 }
391}
392
393pub struct ListTarget<ET: EngineTypes, N>(
400 Option<Box<dyn FnOnce(&mut EngineReferences<ET>, Vec<N>, SourceRef<ET>) -> TeXResult<(), ET>>>,
401);
402impl<ET: EngineTypes, N> ListTarget<ET, N> {
403 pub fn new<
405 F: FnOnce(&mut EngineReferences<ET>, Vec<N>, SourceRef<ET>) -> TeXResult<(), ET> + 'static,
406 >(
407 f: F,
408 ) -> Self {
409 ListTarget(Some(Box::new(f)))
410 }
411 pub fn call(
413 self,
414 engine: &mut EngineReferences<ET>,
415 v: Vec<N>,
416 start: SourceRef<ET>,
417 ) -> TeXResult<(), ET> {
418 match self.0 {
419 Some(f) => f(engine, v, start),
420 None => unreachable!(),
421 }
422 }
423 pub fn none() -> Self {
425 ListTarget(None)
426 }
427 pub fn is_some(&self) -> bool {
429 self.0.is_some()
430 }
431}
432impl<ET: EngineTypes, N> Debug for ListTarget<ET, N> {
433 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
434 match self.0 {
435 None => f.write_str("ListTarget(None)"),
436 Some(_) => f.write_str("ListTarget(Some(_))"),
437 }
438 }
439}
440impl<ET: EngineTypes, N> Clone for ListTarget<ET, N> {
441 fn clone(&self) -> Self {
442 ListTarget(None)
443 }
444}