Skip to main content

stylex_css_parser/css_types/
resolution.rs

1/*!
2CSS Resolution type parsing.
3
4Handles resolution values with 'dpi' (dots per inch), 'dpcm' (dots per cm), and 'dppx' (dots per px) units.
5*/
6
7use stylex_macros::stylex_unreachable;
8
9use crate::{token_parser::TokenParser, token_types::SimpleToken};
10use std::fmt::{self, Display};
11
12/// Valid resolution units
13pub const RESOLUTION_UNITS: &[&str] = &["dpi", "dpcm", "dppx"];
14
15/// CSS Resolution value with unit
16#[derive(Debug, Clone, PartialEq)]
17pub struct Resolution {
18  pub value: f32,
19  pub unit: String, // "dpi", "dpcm", or "dppx"
20}
21
22impl Resolution {
23  /// Create a new Resolution value
24  pub fn new(value: f32, unit: String) -> Self {
25    Self { value, unit }
26  }
27
28  /// All valid resolution units
29  pub fn units() -> &'static [&'static str] {
30    RESOLUTION_UNITS
31  }
32
33  /// Check if a unit is a valid resolution unit
34  pub fn is_valid_unit(unit: &str) -> bool {
35    RESOLUTION_UNITS.contains(&unit)
36  }
37
38  /// Parser for CSS resolution values
39  pub fn parser() -> TokenParser<Resolution> {
40    TokenParser::<SimpleToken>::token(
41      SimpleToken::Dimension {
42        value: 0.0,
43        unit: String::new(),
44      },
45      Some("Dimension"),
46    )
47    .where_fn(
48      |token| {
49        if let SimpleToken::Dimension { unit, .. } = token {
50          Self::is_valid_unit(unit)
51        } else {
52          false
53        }
54      },
55      Some("valid_resolution_unit"),
56    )
57    .map(
58      |token| {
59        if let SimpleToken::Dimension { value, unit } = token {
60          Resolution::new(value as f32, unit)
61        } else {
62          stylex_unreachable!()
63        }
64      },
65      Some("to_resolution"),
66    )
67  }
68}
69
70impl Display for Resolution {
71  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72    write!(f, "{}{}", self.value, self.unit)
73  }
74}
75
76#[cfg(test)]
77mod tests {
78  use super::*;
79
80  #[test]
81  fn test_resolution_creation() {
82    let res = Resolution::new(96.0, "dpi".to_string());
83    assert_eq!(res.value, 96.0);
84    assert_eq!(res.unit, "dpi");
85  }
86
87  #[test]
88  fn test_resolution_display() {
89    let dpi = Resolution::new(96.0, "dpi".to_string());
90    assert_eq!(dpi.to_string(), "96dpi");
91
92    let dpcm = Resolution::new(38.0, "dpcm".to_string());
93    assert_eq!(dpcm.to_string(), "38dpcm");
94
95    let dppx = Resolution::new(2.0, "dppx".to_string());
96    assert_eq!(dppx.to_string(), "2dppx");
97  }
98
99  #[test]
100  fn test_valid_resolution_units() {
101    assert!(Resolution::is_valid_unit("dpi"));
102    assert!(Resolution::is_valid_unit("dpcm"));
103    assert!(Resolution::is_valid_unit("dppx"));
104
105    // Invalid units
106    assert!(!Resolution::is_valid_unit("px"));
107    assert!(!Resolution::is_valid_unit("s"));
108    assert!(!Resolution::is_valid_unit("Hz"));
109    assert!(!Resolution::is_valid_unit("deg"));
110  }
111
112  #[test]
113  fn test_resolution_units_constant() {
114    let units = Resolution::units();
115    assert_eq!(units.len(), 3);
116    assert!(units.contains(&"dpi"));
117    assert!(units.contains(&"dpcm"));
118    assert!(units.contains(&"dppx"));
119  }
120
121  #[test]
122  fn test_resolution_parser_creation() {
123    // Basic test that parser can be created
124    let _parser = Resolution::parser();
125  }
126}