stylex_css_parser/css_types/
dimension.rs1use crate::{token_parser::TokenParser, token_types::SimpleToken};
8use std::fmt::{self, Display};
9
10use super::{frequency::Frequency, length::Length, resolution::Resolution, time::Time};
11
12#[derive(Debug, Clone, PartialEq)]
14pub enum Dimension {
15 Length(Length),
16 Time(Time),
17 Frequency(Frequency),
18 Resolution(Resolution),
19}
20
21impl Dimension {
22 #[allow(dead_code)]
24 fn is_valid_dimension_unit(unit: &str) -> bool {
25 Length::is_valid_unit(unit)
26 || Time::is_valid_unit(unit)
27 || Frequency::is_valid_unit(unit)
28 || Resolution::is_valid_unit(unit)
29 }
30
31 fn from_value_and_unit(value: f32, unit: String) -> Option<Dimension> {
33 if Length::is_valid_unit(&unit) {
34 Some(Dimension::Length(Length::new(value, unit)))
35 } else if Time::is_valid_unit(&unit) {
36 Some(Dimension::Time(Time::new(value, unit)))
37 } else if Frequency::is_valid_unit(&unit) {
38 Some(Dimension::Frequency(Frequency::new(value, unit)))
39 } else if Resolution::is_valid_unit(&unit) {
40 Some(Dimension::Resolution(Resolution::new(value, unit)))
41 } else {
42 None
43 }
44 }
45
46 pub fn parse() -> TokenParser<Dimension> {
48 use crate::token_parser::tokens;
49
50 tokens::dimension()
51 .map(
52 |token| {
53 if let SimpleToken::Dimension { value, unit } = token {
54 Self::from_value_and_unit(value as f32, unit)
55 } else {
56 None
57 }
58 },
59 Some("extract_dimension"),
60 )
61 .where_fn(|opt| opt.is_some(), Some("valid_dimension"))
62 .map(|opt| opt.unwrap(), Some("unwrap_dimension"))
63 }
64}
65
66pub fn dimension() -> TokenParser<Dimension> {
67 Dimension::parse()
68}
69
70impl Display for Dimension {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 match self {
73 Dimension::Length(length) => length.fmt(f),
74 Dimension::Time(time) => time.fmt(f),
75 Dimension::Frequency(frequency) => frequency.fmt(f),
76 Dimension::Resolution(resolution) => resolution.fmt(f),
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_dimension_from_value_and_unit() {
87 let length_dim = Dimension::from_value_and_unit(16.0, "px".to_string());
89 assert!(matches!(length_dim, Some(Dimension::Length(_))));
90
91 let time_dim = Dimension::from_value_and_unit(1.5, "s".to_string());
93 assert!(matches!(time_dim, Some(Dimension::Time(_))));
94
95 let freq_dim = Dimension::from_value_and_unit(440.0, "Hz".to_string());
97 assert!(matches!(freq_dim, Some(Dimension::Frequency(_))));
98
99 let res_dim = Dimension::from_value_and_unit(96.0, "dpi".to_string());
101 assert!(matches!(res_dim, Some(Dimension::Resolution(_))));
102
103 let invalid_dim = Dimension::from_value_and_unit(10.0, "invalid".to_string());
105 assert!(invalid_dim.is_none());
106 }
107
108 #[test]
109 fn test_dimension_display() {
110 let length = Dimension::Length(Length::new(16.0, "px".to_string()));
111 assert_eq!(length.to_string(), "16px");
112
113 let time = Dimension::Time(Time::new(1.5, "s".to_string()));
114 assert_eq!(time.to_string(), "1.5s");
115
116 let freq = Dimension::Frequency(Frequency::new(440.0, "Hz".to_string()));
117 assert_eq!(freq.to_string(), "0.44KHz");
118
119 let res = Dimension::Resolution(Resolution::new(96.0, "dpi".to_string()));
120 assert_eq!(res.to_string(), "96dpi");
121 }
122
123 #[test]
124 fn test_is_valid_dimension_unit() {
125 assert!(Dimension::is_valid_dimension_unit("px"));
127 assert!(Dimension::is_valid_dimension_unit("em"));
128 assert!(Dimension::is_valid_dimension_unit("vh"));
129
130 assert!(Dimension::is_valid_dimension_unit("s"));
132 assert!(Dimension::is_valid_dimension_unit("ms"));
133
134 assert!(Dimension::is_valid_dimension_unit("Hz"));
136 assert!(Dimension::is_valid_dimension_unit("KHz"));
137
138 assert!(Dimension::is_valid_dimension_unit("dpi"));
140 assert!(Dimension::is_valid_dimension_unit("dpcm"));
141 assert!(Dimension::is_valid_dimension_unit("dppx"));
142
143 assert!(!Dimension::is_valid_dimension_unit("invalid"));
145 assert!(!Dimension::is_valid_dimension_unit("deg")); }
147
148 #[test]
149 fn test_dimension_parser_creation() {
150 let _parser = Dimension::parse();
152 }
153
154 #[test]
155 fn test_dimension_equality() {
156 let dim1 = Dimension::Length(Length::new(16.0, "px".to_string()));
157 let dim2 = Dimension::Length(Length::new(16.0, "px".to_string()));
158 let dim3 = Dimension::Length(Length::new(20.0, "px".to_string()));
159
160 assert_eq!(dim1, dim2);
161 assert_ne!(dim1, dim3);
162 }
163}