Skip to main content

latexml_core/common/
pair.rs

1use std::fmt;
2
3use crate::{
4  Digested,
5  common::{error::Result, float::Float, numeric_ops::NumericOps, object::Object},
6  token::{Catcode, Token},
7  tokens::Tokens,
8};
9
10/// A pair of numerical values, typically (x,y) coordinates.
11/// Perl: LaTeXML::Core::Pair
12#[derive(Debug, Clone, PartialEq)]
13pub struct Pair {
14  pub x: Float,
15  pub y: Float,
16}
17
18impl Default for Pair {
19  fn default() -> Self { Pair { x: Float(0.0), y: Float(0.0) } }
20}
21
22impl Pair {
23  pub fn new(x: Float, y: Float) -> Self { Pair { x, y } }
24
25  pub fn get_x(&self) -> Float { self.x }
26  pub fn get_y(&self) -> Float { self.y }
27
28  pub fn to_attribute(&self) -> String {
29    format!("{},{}", self.x.to_attribute(), self.y.to_attribute())
30  }
31}
32
33impl Object for Pair {
34  fn revert(&self) -> Result<Tokens> {
35    let mut toks: Vec<Token> = vec![Token::new("(", Catcode::OTHER)];
36    toks.extend(ExplodeText!(&self.x.to_string()));
37    toks.push(Token::new(",", Catcode::OTHER));
38    toks.extend(ExplodeText!(&self.y.to_string()));
39    toks.push(Token::new(")", Catcode::OTHER));
40    Ok(Tokens::new(toks))
41  }
42
43  fn be_digested(self) -> Result<Digested> {
44    // Preserve pair values through digestion via RegisterValue::Pair
45    Ok(Digested::from(crate::RegisterValue::Pair(self)))
46  }
47}
48
49impl fmt::Display for Pair {
50  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({},{})", self.x, self.y) }
51}
52
53#[cfg(test)]
54mod tests {
55  use super::*;
56
57  #[test]
58  fn pair_new_and_getters() {
59    let p = Pair::new(Float(1.5), Float(-2.5));
60    assert_eq!(p.get_x().0, 1.5);
61    assert_eq!(p.get_y().0, -2.5);
62  }
63
64  #[test]
65  fn pair_default_is_origin() {
66    let p = Pair::default();
67    assert_eq!(p.get_x().0, 0.0);
68    assert_eq!(p.get_y().0, 0.0);
69  }
70
71  #[test]
72  fn pair_display_format() {
73    let p = Pair::new(Float(1.0), Float(2.0));
74    assert_eq!(format!("{p}"), "(1.0,2.0)");
75  }
76
77  #[test]
78  fn pair_display_negative() {
79    let p = Pair::new(Float(-1.5), Float(-2.5));
80    assert_eq!(format!("{p}"), "(-1.5,-2.5)");
81  }
82
83  #[test]
84  fn pair_to_attribute_uses_float_attribute_format() {
85    // to_attribute delegates to Float::to_attribute for each axis.
86    // Float's NumericOps::to_attribute default is to_string(), so
87    // output matches Display.
88    let p = Pair::new(Float(3.0), Float(4.0));
89    assert_eq!(p.to_attribute(), "3.0,4.0");
90  }
91
92  #[test]
93  fn pair_equality() {
94    let a = Pair::new(Float(1.0), Float(2.0));
95    let b = Pair::new(Float(1.0), Float(2.0));
96    let c = Pair::new(Float(1.0), Float(3.0));
97    assert_eq!(a, b);
98    assert_ne!(a, c);
99  }
100}