Skip to main content

stylex_css_parser/css_types/
frequency.rs

1/*!
2CSS Frequency type parsing.
3
4Handles frequency values with 'Hz' (hertz) and 'KHz' (kilohertz) units.
5*/
6
7use crate::{token_parser::TokenParser, token_types::SimpleToken};
8use std::fmt::{self, Display};
9
10/// Valid frequency units
11pub const FREQUENCY_UNITS: &[&str] = &["Hz", "KHz"];
12
13/// CSS Frequency value with unit
14#[derive(Debug, Clone, PartialEq)]
15pub struct Frequency {
16  pub value: f32,
17  pub unit: String, // "Hz" or "KHz"
18}
19
20impl Frequency {
21  /// Create a new Frequency value
22  pub fn new(value: f32, unit: String) -> Self {
23    Self { value, unit }
24  }
25
26  /// All valid frequency units
27  pub fn units() -> &'static [&'static str] {
28    FREQUENCY_UNITS
29  }
30
31  /// Check if a unit is a valid frequency unit
32  pub fn is_valid_unit(unit: &str) -> bool {
33    FREQUENCY_UNITS.contains(&unit)
34  }
35
36  /// Parser for CSS frequency values
37  pub fn parser() -> TokenParser<Frequency> {
38    TokenParser::<SimpleToken>::token(
39      SimpleToken::Dimension {
40        value: 0.0,
41        unit: String::new(),
42      },
43      Some("Dimension"),
44    )
45    .map(
46      |token| {
47        if let SimpleToken::Dimension { value, unit } = token {
48          if Self::is_valid_unit(&unit) {
49            Some((value as f32, unit))
50          } else {
51            None
52          }
53        } else {
54          None
55        }
56      },
57      Some("extract_frequency_dimension"),
58    )
59    .where_fn(|opt| opt.is_some(), Some("valid_frequency"))
60    .map(
61      |opt| {
62        let (value, unit) = opt.unwrap();
63        Frequency::new(value, unit)
64      },
65      Some("to_frequency"),
66    )
67  }
68}
69
70impl Display for Frequency {
71  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72    if self.unit == "Hz" {
73      write!(f, "{}KHz", self.value / 1000.0)
74    } else {
75      write!(f, "{}{}", self.value, self.unit)
76    }
77  }
78}
79
80#[cfg(test)]
81mod tests {
82  use super::*;
83
84  #[test]
85  fn test_frequency_creation() {
86    let freq = Frequency::new(440.0, "Hz".to_string());
87    assert_eq!(freq.value, 440.0);
88    assert_eq!(freq.unit, "Hz");
89  }
90
91  #[test]
92  fn test_frequency_display() {
93    let hertz = Frequency::new(440.0, "Hz".to_string());
94    assert_eq!(hertz.to_string(), "0.44KHz");
95
96    let kilohertz = Frequency::new(2.4, "KHz".to_string());
97    assert_eq!(kilohertz.to_string(), "2.4KHz");
98
99    let full_kilohertz = Frequency::new(1000.0, "Hz".to_string());
100    assert_eq!(full_kilohertz.to_string(), "1KHz");
101
102    let two_kilohertz = Frequency::new(2000.0, "Hz".to_string());
103    assert_eq!(two_kilohertz.to_string(), "2KHz");
104
105    let partial = Frequency::new(1500.0, "Hz".to_string());
106    assert_eq!(partial.to_string(), "1.5KHz");
107  }
108
109  #[test]
110  fn test_valid_frequency_units() {
111    assert!(Frequency::is_valid_unit("Hz"));
112    assert!(Frequency::is_valid_unit("KHz"));
113
114    // Invalid units
115    assert!(!Frequency::is_valid_unit("px"));
116    assert!(!Frequency::is_valid_unit("s"));
117    assert!(!Frequency::is_valid_unit("deg"));
118  }
119
120  #[test]
121  fn test_frequency_units_constant() {
122    let units = Frequency::units();
123    assert_eq!(units.len(), 2);
124    assert!(units.contains(&"Hz"));
125    assert!(units.contains(&"KHz"));
126  }
127
128  #[test]
129  fn test_frequency_parser_creation() {
130    // Basic test that parser can be created
131    let _parser = Frequency::parser();
132  }
133}