1use crate::engine::fontsystem::Font;
4use crate::engine::state::State;
5use crate::engine::{EngineReferences, EngineTypes};
6use std::cmp::Ordering;
7use std::fmt::{Debug, Display, Formatter};
8use std::ops::Sub;
9use std::ops::{Add, Div, Mul, Neg};
10
11pub trait NumSet: Clone + Debug {
13 type Int: TeXInt;
15 type Dim: TeXDimen + Numeric<Self::Int>;
17 type MuDim: MuDim + Numeric<Self::Int>;
19 fn muskip_to_skip(muskip: MuSkip<Self::MuDim>, em: Self::Dim) -> Skip<Self::Dim> {
21 let base = Self::mudim_to_dim(muskip.base, em);
22 let stretch = muskip.stretch.map(|s| match s {
23 MuStretchShrink::Mu(i) => StretchShrink::Dim(Self::mudim_to_dim(i, em)),
24 MuStretchShrink::Fil(i) => StretchShrink::Fil(i),
25 MuStretchShrink::Fill(i) => StretchShrink::Fill(i),
26 MuStretchShrink::Filll(i) => StretchShrink::Filll(i),
27 });
28 let shrink = muskip.shrink.map(|s| match s {
29 MuStretchShrink::Mu(i) => StretchShrink::Dim(Self::mudim_to_dim(i, em)),
30 MuStretchShrink::Fil(i) => StretchShrink::Fil(i),
31 MuStretchShrink::Fill(i) => StretchShrink::Fill(i),
32 MuStretchShrink::Filll(i) => StretchShrink::Filll(i),
33 });
34 Skip::new(base, stretch, shrink)
35 }
36 fn mudim_to_dim(mudim: Self::MuDim, em: Self::Dim) -> Self::Dim;
38 fn dim_to_int(dim: Self::Dim) -> Self::Int;
40}
41
42pub trait Numeric<I: TeXInt>:
44 Eq
45 + Ord
46 + Neg<Output = Self>
47 + Add<Self, Output = Self>
48 + Mul<I, Output = Self>
49 + Div<I, Output = Self>
50 + Copy
51 + Default
52 + Debug
53 + Display
54{
55 #[must_use]
56 fn scale(&self, times: I, div: I) -> Self;
57}
58
59pub trait TeXInt:
61 Numeric<Self>
62 + From<i32>
63 + TryFrom<i64>
64 + Into<i64>
65 + TryInto<i32>
66 + Debug
67 + Display
68 + std::str::FromStr
69{
70 const MIN: Self;
72 const MAX: Self;
74}
75pub trait TeXDimen:
77 Copy
78 + Eq
79 + Ord
80 + Default
81 + Debug
82 + Display
83 + Add<Self, Output = Self>
84 + Sub<Self, Output = Self>
85 + Neg<Output = Self>
86 + Into<i64>
87 + std::iter::Sum
88{
89 const UNITS: &'static [&'static [u8]] = DEFAULT_UNITS;
91 fn scale_float(&self, times: f64) -> Self;
93 fn from_sp(sp: i32) -> Self;
95 fn from_float<ET: EngineTypes<Dim = Self>>(
97 engine: &EngineReferences<ET>,
98 f: f64,
99 dim: &[u8],
100 ) -> Self;
101}
102
103pub const DEFAULT_UNITS: &[&[u8]] = &[
118 b"pt", b"pc", b"in", b"bp", b"cm", b"mm", b"dd", b"cc", b"sp", b"em", b"ex", b"px",
119];
120
121#[derive(Clone, Copy, Eq, PartialEq, Debug)]
124pub struct DefaultNumSet;
125impl NumSet for DefaultNumSet {
126 type Int = i32;
127 type Dim = Dim32;
128 type MuDim = Mu;
129 fn mudim_to_dim(mudim: Mu, em: Dim32) -> Dim32 {
130 Dim32(((mudim.0 as f32 / 65536.0) * (em.0 as f32) / 18.0).round() as i32)
131 }
132 fn dim_to_int(dim: Dim32) -> i32 {
133 dim.0
134 }
135}
136
137impl Numeric<i32> for i32 {
138 fn scale(&self, times: i32, div: i32) -> Self {
139 ((*self as f64 * times as f64) / (div as f64)).round() as i32
140 }
141}
142impl TeXInt for i32 {
143 const MIN: Self = i32::MIN;
144 const MAX: Self = i32::MAX;
145}
146
147#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Default)]
149pub struct Dim32(pub i32);
150impl Numeric<i32> for Dim32 {
151 fn scale(&self, times: i32, div: i32) -> Self {
152 Self(self.0.scale(times, div))
153 }
154}
155impl Add for Dim32 {
156 type Output = Self;
157 fn add(self, rhs: Self) -> Self::Output {
158 Dim32(self.0 + rhs.0)
159 }
160}
161impl Sub for Dim32 {
162 type Output = Self;
163 fn sub(self, rhs: Self) -> Self::Output {
164 Dim32(self.0 - rhs.0)
165 }
166}
167impl Div<i32> for Dim32 {
168 type Output = Self;
169 fn div(self, rhs: i32) -> Self::Output {
170 Self(self.0 / rhs)
171 }
172}
173impl Mul<i32> for Dim32 {
174 type Output = Self;
175 fn mul(self, rhs: i32) -> Self::Output {
176 Self(self.0 * rhs)
177 }
178}
179impl Dim32 {
180 pub fn display_num(num: i32, unit: &str, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182 let mut val = num;
183 if val < 0 {
184 write!(f, "-")?;
185 val = -val;
186 }
187 write!(f, "{}.", val / 65536)?;
188 val = 10 * (val % 65536) + 5;
189 let mut delta = 10;
190 if val < delta {
191 return write!(f, "0{}", unit);
192 }
193 while val > delta {
194 if delta > 65536 {
195 val = val + 32768 - 50000;
196 }
197 write!(f, "{}", val / 65536)?;
198 val = 10 * (val % 65536);
199 delta *= 10;
200 }
201 write!(f, "{}", unit)
202 }
203}
204impl Neg for Dim32 {
205 type Output = Self;
206 fn neg(self) -> Self::Output {
207 Dim32(-self.0)
208 }
209}
210impl Display for Dim32 {
211 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213 Self::display_num(self.0, "pt", f)
214 }
215}
216impl From<Dim32> for i64 {
217 fn from(d: Dim32) -> i64 {
218 d.0 as i64
219 }
220}
221
222impl TeXDimen for Dim32 {
223 #[inline]
224 #[allow(clippy::cast_possible_truncation)]
225 fn scale_float(&self, times: f64) -> Self {
226 let times = (times * 65536.0).round() as i64;
227 Self((i64::from(self.0) * times / 65536) as i32)
228 }
229 fn from_sp(sp: i32) -> Self {
230 Self(sp)
231 }
232 fn from_float<ET: EngineTypes<Dim = Self>>(
233 engine: &EngineReferences<ET>,
234 float: f64,
235 dim: &[u8],
236 ) -> Self {
237 match dim {
238 b"sp" => Self(1).scale_float(float),
239 b"pt" => Self(65536).scale_float(float),
240 b"pc" => Self(786_432).scale_float(float),
241 b"in" => Self(4_736_286).scale_float(float),
242 b"bp" => Self(65_781).scale_float(float),
243 b"px" => Self(65_781).scale_float(float),
244 b"cm" => Self(1_864_679).scale_float(float),
245 b"mm" => Self(186_467).scale_float(float),
246 b"dd" => Self(70_124).scale_float(float),
247 b"cc" => Self(841_489).scale_float(float),
248 b"em" => {
249 let f = engine.state.get_current_font();
250 let em = f.get_dim(5);
251 em.scale_float(float)
252 }
253 b"ex" => {
254 let f = engine.state.get_current_font();
255 let ex = f.get_dim(4);
256 ex.scale_float(float)
257 }
258 _ => unreachable!(),
259 }
260 }
261}
262impl std::iter::Sum for Dim32 {
263 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
264 iter.fold(Self::default(), |a, b| a + b)
265 }
266}
267
268pub const STRETCH_SHRINK_UNITS: &[&[u8]] = &[b"fil", b"fill", b"filll"];
270
271#[derive(Clone, Copy, Eq, PartialEq, Debug, Default)]
273pub struct Skip<D: TeXDimen> {
274 pub base: D,
275 pub stretch: Option<StretchShrink<D>>,
276 pub shrink: Option<StretchShrink<D>>,
277}
278
279#[derive(Clone, Copy, Eq, PartialEq, Debug)]
281pub enum StretchShrink<D: TeXDimen> {
282 Dim(D),
283 Fil(i32),
284 Fill(i32),
285 Filll(i32),
286}
287impl<D: TeXDimen> StretchShrink<D> {
288 pub fn from_float<ET: EngineTypes<Dim = D>>(
291 engine: &EngineReferences<ET>,
292 float: f64,
293 dim: &[u8],
294 ) -> Self {
295 match dim {
296 b"fil" => Self::Fil((float * 65536.0).round() as i32),
297 b"fill" => Self::Fill((float * 65536.0).round() as i32),
298 b"filll" => Self::Filll((float * 65536.0).round() as i32),
299 _ => Self::Dim(D::from_float(engine, float, dim)),
300 }
301 }
302}
303impl<D: TeXDimen> Add<StretchShrink<D>> for StretchShrink<D> {
304 type Output = Self;
305 fn add(self, rhs: Self) -> Self::Output {
306 match (self, rhs) {
307 (Self::Dim(d1), Self::Dim(d2)) => Self::Dim(d1 + d2),
308 (Self::Fil(i1), Self::Fil(i2)) => Self::Fil(i1 + i2),
309 (Self::Fill(i1), Self::Fill(i2)) => Self::Fill(i1 + i2),
310 (Self::Filll(i1), Self::Filll(i2)) => Self::Filll(i1 + i2),
311 _ => self.max(rhs),
312 }
313 }
314}
315impl<D: TeXDimen> PartialOrd for StretchShrink<D> {
316 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
317 Some(self.cmp(other))
318 }
319}
320impl<D: TeXDimen> Ord for StretchShrink<D> {
321 fn cmp(&self, other: &Self) -> Ordering {
322 match (self, other) {
323 (Self::Dim(d1), Self::Dim(d2)) => d1.cmp(d2),
324 (Self::Fil(i1), Self::Fil(i2)) => i1.cmp(i2),
325 (Self::Fill(i1), Self::Fill(i2)) => i1.cmp(i2),
326 (Self::Filll(i1), Self::Filll(i2)) => i1.cmp(i2),
327 (Self::Filll(_), _) => Ordering::Greater,
328 (_, Self::Filll(_)) => Ordering::Less,
329 (Self::Fill(_), _) => Ordering::Greater,
330 (_, Self::Fill(_)) => Ordering::Less,
331 (Self::Fil(_), _) => Ordering::Greater,
332 (_, Self::Fil(_)) => Ordering::Less,
333 }
334 }
335}
336
337impl<D: TeXDimen> Add<D> for Skip<D> {
338 type Output = Self;
339 fn add(self, rhs: D) -> Self::Output {
340 Self {
341 base: self.base + rhs,
342 stretch: self.stretch,
343 shrink: self.shrink,
344 }
345 }
346}
347impl<D: TeXDimen> PartialOrd for Skip<D> {
348 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
349 Some(self.cmp(other))
350 }
351}
352impl<D: TeXDimen> Ord for Skip<D> {
353 fn cmp(&self, other: &Self) -> Ordering {
354 self.base.cmp(&other.base)
355 }
356}
357impl<D: TeXDimen> Add<Self> for Skip<D> {
358 type Output = Self;
359 fn add(self, rhs: Self) -> Self::Output {
360 Self {
361 base: self.base + rhs.base,
362 stretch: match (self.stretch, rhs.stretch) {
363 (Some(a), Some(b)) => Some(a + b),
364 (Some(a), None) => Some(a),
365 (None, Some(b)) => Some(b),
366 _ => None,
367 },
368 shrink: match (self.shrink, rhs.shrink) {
369 (Some(a), Some(b)) => Some(a + b),
370 (Some(a), None) => Some(a),
371 (None, Some(b)) => Some(b),
372 _ => None,
373 },
374 }
375 }
376}
377impl<I: TeXInt, D: TeXDimen + Numeric<I>> Div<I> for Skip<D> {
378 type Output = Self;
379 fn div(self, rhs: I) -> Self::Output {
380 self.scale(1.into(), rhs)
381 }
382}
383impl<I: TeXInt, D: TeXDimen + Numeric<I>> Mul<I> for Skip<D> {
384 type Output = Self;
385 fn mul(self, rhs: I) -> Self::Output {
386 self.scale(rhs, 1.into())
387 }
388}
389
390impl<D: TeXDimen> Display for Skip<D> {
391 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
392 write!(f, "{}", self.base)?;
393 if let Some(stretch) = &self.stretch {
394 write!(f, " plus ")?;
395 match stretch {
396 StretchShrink::Dim(d) => write!(f, "{}", d)?,
397 StretchShrink::Fil(i) => Dim32::display_num(*i, "fil", f)?,
398 StretchShrink::Fill(i) => Dim32::display_num(*i, "fill", f)?,
399 StretchShrink::Filll(i) => Dim32::display_num(*i, "filll", f)?,
400 }
401 }
402 if let Some(shrink) = &self.shrink {
403 write!(f, " minus ")?;
404 match shrink {
405 StretchShrink::Dim(d) => write!(f, "{}", d)?,
406 StretchShrink::Fil(i) => Dim32::display_num(*i, "fil", f)?,
407 StretchShrink::Fill(i) => Dim32::display_num(*i, "fill", f)?,
408 StretchShrink::Filll(i) => Dim32::display_num(*i, "filll", f)?,
409 }
410 }
411 Ok(())
412 }
413}
414impl<D: TeXDimen> Neg for Skip<D> {
415 type Output = Self;
416 fn neg(self) -> Self::Output {
417 Self {
418 base: -self.base,
419 stretch: self.stretch.map(|s| match s {
420 StretchShrink::Dim(d) => StretchShrink::Dim(-d),
421 StretchShrink::Fil(i) => StretchShrink::Fil(-i),
422 StretchShrink::Fill(i) => StretchShrink::Fill(-i),
423 StretchShrink::Filll(i) => StretchShrink::Filll(-i),
424 }),
425 shrink: self.shrink.map(|s| match s {
426 StretchShrink::Dim(d) => StretchShrink::Dim(-d),
427 StretchShrink::Fil(i) => StretchShrink::Fil(-i),
428 StretchShrink::Fill(i) => StretchShrink::Fill(-i),
429 StretchShrink::Filll(i) => StretchShrink::Filll(-i),
430 }),
431 }
432 }
433}
434impl<D: TeXDimen> Skip<D> {
435 pub fn new(
436 base: D,
437 stretch: Option<StretchShrink<D>>,
438 shrink: Option<StretchShrink<D>>,
439 ) -> Self {
440 Self {
441 base,
442 stretch: match stretch {
443 Some(StretchShrink::Dim(d)) if d == D::default() => None,
444 Some(StretchShrink::Fil(0) | StretchShrink::Fill(0) | StretchShrink::Filll(0)) => {
445 None
446 }
447 _ => stretch,
448 },
449 shrink: match shrink {
450 Some(StretchShrink::Dim(d)) if d == D::default() => None,
451 Some(StretchShrink::Fil(0) | StretchShrink::Fill(0) | StretchShrink::Filll(0)) => {
452 None
453 }
454 _ => shrink,
455 },
456 }
457 }
458}
459
460impl<I: TeXInt, D: TeXDimen + Numeric<I>> Numeric<I> for Skip<D> {
461 fn scale(&self, times: I, div: I) -> Self {
462 Self {
463 base: self.base.scale(times, div),
464 stretch: self.stretch,
465 shrink: self.shrink,
466 }
467 }
468}
469
470pub trait MuDim:
472 Display + Debug + Clone + Copy + Neg<Output = Self> + Add<Output = Self> + PartialEq + Ord + Default
473{
474 const UNITS: &'static [&'static [u8]] = &[b"mu"];
476 fn from_float<ET: EngineTypes>(engine: &EngineReferences<ET>, float: f64, dim: &[u8]) -> Self;
478}
479
480#[derive(Clone, Copy, Eq, PartialEq, Debug)]
482pub struct MuSkip<M: MuDim> {
483 pub base: M,
484 pub stretch: Option<MuStretchShrink<M>>,
485 pub shrink: Option<MuStretchShrink<M>>,
486}
487impl<M: MuDim> MuSkip<M> {
488 pub fn new(
490 base: M,
491 stretch: Option<MuStretchShrink<M>>,
492 shrink: Option<MuStretchShrink<M>>,
493 ) -> Self {
494 Self {
495 base,
496 stretch: match stretch {
497 Some(MuStretchShrink::Mu(d)) if d == M::default() => None,
498 Some(
499 MuStretchShrink::Fil(0) | MuStretchShrink::Fill(0) | MuStretchShrink::Filll(0),
500 ) => None,
501 _ => stretch,
502 },
503 shrink: match shrink {
504 Some(MuStretchShrink::Mu(d)) if d == M::default() => None,
505 Some(
506 MuStretchShrink::Fil(0) | MuStretchShrink::Fill(0) | MuStretchShrink::Filll(0),
507 ) => None,
508 _ => shrink,
509 },
510 }
511 }
512}
513
514#[derive(Clone, Copy, Eq, PartialEq, Debug)]
516pub enum MuStretchShrink<M: MuDim> {
517 Mu(M),
518 Fil(i32),
519 Fill(i32),
520 Filll(i32),
521}
522impl<M: MuDim> MuStretchShrink<M> {
523 pub fn from_float<ET: EngineTypes>(
526 engine: &EngineReferences<ET>,
527 float: f64,
528 dim: &[u8],
529 ) -> Self {
530 match dim {
531 b"fil" => Self::Fil((float * 65536.0).round() as i32),
532 b"fill" => Self::Fill((float * 65536.0).round() as i32),
533 b"filll" => Self::Filll((float * 65536.0).round() as i32),
534 _ => Self::Mu(M::from_float(engine, float, dim)),
535 }
536 }
537}
538impl<M: MuDim> Add<MuStretchShrink<M>> for MuStretchShrink<M> {
539 type Output = Self;
540 fn add(self, rhs: Self) -> Self::Output {
541 match (self, rhs) {
542 (Self::Mu(d1), Self::Mu(d2)) => Self::Mu(d1 + d2),
543 (Self::Fil(i1), Self::Fil(i2)) => Self::Fil(i1 + i2),
544 (Self::Fill(i1), Self::Fill(i2)) => Self::Fill(i1 + i2),
545 (Self::Filll(i1), Self::Filll(i2)) => Self::Filll(i1 + i2),
546 _ => self.max(rhs),
547 }
548 }
549}
550impl<M: MuDim> PartialOrd for MuStretchShrink<M> {
551 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
552 Some(self.cmp(other))
553 }
554}
555impl<M: MuDim> Ord for MuStretchShrink<M> {
556 fn cmp(&self, other: &Self) -> Ordering {
557 match (self, other) {
558 (Self::Mu(d1), Self::Mu(d2)) => d1.cmp(d2),
559 (Self::Fil(i1), Self::Fil(i2)) => i1.cmp(i2),
560 (Self::Fill(i1), Self::Fill(i2)) => i1.cmp(i2),
561 (Self::Filll(i1), Self::Filll(i2)) => i1.cmp(i2),
562 (Self::Filll(_), _) => Ordering::Greater,
563 (_, Self::Filll(_)) => Ordering::Less,
564 (Self::Fill(_), _) => Ordering::Greater,
565 (_, Self::Fill(_)) => Ordering::Less,
566 (Self::Fil(_), _) => Ordering::Greater,
567 (_, Self::Fil(_)) => Ordering::Less,
568 }
569 }
570}
571
572#[derive(Clone, Copy, Eq, PartialEq, Debug, Default, PartialOrd, Ord)]
575pub struct Mu(pub i32);
576impl Numeric<i32> for Mu {
577 fn scale(&self, times: i32, div: i32) -> Self {
578 Self((self.0 as i64 * (times as i64) / (div as i64)) as i32)
579 }
580}
581impl Div<i32> for Mu {
582 type Output = Self;
583 fn div(self, rhs: i32) -> Self::Output {
584 Self(self.0 / rhs)
585 }
586}
587impl Mul<i32> for Mu {
588 type Output = Self;
589 fn mul(self, rhs: i32) -> Self::Output {
590 Self(self.0 * rhs)
591 }
592}
593impl MuDim for Mu {
594 fn from_float<ET: EngineTypes>(_engine: &EngineReferences<ET>, float: f64, dim: &[u8]) -> Self {
595 match dim {
596 b"mu" => Mu((float * 65536.0).round() as i32),
597 _ => unreachable!(),
598 }
599 }
600}
601impl Neg for Mu {
602 type Output = Self;
603 fn neg(self) -> Self::Output {
604 Mu(-self.0)
605 }
606}
607impl Add<Mu> for Mu {
608 type Output = Self;
609 fn add(self, rhs: Self) -> Self::Output {
610 Mu(self.0 + rhs.0)
611 }
612}
613impl Display for Mu {
614 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
615 Dim32::display_num(self.0, "mu", f)
616 }
617}
618
619impl<M: MuDim> PartialOrd for MuSkip<M> {
620 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
621 Some(self.cmp(other))
622 }
623}
624impl<M: MuDim> Ord for MuSkip<M> {
625 fn cmp(&self, other: &Self) -> Ordering {
626 self.base.cmp(&other.base)
627 }
628}
629impl<M: MuDim> Display for MuSkip<M> {
630 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
631 write!(f, "{}", self.base)?;
632 if let Some(stretch) = &self.stretch {
633 write!(f, " plus ")?;
634 match stretch {
635 MuStretchShrink::Mu(d) => write!(f, "{}", d)?,
636 MuStretchShrink::Fil(i) => Dim32::display_num(*i, "fil", f)?,
637 MuStretchShrink::Fill(i) => Dim32::display_num(*i, "fill", f)?,
638 MuStretchShrink::Filll(i) => Dim32::display_num(*i, "filll", f)?,
639 }
640 }
641 if let Some(shrink) = &self.shrink {
642 write!(f, " minus ")?;
643 match shrink {
644 MuStretchShrink::Mu(d) => write!(f, "{}", d)?,
645 MuStretchShrink::Fil(i) => Dim32::display_num(*i, "fil", f)?,
646 MuStretchShrink::Fill(i) => Dim32::display_num(*i, "fill", f)?,
647 MuStretchShrink::Filll(i) => Dim32::display_num(*i, "filll", f)?,
648 }
649 }
650 Ok(())
651 }
652}
653impl<M: MuDim> Neg for MuSkip<M> {
654 type Output = Self;
655 fn neg(self) -> Self::Output {
656 Self {
657 base: -self.base,
658 stretch: self.stretch.map(|s| match s {
659 MuStretchShrink::Mu(d) => MuStretchShrink::Mu(-d),
660 MuStretchShrink::Fil(i) => MuStretchShrink::Fil(-i),
661 MuStretchShrink::Fill(i) => MuStretchShrink::Fill(-i),
662 MuStretchShrink::Filll(i) => MuStretchShrink::Filll(-i),
663 }),
664 shrink: self.shrink.map(|s| match s {
665 MuStretchShrink::Mu(d) => MuStretchShrink::Mu(-d),
666 MuStretchShrink::Fil(i) => MuStretchShrink::Fil(-i),
667 MuStretchShrink::Fill(i) => MuStretchShrink::Fill(-i),
668 MuStretchShrink::Filll(i) => MuStretchShrink::Filll(-i),
669 }),
670 }
671 }
672}
673impl<M: MuDim> Default for MuSkip<M> {
674 fn default() -> Self {
675 Self {
676 base: M::default(),
677 stretch: None,
678 shrink: None,
679 }
680 }
681}
682impl<I: TeXInt, M: MuDim + Numeric<I>> Numeric<I> for MuSkip<M> {
683 fn scale(&self, times: I, div: I) -> Self {
684 Self {
685 base: self.base.scale(times, div),
686 stretch: self.stretch,
687 shrink: self.shrink,
688 }
689 }
690}
691
692impl<M: MuDim> Add<Self> for MuSkip<M> {
693 type Output = Self;
694 fn add(self, rhs: Self) -> Self::Output {
695 Self {
696 base: self.base + rhs.base,
697 stretch: match (self.stretch, rhs.stretch) {
698 (Some(a), Some(b)) => Some(a + b),
699 (Some(a), None) => Some(a),
700 (None, Some(b)) => Some(b),
701 _ => None,
702 },
703 shrink: match (self.shrink, rhs.shrink) {
704 (Some(a), Some(b)) => Some(a + b),
705 (Some(a), None) => Some(a),
706 (None, Some(b)) => Some(b),
707 _ => None,
708 },
709 }
710 }
711}
712impl<I: TeXInt, M: MuDim + Numeric<I>> Div<I> for MuSkip<M> {
713 type Output = Self;
714 fn div(self, rhs: I) -> Self::Output {
715 self.scale(1.into(), rhs)
716 }
717}
718impl<I: TeXInt, M: MuDim + Numeric<I>> Mul<I> for MuSkip<M> {
719 type Output = Self;
720 fn mul(self, rhs: I) -> Self::Output {
721 self.scale(rhs, 1.into())
722 }
723}