use std::collections::HashMap;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Renderer {
MathJaxV3,
Katex,
}
impl Renderer {
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::MathJaxV3 => "MathJax v3",
Self::Katex => "KaTeX",
}
}
#[must_use]
pub const fn package_noun(self) -> &'static str {
match self {
Self::MathJaxV3 => "package",
Self::Katex => "extension",
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub(crate) struct PackageMask(u32);
impl PackageMask {
pub(crate) const BASE: Self = Self(1 << 0);
pub(crate) const AMS: Self = Self(1 << 1);
pub(crate) const NEWCOMMAND: Self = Self(1 << 2);
pub(crate) const CONFIGMACROS: Self = Self(1 << 3);
pub(crate) const BOLDSYMBOL: Self = Self(1 << 4);
pub(crate) const REQUIRE: Self = Self(1 << 5);
pub(crate) const NOUNDEFINED: Self = Self(1 << 6);
pub(crate) const COLOR: Self = Self(1 << 7);
pub(crate) const CANCEL: Self = Self(1 << 8);
pub(crate) const ENCLOSE: Self = Self(1 << 9);
pub(crate) const MHCHEM: Self = Self(1 << 10);
pub(crate) const PHYSICS: Self = Self(1 << 11);
pub(crate) const AMSCD: Self = Self(1 << 12);
pub(crate) const BRACEMATCH: Self = Self(1 << 13);
pub(crate) const TEXTMACROS: Self = Self(1 << 14);
pub(crate) const MATHTOOLS: Self = Self(1 << 15);
pub(crate) const fn contains(self, other: Self) -> bool {
(self.0 & other.0) != 0
}
pub(crate) const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
}
pub(crate) fn package_from_name(name: &str) -> Option<PackageMask> {
match name {
"base" => Some(PackageMask::BASE),
"ams" => Some(PackageMask::AMS),
"newcommand" => Some(PackageMask::NEWCOMMAND),
"configmacros" => Some(PackageMask::CONFIGMACROS),
"boldsymbol" => Some(PackageMask::BOLDSYMBOL),
"require" => Some(PackageMask::REQUIRE),
"noundefined" => Some(PackageMask::NOUNDEFINED),
"color" => Some(PackageMask::COLOR),
"cancel" => Some(PackageMask::CANCEL),
"enclose" => Some(PackageMask::ENCLOSE),
"mhchem" => Some(PackageMask::MHCHEM),
"physics" => Some(PackageMask::PHYSICS),
"amscd" => Some(PackageMask::AMSCD),
"bracematch" => Some(PackageMask::BRACEMATCH),
"textmacros" => Some(PackageMask::TEXTMACROS),
"mathtools" => Some(PackageMask::MATHTOOLS),
_ => None,
}
}
pub(crate) fn package_name(mask: PackageMask) -> &'static str {
if mask.contains(PackageMask::BASE) {
"base"
} else if mask.contains(PackageMask::AMS) {
"ams"
} else if mask.contains(PackageMask::MHCHEM) {
"mhchem"
} else if mask.contains(PackageMask::PHYSICS) {
"physics"
} else if mask.contains(PackageMask::COLOR) {
"color"
} else if mask.contains(PackageMask::CANCEL) {
"cancel"
} else if mask.contains(PackageMask::ENCLOSE) {
"enclose"
} else if mask.contains(PackageMask::AMSCD) {
"amscd"
} else if mask.contains(PackageMask::BOLDSYMBOL) {
"boldsymbol"
} else if mask.contains(PackageMask::NEWCOMMAND) {
"newcommand"
} else if mask.contains(PackageMask::CONFIGMACROS) {
"configmacros"
} else if mask.contains(PackageMask::REQUIRE) {
"require"
} else if mask.contains(PackageMask::NOUNDEFINED) {
"noundefined"
} else if mask.contains(PackageMask::BRACEMATCH) {
"bracematch"
} else if mask.contains(PackageMask::TEXTMACROS) {
"textmacros"
} else if mask.contains(PackageMask::MATHTOOLS) {
"mathtools"
} else {
"unknown"
}
}
#[derive(Clone, Debug)]
pub struct RenderProfile {
pub(crate) renderer: Renderer,
pub(crate) packages: PackageMask,
pub(crate) macros: HashMap<String, u8>,
}
impl Default for RenderProfile {
fn default() -> Self {
Self::mathjax_v3()
}
}
impl RenderProfile {
#[must_use]
pub fn mathjax_v3() -> Self {
let packages = PackageMask::BASE
.union(PackageMask::AMS)
.union(PackageMask::NEWCOMMAND)
.union(PackageMask::NOUNDEFINED)
.union(PackageMask::REQUIRE)
.union(PackageMask::CONFIGMACROS)
.union(PackageMask::BOLDSYMBOL);
Self {
renderer: Renderer::MathJaxV3,
packages,
macros: HashMap::new(),
}
}
#[must_use]
pub fn katex() -> Self {
let packages = PackageMask::BASE
.union(PackageMask::AMS)
.union(PackageMask::NEWCOMMAND)
.union(PackageMask::CONFIGMACROS);
Self {
renderer: Renderer::Katex,
packages,
macros: HashMap::new(),
}
}
#[must_use]
pub const fn renderer(&self) -> Renderer {
self.renderer
}
#[must_use]
pub fn with_package(mut self, package: &str) -> Self {
if let Some(mask) = package_from_name(package) {
self.packages = self.packages.union(mask);
}
self
}
#[must_use]
pub fn with_macro(mut self, name: impl Into<String>, arity: u8) -> Self {
self.macros.insert(name.into(), arity);
self
}
pub(crate) fn has_package(&self, mask: PackageMask) -> bool {
self.packages.contains(mask)
}
pub(crate) fn has_macro(&self, name: &str) -> bool {
self.macros.contains_key(name)
}
}