1use rust_latex_parser::MathFontKind;
7
8pub fn map_char(kind: &MathFontKind, ch: char) -> char {
11 match kind {
12 MathFontKind::Bold => to_bold(ch),
13 MathFontKind::Blackboard => to_double_struck(ch),
14 MathFontKind::Calligraphic => to_script(ch),
15 MathFontKind::Fraktur => to_fraktur(ch),
16 MathFontKind::Roman => ch, MathFontKind::SansSerif => to_sans_serif(ch),
18 MathFontKind::Monospace => to_monospace(ch),
19 }
20}
21
22pub fn map_str(kind: &MathFontKind, s: &str) -> String {
24 s.chars().map(|c| map_char(kind, c)).collect()
25}
26
27fn to_bold(ch: char) -> char {
31 match ch {
32 'A'..='Z' => char::from_u32(0x1D400 + (ch as u32 - 'A' as u32)).unwrap_or(ch),
33 'a'..='z' => char::from_u32(0x1D41A + (ch as u32 - 'a' as u32)).unwrap_or(ch),
34 '0'..='9' => char::from_u32(0x1D7CE + (ch as u32 - '0' as u32)).unwrap_or(ch),
35 'Α'..='Ω' => char::from_u32(0x1D6A8 + (ch as u32 - 'Α' as u32)).unwrap_or(ch),
37 'α'..='ω' => char::from_u32(0x1D6C2 + (ch as u32 - 'α' as u32)).unwrap_or(ch),
39 _ => ch,
40 }
41}
42
43fn to_double_struck(ch: char) -> char {
48 match ch {
49 'C' => 'ℂ',
50 'H' => 'ℍ',
51 'N' => 'ℕ',
52 'P' => 'ℙ',
53 'Q' => 'ℚ',
54 'R' => 'ℝ',
55 'Z' => 'ℤ',
56 'A' | 'B' | 'D'..='G' | 'I'..='M' | 'O' | 'S'..='Y' => {
57 char::from_u32(0x1D538 + (ch as u32 - 'A' as u32)).unwrap_or(ch)
58 }
59 'a'..='z' => char::from_u32(0x1D552 + (ch as u32 - 'a' as u32)).unwrap_or(ch),
60 '0'..='9' => char::from_u32(0x1D7D8 + (ch as u32 - '0' as u32)).unwrap_or(ch),
61 _ => ch,
62 }
63}
64
65fn to_script(ch: char) -> char {
70 match ch {
71 'B' => 'ℬ',
72 'E' => 'ℰ',
73 'F' => 'ℱ',
74 'H' => 'ℋ',
75 'I' => 'ℐ',
76 'L' => 'ℒ',
77 'M' => 'ℳ',
78 'R' => 'ℛ',
79 'e' => 'ℯ',
80 'g' => 'ℊ',
81 'o' => 'ℴ',
82 'A' | 'C' | 'D' | 'G' | 'J' | 'K' | 'N'..='Q' | 'S'..='Z' => {
83 char::from_u32(0x1D49C + (ch as u32 - 'A' as u32)).unwrap_or(ch)
84 }
85 'a'..='d' | 'f' | 'h'..='n' | 'p'..='z' => {
86 char::from_u32(0x1D4B6 + (ch as u32 - 'a' as u32)).unwrap_or(ch)
87 }
88 _ => ch,
89 }
90}
91
92fn to_fraktur(ch: char) -> char {
96 match ch {
97 'C' => 'ℭ',
98 'H' => 'ℌ',
99 'I' => 'ℑ',
100 'R' => 'ℜ',
101 'Z' => 'ℨ',
102 'A' | 'B' | 'D'..='G' | 'J'..='Q' | 'S'..='Y' => {
103 char::from_u32(0x1D504 + (ch as u32 - 'A' as u32)).unwrap_or(ch)
104 }
105 'a'..='z' => char::from_u32(0x1D51E + (ch as u32 - 'a' as u32)).unwrap_or(ch),
106 _ => ch,
107 }
108}
109
110fn to_sans_serif(ch: char) -> char {
114 match ch {
115 'A'..='Z' => char::from_u32(0x1D5A0 + (ch as u32 - 'A' as u32)).unwrap_or(ch),
116 'a'..='z' => char::from_u32(0x1D5BA + (ch as u32 - 'a' as u32)).unwrap_or(ch),
117 '0'..='9' => char::from_u32(0x1D7E2 + (ch as u32 - '0' as u32)).unwrap_or(ch),
118 _ => ch,
119 }
120}
121
122fn to_monospace(ch: char) -> char {
126 match ch {
127 'A'..='Z' => char::from_u32(0x1D670 + (ch as u32 - 'A' as u32)).unwrap_or(ch),
128 'a'..='z' => char::from_u32(0x1D68A + (ch as u32 - 'a' as u32)).unwrap_or(ch),
129 '0'..='9' => char::from_u32(0x1D7F6 + (ch as u32 - '0' as u32)).unwrap_or(ch),
130 _ => ch,
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn test_bold() {
140 assert_eq!(to_bold('A'), '𝐀');
141 assert_eq!(to_bold('Z'), '𝐙');
142 assert_eq!(to_bold('a'), '𝐚');
143 assert_eq!(to_bold('z'), '𝐳');
144 assert_eq!(to_bold('0'), '𝟎');
145 }
146
147 #[test]
148 fn test_double_struck() {
149 assert_eq!(to_double_struck('R'), 'ℝ');
150 assert_eq!(to_double_struck('Z'), 'ℤ');
151 assert_eq!(to_double_struck('N'), 'ℕ');
152 assert_eq!(to_double_struck('C'), 'ℂ');
153 assert_eq!(to_double_struck('Q'), 'ℚ');
154 assert_eq!(to_double_struck('A'), '𝔸');
156 }
157
158 #[test]
159 fn test_script() {
160 assert_eq!(to_script('L'), 'ℒ');
161 assert_eq!(to_script('H'), 'ℋ');
162 assert_eq!(to_script('B'), 'ℬ');
163 assert_eq!(to_script('A'), '𝒜');
165 }
166
167 #[test]
168 fn test_fraktur() {
169 assert_eq!(to_fraktur('H'), 'ℌ');
170 assert_eq!(to_fraktur('R'), 'ℜ');
171 assert_eq!(to_fraktur('a'), '𝔞');
172 assert_eq!(to_fraktur('g'), '𝔤');
173 }
174
175 #[test]
176 fn test_sans_serif() {
177 assert_eq!(to_sans_serif('A'), '𝖠');
178 assert_eq!(to_sans_serif('a'), '𝖺');
179 }
180
181 #[test]
182 fn test_monospace() {
183 assert_eq!(to_monospace('A'), '𝙰');
184 assert_eq!(to_monospace('a'), '𝚊');
185 assert_eq!(to_monospace('0'), '𝟶');
186 }
187
188 #[test]
189 fn test_non_letter_passthrough() {
190 assert_eq!(map_char(&MathFontKind::Bold, '+'), '+');
192 assert_eq!(map_char(&MathFontKind::Blackboard, ' '), ' ');
193 }
194}