use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub enum MathStyle {
#[default]
Display,
DisplayCramped,
Text,
TextCramped,
Script,
ScriptCramped,
ScriptScript,
ScriptScriptCramped,
}
impl MathStyle {
pub fn numerator(self) -> Self {
match self {
Self::Display => Self::Text,
Self::DisplayCramped => Self::TextCramped,
Self::Text => Self::Script,
Self::TextCramped => Self::ScriptCramped,
Self::Script | Self::ScriptScript => Self::ScriptScript,
Self::ScriptCramped | Self::ScriptScriptCramped => Self::ScriptScriptCramped,
}
}
pub fn denominator(self) -> Self {
match self {
Self::Display | Self::DisplayCramped => Self::TextCramped,
Self::Text | Self::TextCramped => Self::ScriptCramped,
Self::Script | Self::ScriptCramped | Self::ScriptScript | Self::ScriptScriptCramped => {
Self::ScriptScriptCramped
}
}
}
pub fn superscript(self) -> Self {
match self {
Self::Display | Self::Text => Self::Script,
Self::DisplayCramped | Self::TextCramped => Self::ScriptCramped,
Self::Script | Self::ScriptScript => Self::ScriptScript,
Self::ScriptCramped | Self::ScriptScriptCramped => Self::ScriptScriptCramped,
}
}
pub fn subscript(self) -> Self {
match self {
Self::Display | Self::DisplayCramped | Self::Text | Self::TextCramped => {
Self::ScriptCramped
}
Self::Script
| Self::ScriptCramped
| Self::ScriptScript
| Self::ScriptScriptCramped => Self::ScriptScriptCramped,
}
}
pub fn cramped(self) -> Self {
match self {
Self::Display => Self::DisplayCramped,
Self::Text => Self::TextCramped,
Self::Script => Self::ScriptCramped,
Self::ScriptScript => Self::ScriptScriptCramped,
other => other,
}
}
pub fn text(self) -> Self {
match self {
Self::Display => Self::Display,
Self::DisplayCramped => Self::DisplayCramped,
Self::Text => Self::Text,
Self::TextCramped => Self::TextCramped,
Self::Script | Self::ScriptScript => Self::Text,
Self::ScriptCramped | Self::ScriptScriptCramped => Self::TextCramped,
}
}
pub fn is_display(self) -> bool {
matches!(self, Self::Display | Self::DisplayCramped)
}
pub fn is_cramped(self) -> bool {
matches!(
self,
Self::DisplayCramped
| Self::TextCramped
| Self::ScriptCramped
| Self::ScriptScriptCramped
)
}
pub fn is_tight(self) -> bool {
matches!(
self,
Self::Script
| Self::ScriptCramped
| Self::ScriptScript
| Self::ScriptScriptCramped
)
}
pub fn size_index(self) -> usize {
match self {
Self::Display | Self::DisplayCramped | Self::Text | Self::TextCramped => 0,
Self::Script | Self::ScriptCramped => 1,
Self::ScriptScript | Self::ScriptScriptCramped => 2,
}
}
pub fn size_multiplier(self) -> f64 {
match self {
Self::Display | Self::DisplayCramped | Self::Text | Self::TextCramped => 1.0,
Self::Script | Self::ScriptCramped => 0.7,
Self::ScriptScript | Self::ScriptScriptCramped => 0.5,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use MathStyle::*;
#[test]
fn test_numerator_all_styles() {
assert_eq!(Display.numerator(), Text);
assert_eq!(DisplayCramped.numerator(), TextCramped);
assert_eq!(Text.numerator(), Script);
assert_eq!(TextCramped.numerator(), ScriptCramped);
assert_eq!(Script.numerator(), ScriptScript);
assert_eq!(ScriptCramped.numerator(), ScriptScriptCramped);
assert_eq!(ScriptScript.numerator(), ScriptScript);
assert_eq!(ScriptScriptCramped.numerator(), ScriptScriptCramped);
}
#[test]
fn test_denominator_all_styles() {
assert_eq!(Display.denominator(), TextCramped);
assert_eq!(DisplayCramped.denominator(), TextCramped);
assert_eq!(Text.denominator(), ScriptCramped);
assert_eq!(TextCramped.denominator(), ScriptCramped);
assert_eq!(Script.denominator(), ScriptScriptCramped);
assert_eq!(ScriptCramped.denominator(), ScriptScriptCramped);
assert_eq!(ScriptScript.denominator(), ScriptScriptCramped);
assert_eq!(ScriptScriptCramped.denominator(), ScriptScriptCramped);
}
#[test]
fn test_superscript_all_styles() {
assert_eq!(Display.superscript(), Script);
assert_eq!(DisplayCramped.superscript(), ScriptCramped);
assert_eq!(Text.superscript(), Script);
assert_eq!(TextCramped.superscript(), ScriptCramped);
assert_eq!(Script.superscript(), ScriptScript);
assert_eq!(ScriptCramped.superscript(), ScriptScriptCramped);
assert_eq!(ScriptScript.superscript(), ScriptScript);
assert_eq!(ScriptScriptCramped.superscript(), ScriptScriptCramped);
}
#[test]
fn test_subscript_all_styles() {
assert_eq!(Display.subscript(), ScriptCramped);
assert_eq!(DisplayCramped.subscript(), ScriptCramped);
assert_eq!(Text.subscript(), ScriptCramped);
assert_eq!(TextCramped.subscript(), ScriptCramped);
assert_eq!(Script.subscript(), ScriptScriptCramped);
assert_eq!(ScriptCramped.subscript(), ScriptScriptCramped);
assert_eq!(ScriptScript.subscript(), ScriptScriptCramped);
assert_eq!(ScriptScriptCramped.subscript(), ScriptScriptCramped);
}
#[test]
fn test_cramped_all_styles() {
assert_eq!(Display.cramped(), DisplayCramped);
assert_eq!(DisplayCramped.cramped(), DisplayCramped);
assert_eq!(Text.cramped(), TextCramped);
assert_eq!(TextCramped.cramped(), TextCramped);
assert_eq!(Script.cramped(), ScriptCramped);
assert_eq!(ScriptCramped.cramped(), ScriptCramped);
assert_eq!(ScriptScript.cramped(), ScriptScriptCramped);
assert_eq!(ScriptScriptCramped.cramped(), ScriptScriptCramped);
}
#[test]
fn test_text_all_styles() {
assert_eq!(Display.text(), Display);
assert_eq!(DisplayCramped.text(), DisplayCramped);
assert_eq!(Text.text(), Text);
assert_eq!(TextCramped.text(), TextCramped);
assert_eq!(Script.text(), Text);
assert_eq!(ScriptCramped.text(), TextCramped);
assert_eq!(ScriptScript.text(), Text);
assert_eq!(ScriptScriptCramped.text(), TextCramped);
}
#[test]
fn test_is_display() {
assert!(Display.is_display());
assert!(DisplayCramped.is_display());
assert!(!Text.is_display());
assert!(!Script.is_display());
}
#[test]
fn test_is_tight() {
assert!(!Display.is_tight());
assert!(!Text.is_tight());
assert!(Script.is_tight());
assert!(ScriptCramped.is_tight());
assert!(ScriptScript.is_tight());
assert!(ScriptScriptCramped.is_tight());
}
#[test]
fn test_size_index() {
assert_eq!(Display.size_index(), 0);
assert_eq!(Text.size_index(), 0);
assert_eq!(Script.size_index(), 1);
assert_eq!(ScriptScript.size_index(), 2);
}
#[test]
fn test_size_multiplier() {
assert!((Display.size_multiplier() - 1.0).abs() < f64::EPSILON);
assert!((Text.size_multiplier() - 1.0).abs() < f64::EPSILON);
assert!((Script.size_multiplier() - 0.7).abs() < f64::EPSILON);
assert!((ScriptScript.size_multiplier() - 0.5).abs() < f64::EPSILON);
}
}