Skip to main content

stylex_css_parser/css_types/
flex.rs

1/*!
2CSS Flex type parsing.
3
4Handles flex grid fraction values (e.g., 1fr, 2.5fr).
5*/
6
7use stylex_macros::stylex_unreachable;
8
9use crate::{token_parser::TokenParser, token_types::SimpleToken};
10use std::fmt::{self, Display};
11
12/// CSS flex fraction unit (e.g., 1fr)
13#[derive(Debug, Clone, PartialEq)]
14pub struct Flex {
15  pub fraction: f32,
16}
17
18impl Flex {
19  /// Create a new Flex value
20  pub fn new(fraction: f32) -> Self {
21    Self { fraction }
22  }
23
24  /// Check if a fraction value is valid for flex
25  /// Flex values must be non-negative
26  pub fn is_valid_fraction(fraction: f32) -> bool {
27    fraction >= 0.0
28  }
29
30  /// Parser for flex fraction values
31  pub fn parser() -> TokenParser<Flex> {
32    TokenParser::<SimpleToken>::token(
33      SimpleToken::Dimension {
34        value: 0.0,
35        unit: String::new(),
36      },
37      Some("Dimension"),
38    )
39    .where_fn(
40      |token| {
41        if let SimpleToken::Dimension { value, unit } = token {
42          unit == "fr" && *value >= 0.0
43        } else {
44          false
45        }
46      },
47      Some("valid_fr_unit"),
48    )
49    .map(
50      |token| {
51        if let SimpleToken::Dimension { value, unit: _ } = token {
52          Flex::new(value as f32)
53        } else {
54          stylex_unreachable!()
55        }
56      },
57      Some("to_flex"),
58    )
59  }
60}
61
62impl Display for Flex {
63  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64    write!(f, "{}fr", self.fraction)
65  }
66}
67
68#[cfg(test)]
69mod tests {
70  use super::*;
71
72  #[test]
73  fn test_flex_creation() {
74    let flex = Flex::new(1.0);
75    assert_eq!(flex.fraction, 1.0);
76
77    let flex_half = Flex::new(0.5);
78    assert_eq!(flex_half.fraction, 0.5);
79
80    let flex_zero = Flex::new(0.0);
81    assert_eq!(flex_zero.fraction, 0.0);
82  }
83
84  #[test]
85  fn test_flex_display() {
86    assert_eq!(Flex::new(1.0).to_string(), "1fr");
87    assert_eq!(Flex::new(2.5).to_string(), "2.5fr");
88    assert_eq!(Flex::new(0.0).to_string(), "0fr");
89    assert_eq!(Flex::new(10.0).to_string(), "10fr");
90  }
91
92  #[test]
93  fn test_flex_equality() {
94    let flex1 = Flex::new(1.0);
95    let flex2 = Flex::new(1.0);
96    let flex3 = Flex::new(2.0);
97
98    assert_eq!(flex1, flex2);
99    assert_ne!(flex1, flex3);
100  }
101
102  #[test]
103  fn test_is_valid_fraction() {
104    assert!(Flex::is_valid_fraction(0.0));
105    assert!(Flex::is_valid_fraction(1.0));
106    assert!(Flex::is_valid_fraction(2.5));
107    assert!(Flex::is_valid_fraction(100.0));
108
109    // Negative values should be invalid
110    assert!(!Flex::is_valid_fraction(-1.0));
111    assert!(!Flex::is_valid_fraction(-0.5));
112  }
113
114  #[test]
115  fn test_flex_parser_creation() {
116    // Basic test that parser can be created
117    let _parser = Flex::parser();
118  }
119
120  #[test]
121  fn test_flex_common_values() {
122    // Test common flex fraction values
123    let one_fr = Flex::new(1.0);
124    assert_eq!(one_fr.to_string(), "1fr");
125
126    let two_fr = Flex::new(2.0);
127    assert_eq!(two_fr.to_string(), "2fr");
128
129    let half_fr = Flex::new(0.5);
130    assert_eq!(half_fr.to_string(), "0.5fr");
131  }
132
133  #[test]
134  fn test_flex_precision() {
135    // Test fractional values with precision
136    let precise_flex = Flex::new(1.25);
137    assert_eq!(precise_flex.to_string(), "1.25fr");
138
139    let small_flex = Flex::new(0.1);
140    assert_eq!(small_flex.to_string(), "0.1fr");
141  }
142
143  #[test]
144  fn test_flex_grid_layout_values() {
145    // Test typical grid layout flex values
146    let equal_columns = Flex::new(1.0); // 1fr for equal columns
147    assert_eq!(equal_columns.to_string(), "1fr");
148
149    let larger_column = Flex::new(2.0); // 2fr for larger column
150    assert_eq!(larger_column.to_string(), "2fr");
151
152    let smaller_column = Flex::new(0.5); // 0.5fr for smaller column
153    assert_eq!(smaller_column.to_string(), "0.5fr");
154  }
155
156  #[test]
157  fn test_flex_zero_value() {
158    // Test zero flex value (should be valid)
159    let zero_flex = Flex::new(0.0);
160    assert_eq!(zero_flex.fraction, 0.0);
161    assert_eq!(zero_flex.to_string(), "0fr");
162    assert!(Flex::is_valid_fraction(0.0));
163  }
164
165  #[test]
166  fn test_flex_large_values() {
167    // Test large flex values
168    let large_flex = Flex::new(100.0);
169    assert_eq!(large_flex.to_string(), "100fr");
170
171    let very_large_flex = Flex::new(1000.0);
172    assert_eq!(very_large_flex.to_string(), "1000fr");
173  }
174
175  #[test]
176  fn test_flex_decimal_precision() {
177    // Test various decimal precisions
178    let three_decimals = Flex::new(1.125);
179    assert_eq!(three_decimals.to_string(), "1.125fr");
180
181    let many_decimals = Flex::new(1.234_567_9);
182    // Note: Display might round or truncate, but value should be preserved
183    assert_eq!(many_decimals.fraction, 1.234_567_9);
184  }
185}