1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum MathClass {
6 Ord, Op, Bin, Rel, Open, Close, Punct, Inner, }
15
16#[rustfmt::skip]
25const SPACING_TABLE: [[i8; 8]; 8] = [
26[ 0, 3, 4, 5, 0, 0, 0, 3],
28[ 3, 4, 0, 5, 0, 0, 0, 3],
29[ 4, 4, 0, 0, 4, 0, 0, 4],
30[ 5, 5, 0, 0, 5, 0, 0, 5],
31[ 0, 0, 0, 0, 0, 0, 0, 0],
32[ 0, 3, 4, 5, 0, 0, 0, 3],
33[ 3, 3, 0, 5, 3, 3, 3, 3],
34[ 3, 3, 4, 5, 3, 0, 3, 3],
35];
36
37#[rustfmt::skip]
40const TIGHT_SPACING_TABLE: [[i8; 8]; 8] = [
41[ 0, 3, 0, 0, 0, 0, 0, 0],
43[ 3, 3, 0, 0, 0, 0, 0, 0],
44[ 0, 0, 0, 0, 0, 0, 0, 0],
45[ 0, 0, 0, 0, 0, 0, 0, 0],
46[ 0, 0, 0, 0, 0, 0, 0, 0],
47[ 0, 3, 0, 0, 0, 0, 0, 0],
48[ 0, 0, 0, 0, 0, 0, 0, 0],
49[ 0, 3, 0, 0, 0, 0, 0, 0],
50];
51
52impl MathClass {
53 fn index(self) -> usize {
54 match self {
55 Self::Ord => 0,
56 Self::Op => 1,
57 Self::Bin => 2,
58 Self::Rel => 3,
59 Self::Open => 4,
60 Self::Close => 5,
61 Self::Punct => 6,
62 Self::Inner => 7,
63 }
64 }
65}
66
67pub fn atom_spacing(left: MathClass, right: MathClass, tight: bool) -> f64 {
72 let table = if tight { &TIGHT_SPACING_TABLE } else { &SPACING_TABLE };
73 table[left.index()][right.index()] as f64
74}
75
76pub fn mu_to_em(mu: f64, quad: f64) -> f64 {
78 mu * quad / 18.0
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_ord_bin_spacing() {
87 assert_eq!(atom_spacing(MathClass::Ord, MathClass::Bin, false), 4.0);
88 }
89
90 #[test]
91 fn test_ord_rel_spacing() {
92 assert_eq!(atom_spacing(MathClass::Ord, MathClass::Rel, false), 5.0);
93 }
94
95 #[test]
96 fn test_ord_ord_no_spacing() {
97 assert_eq!(atom_spacing(MathClass::Ord, MathClass::Ord, false), 0.0);
98 }
99
100 #[test]
101 fn test_tight_eliminates_most_spacing() {
102 assert_eq!(atom_spacing(MathClass::Ord, MathClass::Bin, true), 0.0);
103 assert_eq!(atom_spacing(MathClass::Ord, MathClass::Rel, true), 0.0);
104 }
105
106 #[test]
107 fn test_tight_keeps_op_spacing() {
108 assert_eq!(atom_spacing(MathClass::Ord, MathClass::Op, true), 3.0);
109 assert_eq!(atom_spacing(MathClass::Op, MathClass::Ord, true), 3.0);
110 }
111
112 #[test]
113 fn test_mu_to_em() {
114 let quad = 1.0;
115 assert!((mu_to_em(3.0, quad) - 3.0 / 18.0).abs() < 1e-10);
116 assert!((mu_to_em(4.0, quad) - 4.0 / 18.0).abs() < 1e-10);
117 assert!((mu_to_em(5.0, quad) - 5.0 / 18.0).abs() < 1e-10);
118 }
119}