use crate::ir::AtomClass;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Spacing {
None,
Thin, Med, Thick, }
impl Spacing {
pub fn to_px(self, font_size: f32) -> f32 {
let em = font_size;
match self {
Spacing::None => 0.0,
Spacing::Thin => em * 3.0 / 18.0,
Spacing::Med => em * 4.0 / 18.0,
Spacing::Thick => em * 5.0 / 18.0,
}
}
}
fn idx(c: AtomClass) -> usize {
match c {
AtomClass::Ord => 0,
AtomClass::Op => 1,
AtomClass::Bin => 2,
AtomClass::Rel => 3,
AtomClass::Open => 4,
AtomClass::Close => 5,
AtomClass::Punct => 6,
AtomClass::Inner => 7,
}
}
const T: [[Spacing; 8]; 8] = {
use Spacing::*;
[
[None, Thin, Med, Thick, None, None, None, Thin],
[Thin, Thin, None, Thick, None, None, None, Thin],
[Med, Med, None, None, Med, None, None, Med],
[Thick, Thick, None, None, Thick, None, None, Thick],
[None, None, None, None, None, None, None, None],
[None, Thin, Med, Thick, None, None, None, Thin],
[Thin, Thin, None, Thin, Thin, Thin, Thin, Thin],
[Thin, Thin, Med, Thick, Thin, None, Thin, Thin],
]
};
pub fn between(left: AtomClass, right: AtomClass, display_or_text: bool) -> Spacing {
let raw = T[idx(left)][idx(right)];
if !display_or_text && matches!(raw, Spacing::Med | Spacing::Thick) {
Spacing::None
} else {
raw
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ir::AtomClass;
#[test]
fn ord_op_is_thin() {
let s = between(AtomClass::Ord, AtomClass::Op, true);
assert_eq!(s, Spacing::Thin);
}
#[test]
fn bin_bin_is_none_per_tex() {
let s = between(AtomClass::Bin, AtomClass::Bin, true);
assert_eq!(s, Spacing::None);
}
#[test]
fn ord_rel_is_thick() {
let s = between(AtomClass::Ord, AtomClass::Rel, true);
assert_eq!(s, Spacing::Thick);
}
#[test]
fn script_style_suppresses_med_thick() {
let s = between(AtomClass::Ord, AtomClass::Rel, false);
assert_eq!(s, Spacing::None);
}
}