1use super::*;
2
3impl MathElement for MathOperator {
4 fn tag_name(&self) -> &'static str {
5 "mo"
6 }
7
8 fn get_attributes(&self) -> &BTreeMap<String, String> {
9 &self.attributes
10 }
11
12 fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
13 &mut self.attributes
14 }
15}
16
17impl MathOperator {
18 pub fn new<S>(text: S) -> Self
20 where
21 S: ToString,
22 {
23 Self { operator: text.to_string(), attributes: Default::default() }
24 }
25 pub fn mark_fence(self) -> Self {
27 self.with_attribute("fence", true)
28 }
29 pub fn mark_separator(self) -> Self {
31 self.with_attribute("separator", true)
32 }
33 pub fn mark_large_operator(self) -> Self {
35 self.with_attribute("largeop", true)
36 }
37 pub fn mark_stretchy(self) -> Self {
39 self.with_attribute("stretchy", true)
40 }
41 pub fn mark_symmetric(self) -> Self {
43 self.mark_stretchy().with_attribute("symmetric", true)
44 }
45 pub fn with_space(self, lhs: f32, rhs: f32) -> Self {
47 self.with_attribute("lspace", lhs).with_attribute("rspace", rhs)
48 }
49 pub fn with_size(self, min: f32, max: f32) -> Self {
51 self.mark_stretchy().with_attribute("minsize", min).with_attribute("maxsize", max)
52 }
53}
54
55impl Default for MathSpace {
56 fn default() -> Self {
57 MathSpace::new(1.0)
58 }
59}
60
61impl MathElement for MathSpace {
62 fn tag_name(&self) -> &'static str {
63 "mspace"
64 }
65
66 fn get_attributes(&self) -> &BTreeMap<String, String> {
67 &self.attributes
68 }
69
70 fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
71 &mut self.attributes
72 }
73}
74
75impl MathSpace {
76 pub fn new(width: f32) -> Self {
78 let mut attributes = BTreeMap::new();
79 attributes.insert("width".to_string(), format!("{}rem", width));
80 Self { attributes }
81 }
82}
83
84impl MathElement for MathSqrt {
85 fn tag_name(&self) -> &'static str {
86 if self.surd.is_none() { "msqrt" } else { "mroot" }
87 }
88
89 fn get_attributes(&self) -> &BTreeMap<String, String> {
90 todo!()
91 }
92
93 fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
94 todo!()
95 }
96}
97
98impl MathSqrt {
99 pub fn sqrt(base: MathML) -> Self {
101 Self { base, surd: None }
102 }
103 pub fn surd(base: MathML, power: MathML) -> Self {
105 Self { base, surd: Some(power) }
106 }
107}
108
109impl MathElement for MathMultiScript {
110 fn tag_name(&self) -> &'static str {
111 if self.is_sub_super_script() {
112 "msubsup"
113 }
114 else if self.is_sub_script() {
115 "msub"
116 }
117 else if self.is_super_script() {
118 "msup"
119 }
120 else {
121 "mmultiscripts"
122 }
123 }
124
125 fn get_attributes(&self) -> &BTreeMap<String, String> {
126 &self.attributes
127 }
128
129 fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
130 &mut self.attributes
131 }
132}
133
134impl MathMultiScript {
135 pub fn new(base: MathML, lu: Vec<MathML>, ld: Vec<MathML>, ru: Vec<MathML>, rd: Vec<MathML>) -> Self {
137 Self { base, ru, rd, lu, ld, attributes: BTreeMap::new() }
138 }
139 pub fn sub_script(base: MathML, sub: MathML) -> Self {
141 MathMultiScript::new(base, vec![], vec![], vec![], vec![sub])
142 }
143 pub fn is_sub_script(&self) -> bool {
145 self.lu.is_empty() && self.ld.is_empty() && self.ru.is_empty() && self.rd.len() == 1
146 }
147 pub fn super_script(base: MathML, sup: MathML) -> Self {
149 MathMultiScript::new(base, vec![], vec![], vec![sup], vec![])
150 }
151 pub fn is_super_script(&self) -> bool {
153 self.lu.is_empty() && self.ld.is_empty() && self.ru.len() == 1 && self.rd.is_empty()
154 }
155 pub fn sub_super_script(base: MathML, sub: MathML, sup: MathML) -> Self {
157 MathMultiScript::new(base, vec![], vec![], vec![sup], vec![sub])
158 }
159 pub fn is_sub_super_script(&self) -> bool {
161 self.lu.is_empty() && self.ld.is_empty() && self.ru.len() == 1 && self.rd.len() == 1
162 }
163}
164
165impl MathFenced {
166 pub fn new<I>(base: I, lhs: char, rhs: char) -> Self
168 where
169 I: IntoIterator<Item = MathML>,
170 {
171 Self { base: base.into_iter().collect(), open: lhs, close: rhs, separators: String::new() }
172 }
173 pub fn parentheses<I>(base: I) -> Self
175 where
176 I: IntoIterator<Item = MathML>,
177 {
178 Self::new(base, '(', ')')
179 }
180 pub fn brackets<I>(base: I) -> Self
182 where
183 I: IntoIterator<Item = MathML>,
184 {
185 Self::new(base, '[', ']')
186 }
187 pub fn curly<I>(base: I) -> Self
189 where
190 I: IntoIterator<Item = MathML>,
191 {
192 Self::new(base, '{', '}')
193 }
194 pub fn with_separators<S>(mut self, separators: S) -> Self
196 where
197 S: ToString,
198 {
199 self.separators = separators.to_string();
200 self
201 }
202}
203
204impl MathElement for MathUnderOver {
205 fn tag_name(&self) -> &'static str {
206 match (&self.under, &self.over) {
207 (Some(_), Some(_)) => "munderover",
208 (Some(_), None) => "munder",
209 (None, Some(_)) => "mover",
210 (None, None) => unreachable!("MathUnderOver must have at least one of under or over"),
211 }
212 }
213
214 fn get_attributes(&self) -> &BTreeMap<String, String> {
215 &self.attributes
216 }
217
218 fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
219 &mut self.attributes
220 }
221}
222
223impl MathUnderOver {
224 pub fn under(base: MathML, under: MathML) -> Self {
226 Self { base, under: Some(under), over: None, attributes: BTreeMap::new() }
227 }
228 pub fn over(base: MathML, over: MathML) -> Self {
230 Self { base, under: None, over: Some(over), attributes: BTreeMap::new() }
231 }
232 pub fn under_over(base: MathML, under: MathML, over: MathML) -> Self {
234 Self { base, under: Some(under), over: Some(over), attributes: BTreeMap::new() }
235 }
236 pub fn with_accent_over(self) -> Self {
238 self.with_attribute("accent", true)
239 }
240 pub fn with_accent_under(self) -> Self {
242 self.with_attribute("accentunder", true)
243 }
244}
245
246impl MathML {
247 pub fn operation<S>(text: S) -> Self
249 where
250 S: ToString,
251 {
252 MathOperator::new(text).into()
253 }
254}