pub mod boxes;
pub mod horizontal;
pub mod math;
pub mod vertical;
use crate::commands::primitives::PrimitiveIdentifier;
use crate::engine::filesystem::SourceRef;
use crate::engine::{EngineReferences, EngineTypes};
use crate::tex::nodes::boxes::TeXBox;
use crate::tex::nodes::horizontal::{HNode, HorizontalNodeListType};
use crate::tex::nodes::math::{MathNode, MathNodeList, MathNodeListType, UnresolvedMathFontStyle};
use crate::tex::nodes::vertical::{VNode, VerticalNodeListType};
use crate::tex::numerics::Skip;
use crate::utils::errors::TeXResult;
use crate::utils::Ptr;
use std::convert::Infallible;
use std::fmt::{Debug, Display, Formatter, Write};
use std::marker::PhantomData;
pub trait NodeTrait<ET: EngineTypes>: Debug + Clone {
fn height(&self) -> ET::Dim;
fn depth(&self) -> ET::Dim;
fn width(&self) -> ET::Dim;
fn nodetype(&self) -> NodeType;
fn display_fmt(&self, indent: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
fn display(&self) -> DisplayNode<ET, Self> {
DisplayNode(self, PhantomData)
}
fn opaque(&self) -> bool {
false
}
fn sourceref(&self) -> Option<(&SourceRef<ET>, &SourceRef<ET>)> {
None
}
}
pub fn display_do_indent(indent: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_char('\n')?;
for _ in 0..indent {
f.write_char(' ')?;
}
Ok(())
}
pub struct DisplayNode<'a, ET: EngineTypes, N: NodeTrait<ET>>(&'a N, PhantomData<ET>);
impl<'a, ET: EngineTypes, N: NodeTrait<ET>> Display for DisplayNode<'a, ET, N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.display_fmt(0, f)
}
}
pub trait CustomNodeTrait<ET: EngineTypes>: NodeTrait<ET>
where
Self: Into<ET::CustomNode>,
{
fn into_v(self) -> VNode<ET> {
VNode::Custom(self.into())
}
fn into_h(self) -> HNode<ET> {
HNode::Custom(self.into())
}
fn into_math(self) -> MathNode<ET, UnresolvedMathFontStyle<ET>> {
MathNode::Custom(self.into())
}
}
impl<ET: EngineTypes<CustomNode = Infallible>> NodeTrait<ET> for Infallible {
fn height(&self) -> ET::Dim {
ET::Dim::default()
}
fn depth(&self) -> ET::Dim {
ET::Dim::default()
}
fn width(&self) -> ET::Dim {
ET::Dim::default()
}
fn nodetype(&self) -> NodeType {
NodeType::WhatsIt
}
fn display_fmt(&self, _indent: usize, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Ok(())
}
fn opaque(&self) -> bool {
true
}
}
impl<ET: EngineTypes<CustomNode = Infallible>> CustomNodeTrait<ET> for Infallible {}
#[cfg(feature = "multithreaded")]
pub type WhatsitFunction<ET> =
dyn FnOnce(&mut EngineReferences<ET>) -> TeXResult<(), ET> + Send + Sync;
#[cfg(not(feature = "multithreaded"))]
pub type WhatsitFunction<ET> = dyn FnOnce(&mut EngineReferences<ET>) -> TeXResult<(), ET>;
#[cfg(feature = "multithreaded")]
type WhatsitF<ET> = Ptr<std::sync::RwLock<Option<Box<WhatsitFunction<ET>>>>>;
#[cfg(not(feature = "multithreaded"))]
type WhatsitF<ET> = Ptr<std::cell::RefCell<Option<Box<WhatsitFunction<ET>>>>>;
#[derive(Clone)]
pub struct WhatsitNode<ET: EngineTypes>(String, WhatsitF<ET>);
impl<ET: EngineTypes> std::fmt::Debug for WhatsitNode<ET> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<whatsit {}>", self.0)
}
}
impl<ET: EngineTypes> WhatsitNode<ET> {
pub fn new(f: Box<WhatsitFunction<ET>>, name: PrimitiveIdentifier) -> Self {
#[cfg(feature = "multithreaded")]
let i = std::sync::RwLock::new(Some(f));
#[cfg(not(feature = "multithreaded"))]
let i = std::cell::RefCell::new(Some(f));
WhatsitNode(name.display::<ET::Char>(None).to_string(), Ptr::new(i))
}
#[cfg(feature = "multithreaded")]
pub fn call(self, engine: &mut EngineReferences<ET>) -> TeXResult<(), ET> {
let mut lock = self.1.write().unwrap();
if let Some(f) = std::mem::take(&mut *lock) {
f(engine)
} else {
Ok(())
}
}
#[cfg(not(feature = "multithreaded"))]
pub fn call(self, engine: &mut EngineReferences<ET>) -> TeXResult<(), ET> {
if let Some(f) = self.1.replace(None) {
f(engine)
} else {
Ok(())
}
}
}
#[derive(Clone, Debug)]
pub struct Leaders<ET: EngineTypes> {
pub tp: LeaderType,
pub body: LeaderBody<ET>,
pub skip: LeaderSkip<ET>,
}
impl<ET: EngineTypes> NodeTrait<ET> for Leaders<ET> {
fn display_fmt(&self, indent: usize, f: &mut Formatter<'_>) -> std::fmt::Result {
display_do_indent(indent, f)?;
write!(f, "<leaders")?;
match self.tp {
LeaderType::Normal => {}
LeaderType::C => write!(f, " type=c")?,
LeaderType::X => write!(f, " type=x")?,
}
match self.skip {
LeaderSkip::HSkip(s) => write!(f, " hskip={}", s)?,
LeaderSkip::HFil => write!(f, " hfil")?,
LeaderSkip::HFill => write!(f, " hfill")?,
LeaderSkip::VSkip(s) => write!(f, " vskip={}", s)?,
LeaderSkip::VFil => write!(f, " vfil")?,
LeaderSkip::VFill => write!(f, " vfill")?,
}
write!(f, ">")?;
display_do_indent(indent, f)?;
write!(f, "</leaders>")
}
fn height(&self) -> ET::Dim {
if self.skip.is_h() {
ET::Dim::default() } else {
match self.skip {
LeaderSkip::VSkip(s) => s.base,
_ => ET::Dim::default(),
}
}
}
fn width(&self) -> ET::Dim {
if self.skip.is_h() {
match self.skip {
LeaderSkip::HSkip(s) => s.base,
_ => ET::Dim::default(),
}
} else {
ET::Dim::default() }
}
fn depth(&self) -> ET::Dim {
ET::Dim::default()
}
fn nodetype(&self) -> NodeType {
NodeType::Glue
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LeaderType {
Normal,
C,
X,
}
#[derive(Clone, Debug)]
pub enum LeaderBody<ET: EngineTypes> {
Box(TeXBox<ET>),
Rule {
width: Option<ET::Dim>,
height: Option<ET::Dim>,
depth: Option<ET::Dim>,
},
}
#[derive(Clone, Debug)]
pub enum LeaderSkip<ET: EngineTypes> {
HSkip(Skip<ET::Dim>),
HFil,
HFill,
VSkip(Skip<ET::Dim>),
VFil,
VFill,
}
impl<ET: EngineTypes> LeaderSkip<ET> {
pub fn is_h(&self) -> bool {
use LeaderSkip::*;
matches!(self, HSkip(_) | HFil | HFill)
}
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum NodeType {
Char = 0,
HList = 1,
VList = 2,
Rule = 3,
Insertion = 4,
Mark = 5,
Adjust = 6,
Ligature = 7,
Discretionary = 8,
WhatsIt = 9,
Math = 10,
Glue = 11,
Kern = 12,
Penalty = 13,
Unset = 14,
MathChar = 15,
}
impl NodeType {
pub fn to_u8(&self) -> u8 {
*self as u8
}
}
#[derive(Clone, Debug)]
pub enum NodeList<ET: EngineTypes> {
Vertical {
tp: VerticalNodeListType<ET>,
children: Vec<VNode<ET>>,
},
Horizontal {
tp: HorizontalNodeListType<ET>,
children: Vec<HNode<ET>>,
},
Math {
children: MathNodeList<ET>,
start: SourceRef<ET>,
tp: MathNodeListType<ET>,
},
}
impl<ET: EngineTypes> NodeList<ET> {
pub fn new_math(start: SourceRef<ET>) -> Self {
NodeList::Math {
children: MathNodeList::default(),
start,
tp: MathNodeListType::Target(ListTarget::none()),
}
}
}
pub struct BoxTarget<ET: EngineTypes>(
Option<Box<dyn FnOnce(&mut EngineReferences<ET>, TeXBox<ET>) -> TeXResult<(), ET>>>,
);
impl<ET: EngineTypes> crate::tex::nodes::BoxTarget<ET> {
pub fn new<F: FnOnce(&mut EngineReferences<ET>, TeXBox<ET>) -> TeXResult<(), ET> + 'static>(
f: F,
) -> Self {
crate::tex::nodes::BoxTarget(Some(Box::new(f)))
}
pub fn call(self, engine: &mut EngineReferences<ET>, bx: TeXBox<ET>) -> TeXResult<(), ET> {
match self.0 {
Some(f) => f(engine, bx),
None => unreachable!(),
}
}
pub fn none() -> Self {
crate::tex::nodes::BoxTarget(None)
}
pub fn is_some(&self) -> bool {
self.0.is_some()
}
}
impl<ET: EngineTypes> Debug for crate::tex::nodes::BoxTarget<ET> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self.0 {
None => f.write_str("BoxTarget(None)"),
Some(_) => f.write_str("BoxTarget(Some(_))"),
}
}
}
impl<ET: EngineTypes> Clone for crate::tex::nodes::BoxTarget<ET> {
fn clone(&self) -> Self {
crate::tex::nodes::BoxTarget(None)
}
}
pub struct ListTarget<ET: EngineTypes, N>(
Option<Box<dyn FnOnce(&mut EngineReferences<ET>, Vec<N>, SourceRef<ET>) -> TeXResult<(), ET>>>,
);
impl<ET: EngineTypes, N> ListTarget<ET, N> {
pub fn new<
F: FnOnce(&mut EngineReferences<ET>, Vec<N>, SourceRef<ET>) -> TeXResult<(), ET> + 'static,
>(
f: F,
) -> Self {
ListTarget(Some(Box::new(f)))
}
pub fn call(
self,
engine: &mut EngineReferences<ET>,
v: Vec<N>,
start: SourceRef<ET>,
) -> TeXResult<(), ET> {
match self.0 {
Some(f) => f(engine, v, start),
None => unreachable!(),
}
}
pub fn none() -> Self {
ListTarget(None)
}
pub fn is_some(&self) -> bool {
self.0.is_some()
}
}
impl<ET: EngineTypes, N> Debug for ListTarget<ET, N> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self.0 {
None => f.write_str("ListTarget(None)"),
Some(_) => f.write_str("ListTarget(Some(_))"),
}
}
}
impl<ET: EngineTypes, N> Clone for ListTarget<ET, N> {
fn clone(&self) -> Self {
ListTarget(None)
}
}