mdwright_mathrender/
profile.rs1use std::collections::HashMap;
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum Renderer {
13 MathJaxV3,
15 Katex,
17}
18
19impl Renderer {
20 #[must_use]
22 pub const fn name(self) -> &'static str {
23 match self {
24 Self::MathJaxV3 => "MathJax v3",
25 Self::Katex => "KaTeX",
26 }
27 }
28
29 #[must_use]
34 pub const fn package_noun(self) -> &'static str {
35 match self {
36 Self::MathJaxV3 => "package",
37 Self::Katex => "extension",
38 }
39 }
40}
41
42#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
47pub(crate) struct PackageMask(u32);
48
49impl PackageMask {
50 pub(crate) const BASE: Self = Self(1 << 0);
51 pub(crate) const AMS: Self = Self(1 << 1);
52 pub(crate) const NEWCOMMAND: Self = Self(1 << 2);
53 pub(crate) const CONFIGMACROS: Self = Self(1 << 3);
54 pub(crate) const BOLDSYMBOL: Self = Self(1 << 4);
55 pub(crate) const REQUIRE: Self = Self(1 << 5);
56 pub(crate) const NOUNDEFINED: Self = Self(1 << 6);
57 pub(crate) const COLOR: Self = Self(1 << 7);
58 pub(crate) const CANCEL: Self = Self(1 << 8);
59 pub(crate) const ENCLOSE: Self = Self(1 << 9);
60 pub(crate) const MHCHEM: Self = Self(1 << 10);
61 pub(crate) const PHYSICS: Self = Self(1 << 11);
62 pub(crate) const AMSCD: Self = Self(1 << 12);
63 pub(crate) const BRACEMATCH: Self = Self(1 << 13);
64 pub(crate) const TEXTMACROS: Self = Self(1 << 14);
65 pub(crate) const MATHTOOLS: Self = Self(1 << 15);
66
67 pub(crate) const fn contains(self, other: Self) -> bool {
68 (self.0 & other.0) != 0
69 }
70
71 pub(crate) const fn union(self, other: Self) -> Self {
72 Self(self.0 | other.0)
73 }
74}
75
76pub(crate) fn package_from_name(name: &str) -> Option<PackageMask> {
81 match name {
82 "base" => Some(PackageMask::BASE),
83 "ams" => Some(PackageMask::AMS),
84 "newcommand" => Some(PackageMask::NEWCOMMAND),
85 "configmacros" => Some(PackageMask::CONFIGMACROS),
86 "boldsymbol" => Some(PackageMask::BOLDSYMBOL),
87 "require" => Some(PackageMask::REQUIRE),
88 "noundefined" => Some(PackageMask::NOUNDEFINED),
89 "color" => Some(PackageMask::COLOR),
90 "cancel" => Some(PackageMask::CANCEL),
91 "enclose" => Some(PackageMask::ENCLOSE),
92 "mhchem" => Some(PackageMask::MHCHEM),
93 "physics" => Some(PackageMask::PHYSICS),
94 "amscd" => Some(PackageMask::AMSCD),
95 "bracematch" => Some(PackageMask::BRACEMATCH),
96 "textmacros" => Some(PackageMask::TEXTMACROS),
97 "mathtools" => Some(PackageMask::MATHTOOLS),
98 _ => None,
99 }
100}
101
102pub(crate) fn package_name(mask: PackageMask) -> &'static str {
104 if mask.contains(PackageMask::BASE) {
105 "base"
106 } else if mask.contains(PackageMask::AMS) {
107 "ams"
108 } else if mask.contains(PackageMask::MHCHEM) {
109 "mhchem"
110 } else if mask.contains(PackageMask::PHYSICS) {
111 "physics"
112 } else if mask.contains(PackageMask::COLOR) {
113 "color"
114 } else if mask.contains(PackageMask::CANCEL) {
115 "cancel"
116 } else if mask.contains(PackageMask::ENCLOSE) {
117 "enclose"
118 } else if mask.contains(PackageMask::AMSCD) {
119 "amscd"
120 } else if mask.contains(PackageMask::BOLDSYMBOL) {
121 "boldsymbol"
122 } else if mask.contains(PackageMask::NEWCOMMAND) {
123 "newcommand"
124 } else if mask.contains(PackageMask::CONFIGMACROS) {
125 "configmacros"
126 } else if mask.contains(PackageMask::REQUIRE) {
127 "require"
128 } else if mask.contains(PackageMask::NOUNDEFINED) {
129 "noundefined"
130 } else if mask.contains(PackageMask::BRACEMATCH) {
131 "bracematch"
132 } else if mask.contains(PackageMask::TEXTMACROS) {
133 "textmacros"
134 } else if mask.contains(PackageMask::MATHTOOLS) {
135 "mathtools"
136 } else {
137 "unknown"
138 }
139}
140
141#[derive(Clone, Debug)]
144pub struct RenderProfile {
145 pub(crate) renderer: Renderer,
146 pub(crate) packages: PackageMask,
147 pub(crate) macros: HashMap<String, u8>,
148}
149
150impl Default for RenderProfile {
151 fn default() -> Self {
152 Self::mathjax_v3()
153 }
154}
155
156impl RenderProfile {
157 #[must_use]
160 pub fn mathjax_v3() -> Self {
161 let packages = PackageMask::BASE
162 .union(PackageMask::AMS)
163 .union(PackageMask::NEWCOMMAND)
164 .union(PackageMask::NOUNDEFINED)
165 .union(PackageMask::REQUIRE)
166 .union(PackageMask::CONFIGMACROS)
167 .union(PackageMask::BOLDSYMBOL);
168 Self {
169 renderer: Renderer::MathJaxV3,
170 packages,
171 macros: HashMap::new(),
172 }
173 }
174
175 #[must_use]
180 pub fn katex() -> Self {
181 let packages = PackageMask::BASE
182 .union(PackageMask::AMS)
183 .union(PackageMask::NEWCOMMAND)
184 .union(PackageMask::CONFIGMACROS);
185 Self {
186 renderer: Renderer::Katex,
187 packages,
188 macros: HashMap::new(),
189 }
190 }
191
192 #[must_use]
194 pub const fn renderer(&self) -> Renderer {
195 self.renderer
196 }
197
198 #[must_use]
202 pub fn with_package(mut self, package: &str) -> Self {
203 if let Some(mask) = package_from_name(package) {
204 self.packages = self.packages.union(mask);
205 }
206 self
207 }
208
209 #[must_use]
213 pub fn with_macro(mut self, name: impl Into<String>, arity: u8) -> Self {
214 self.macros.insert(name.into(), arity);
215 self
216 }
217
218 pub(crate) fn has_package(&self, mask: PackageMask) -> bool {
219 self.packages.contains(mask)
220 }
221
222 pub(crate) fn has_macro(&self, name: &str) -> bool {
223 self.macros.contains_key(name)
224 }
225}