1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
9pub enum MathStyle {
10 #[default]
11 Display,
12 DisplayCramped,
13 Text,
14 TextCramped,
15 Script,
16 ScriptCramped,
17 ScriptScript,
18 ScriptScriptCramped,
19}
20
21impl MathStyle {
22 pub fn numerator(self) -> Self {
32 match self {
33 Self::Display => Self::Text,
34 Self::DisplayCramped => Self::TextCramped,
35 Self::Text => Self::Script,
36 Self::TextCramped => Self::ScriptCramped,
37 Self::Script | Self::ScriptScript => Self::ScriptScript,
38 Self::ScriptCramped | Self::ScriptScriptCramped => Self::ScriptScriptCramped,
39 }
40 }
41
42 pub fn denominator(self) -> Self {
44 match self {
45 Self::Display | Self::DisplayCramped => Self::TextCramped,
46 Self::Text | Self::TextCramped => Self::ScriptCramped,
47 Self::Script | Self::ScriptCramped | Self::ScriptScript | Self::ScriptScriptCramped => {
48 Self::ScriptScriptCramped
49 }
50 }
51 }
52
53 pub fn superscript(self) -> Self {
55 match self {
56 Self::Display | Self::Text => Self::Script,
57 Self::DisplayCramped | Self::TextCramped => Self::ScriptCramped,
58 Self::Script | Self::ScriptScript => Self::ScriptScript,
59 Self::ScriptCramped | Self::ScriptScriptCramped => Self::ScriptScriptCramped,
60 }
61 }
62
63 pub fn subscript(self) -> Self {
65 match self {
66 Self::Display | Self::DisplayCramped | Self::Text | Self::TextCramped => {
67 Self::ScriptCramped
68 }
69 Self::Script
70 | Self::ScriptCramped
71 | Self::ScriptScript
72 | Self::ScriptScriptCramped => Self::ScriptScriptCramped,
73 }
74 }
75
76 pub fn cramped(self) -> Self {
78 match self {
79 Self::Display => Self::DisplayCramped,
80 Self::Text => Self::TextCramped,
81 Self::Script => Self::ScriptCramped,
82 Self::ScriptScript => Self::ScriptScriptCramped,
83 other => other,
84 }
85 }
86
87 pub fn text(self) -> Self {
90 match self {
91 Self::Display => Self::Display,
92 Self::DisplayCramped => Self::DisplayCramped,
93 Self::Text => Self::Text,
94 Self::TextCramped => Self::TextCramped,
95 Self::Script | Self::ScriptScript => Self::Text,
96 Self::ScriptCramped | Self::ScriptScriptCramped => Self::TextCramped,
97 }
98 }
99
100 pub fn is_display(self) -> bool {
101 matches!(self, Self::Display | Self::DisplayCramped)
102 }
103
104 pub fn is_cramped(self) -> bool {
105 matches!(
106 self,
107 Self::DisplayCramped
108 | Self::TextCramped
109 | Self::ScriptCramped
110 | Self::ScriptScriptCramped
111 )
112 }
113
114 pub fn is_tight(self) -> bool {
116 matches!(
117 self,
118 Self::Script
119 | Self::ScriptCramped
120 | Self::ScriptScript
121 | Self::ScriptScriptCramped
122 )
123 }
124
125 pub fn size_index(self) -> usize {
127 match self {
128 Self::Display | Self::DisplayCramped | Self::Text | Self::TextCramped => 0,
129 Self::Script | Self::ScriptCramped => 1,
130 Self::ScriptScript | Self::ScriptScriptCramped => 2,
131 }
132 }
133
134 pub fn size_multiplier(self) -> f64 {
136 match self {
137 Self::Display | Self::DisplayCramped | Self::Text | Self::TextCramped => 1.0,
138 Self::Script | Self::ScriptCramped => 0.7,
139 Self::ScriptScript | Self::ScriptScriptCramped => 0.5,
140 }
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 use MathStyle::*;
148
149 #[test]
152 fn test_numerator_all_styles() {
153 assert_eq!(Display.numerator(), Text);
155 assert_eq!(DisplayCramped.numerator(), TextCramped);
156 assert_eq!(Text.numerator(), Script);
157 assert_eq!(TextCramped.numerator(), ScriptCramped);
158 assert_eq!(Script.numerator(), ScriptScript);
159 assert_eq!(ScriptCramped.numerator(), ScriptScriptCramped);
160 assert_eq!(ScriptScript.numerator(), ScriptScript);
161 assert_eq!(ScriptScriptCramped.numerator(), ScriptScriptCramped);
162 }
163
164 #[test]
165 fn test_denominator_all_styles() {
166 assert_eq!(Display.denominator(), TextCramped);
168 assert_eq!(DisplayCramped.denominator(), TextCramped);
169 assert_eq!(Text.denominator(), ScriptCramped);
170 assert_eq!(TextCramped.denominator(), ScriptCramped);
171 assert_eq!(Script.denominator(), ScriptScriptCramped);
172 assert_eq!(ScriptCramped.denominator(), ScriptScriptCramped);
173 assert_eq!(ScriptScript.denominator(), ScriptScriptCramped);
174 assert_eq!(ScriptScriptCramped.denominator(), ScriptScriptCramped);
175 }
176
177 #[test]
178 fn test_superscript_all_styles() {
179 assert_eq!(Display.superscript(), Script);
181 assert_eq!(DisplayCramped.superscript(), ScriptCramped);
182 assert_eq!(Text.superscript(), Script);
183 assert_eq!(TextCramped.superscript(), ScriptCramped);
184 assert_eq!(Script.superscript(), ScriptScript);
185 assert_eq!(ScriptCramped.superscript(), ScriptScriptCramped);
186 assert_eq!(ScriptScript.superscript(), ScriptScript);
187 assert_eq!(ScriptScriptCramped.superscript(), ScriptScriptCramped);
188 }
189
190 #[test]
191 fn test_subscript_all_styles() {
192 assert_eq!(Display.subscript(), ScriptCramped);
194 assert_eq!(DisplayCramped.subscript(), ScriptCramped);
195 assert_eq!(Text.subscript(), ScriptCramped);
196 assert_eq!(TextCramped.subscript(), ScriptCramped);
197 assert_eq!(Script.subscript(), ScriptScriptCramped);
198 assert_eq!(ScriptCramped.subscript(), ScriptScriptCramped);
199 assert_eq!(ScriptScript.subscript(), ScriptScriptCramped);
200 assert_eq!(ScriptScriptCramped.subscript(), ScriptScriptCramped);
201 }
202
203 #[test]
204 fn test_cramped_all_styles() {
205 assert_eq!(Display.cramped(), DisplayCramped);
207 assert_eq!(DisplayCramped.cramped(), DisplayCramped);
208 assert_eq!(Text.cramped(), TextCramped);
209 assert_eq!(TextCramped.cramped(), TextCramped);
210 assert_eq!(Script.cramped(), ScriptCramped);
211 assert_eq!(ScriptCramped.cramped(), ScriptCramped);
212 assert_eq!(ScriptScript.cramped(), ScriptScriptCramped);
213 assert_eq!(ScriptScriptCramped.cramped(), ScriptScriptCramped);
214 }
215
216 #[test]
217 fn test_text_all_styles() {
218 assert_eq!(Display.text(), Display);
220 assert_eq!(DisplayCramped.text(), DisplayCramped);
221 assert_eq!(Text.text(), Text);
222 assert_eq!(TextCramped.text(), TextCramped);
223 assert_eq!(Script.text(), Text);
224 assert_eq!(ScriptCramped.text(), TextCramped);
225 assert_eq!(ScriptScript.text(), Text);
226 assert_eq!(ScriptScriptCramped.text(), TextCramped);
227 }
228
229 #[test]
230 fn test_is_display() {
231 assert!(Display.is_display());
232 assert!(DisplayCramped.is_display());
233 assert!(!Text.is_display());
234 assert!(!Script.is_display());
235 }
236
237 #[test]
238 fn test_is_tight() {
239 assert!(!Display.is_tight());
240 assert!(!Text.is_tight());
241 assert!(Script.is_tight());
242 assert!(ScriptCramped.is_tight());
243 assert!(ScriptScript.is_tight());
244 assert!(ScriptScriptCramped.is_tight());
245 }
246
247 #[test]
248 fn test_size_index() {
249 assert_eq!(Display.size_index(), 0);
250 assert_eq!(Text.size_index(), 0);
251 assert_eq!(Script.size_index(), 1);
252 assert_eq!(ScriptScript.size_index(), 2);
253 }
254
255 #[test]
256 fn test_size_multiplier() {
257 assert!((Display.size_multiplier() - 1.0).abs() < f64::EPSILON);
258 assert!((Text.size_multiplier() - 1.0).abs() < f64::EPSILON);
259 assert!((Script.size_multiplier() - 0.7).abs() < f64::EPSILON);
260 assert!((ScriptScript.size_multiplier() - 0.5).abs() < f64::EPSILON);
261 }
262}