layoutcss_parser/
classes.rs

1use std::{collections::HashSet, hash::Hash};
2
3use crate::utilities::align_self::align_self_css;
4use crate::utilities::bg_img::bg_img_css;
5use crate::utilities::flex::*;
6use crate::utilities::font_size::font_size_css;
7use crate::utilities::h::h_css;
8use crate::utilities::hide::*;
9use crate::utilities::line_height::line_height_css;
10use crate::utilities::p::*;
11use crate::utilities::p_child::*;
12use crate::utilities::p_recursive::*;
13use crate::utilities::ratio::ratio_css;
14use crate::utilities::relative::relative_css;
15use crate::utilities::w::w_css;
16use crate::utilities::z_index::z_index_css;
17
18#[derive(Debug, PartialEq, Hash, Eq)]
19pub enum LayoutClass<'a> {
20    // Component Classes
21    MaxWidth(&'a str),
22    MinCellWidth(&'a str),
23    MinCols(&'a str),
24    MaxCols(&'a str),
25    Recursive,
26    Reverse,
27    Screen,
28    TwinWidth,
29    NoWrap,
30    HideBar,
31    AndText,
32    Grow,
33    Gap(&'a str),
34    GapX(&'a str),
35    GapY(&'a str),
36    GapDir(&'a str),
37    Scale(&'a str),
38    Align(&'a str),
39    Position(&'a str),
40    Top(&'a str),
41    Bottom(&'a str),
42    Left(&'a str),
43    Right(&'a str),
44    Height(&'a str),
45    ItemWidth(&'a str),
46    MinHeight(&'a str),
47    MaxHeight(&'a str),
48    SideWidth(&'a str),
49    Side(&'a str),
50    ContentMin(&'a str),
51    Threshold(&'a str),
52    Limit(&'a str),
53    KeepP,
54    KeepPL,
55    KeepPR,
56    KeepCenter,
57    Shrink,
58    Template(&'a str),
59    Col(&'a str),
60    Row(&'a str),
61
62    // Utility Classes
63    AlignSelf(&'a str),
64    BgImg(&'a str),
65    FlexBasis(&'a str),
66    FlexGrow(&'a str),
67    FlexShrink(&'a str),
68    FontSize(&'a str),
69    H(&'a str),
70    HideOver(&'a str),
71    HideUnder(&'a str),
72    LineHeight(&'a str),
73    Justify(&'a str),
74    P(&'a str),
75    PT(&'a str),
76    PB(&'a str),
77    PL(&'a str),
78    PR(&'a str),
79    PX(&'a str),
80    PY(&'a str),
81    PChild(&'a str),
82    PTChild(&'a str),
83    PBChild(&'a str),
84    PLChild(&'a str),
85    PRChild(&'a str),
86    PXChild(&'a str),
87    PYChild(&'a str),
88    PRecursive(&'a str),
89    PTRecursive(&'a str),
90    PBRecursive(&'a str),
91    PLRecursive(&'a str),
92    PRRecursive(&'a str),
93    PXRecursive(&'a str),
94    PYRecursive(&'a str),
95    Ratio(&'a str),
96    Relative,
97    W(&'a str),
98    ZIndex(&'a str),
99}
100
101impl<'a> TryFrom<&'a str> for LayoutClass<'a> {
102    type Error = ();
103
104    fn try_from(input: &'a str) -> Result<LayoutClass<'a>, Self::Error> {
105        let colon_index = input.find(':');
106        let (class_name, class_value) = if let Some(i) = colon_index {
107            //In the case where their is ':' but nothing after
108            // this syntax is wrong so we return an error
109            if input.len() <= i + 1 {
110                return Err(());
111            }
112            (Some(&input[..i]), Some(&input[i + 1..]))
113        } else {
114            (Some(&input[..]), None)
115        };
116        match (class_name, class_value) {
117            // all layout classes with value
118            (Some(class), Some(value)) => match class {
119                "max-width" => Ok(LayoutClass::MaxWidth(value)),
120                "min-cell-width" => Ok(LayoutClass::MinCellWidth(value)),
121                "min-cols" => Ok(LayoutClass::MinCols(value)),
122                "max-cols" => Ok(LayoutClass::MaxCols(value)),
123                "gap" => Ok(LayoutClass::Gap(value)),
124                "gap-x" => Ok(LayoutClass::GapX(value)),
125                "gap-y" => Ok(LayoutClass::GapY(value)),
126                "gap-dir" => Ok(LayoutClass::GapDir(value)),
127                "scale" => Ok(LayoutClass::Scale(value)),
128                "align" => Ok(LayoutClass::Align(value)),
129                "position" => Ok(LayoutClass::Position(value)),
130                "top" => Ok(LayoutClass::Top(value)),
131                "bottom" => Ok(LayoutClass::Bottom(value)),
132                "left" => Ok(LayoutClass::Left(value)),
133                "right" => Ok(LayoutClass::Right(value)),
134                "height" => Ok(LayoutClass::Height(value)),
135                "item-width" => Ok(LayoutClass::ItemWidth(value)),
136                "min-height" => Ok(LayoutClass::MinHeight(value)),
137                "max-height" => Ok(LayoutClass::MaxHeight(value)),
138                "side" => Ok(LayoutClass::Side(value)),
139                "side-width" => Ok(LayoutClass::SideWidth(value)),
140                "content-min" => Ok(LayoutClass::ContentMin(value)),
141                "threshold" => Ok(LayoutClass::Threshold(value)),
142                "template" => Ok(LayoutClass::Template(value)),
143                "limit" => Ok(LayoutClass::Limit(value)),
144
145                "align-self" => Ok(LayoutClass::AlignSelf(value)),
146                "bg-img" => Ok(LayoutClass::BgImg(value)),
147                "flex-basis" => Ok(LayoutClass::FlexBasis(value)),
148                "flex-grow" => Ok(LayoutClass::FlexGrow(value)),
149                "flex-shrink" => Ok(LayoutClass::FlexShrink(value)),
150                "font-size" => Ok(LayoutClass::FontSize(value)),
151                "h" => Ok(LayoutClass::H(value)),
152                "hide-over" => Ok(LayoutClass::HideOver(value)),
153                "hide-under" => Ok(LayoutClass::HideUnder(value)),
154                "line-height" => Ok(LayoutClass::LineHeight(value)),
155                "p" => Ok(LayoutClass::P(value)),
156                "pt" => Ok(LayoutClass::PT(value)),
157                "pb" => Ok(LayoutClass::PB(value)),
158                "pl" => Ok(LayoutClass::PL(value)),
159                "pr" => Ok(LayoutClass::PR(value)),
160                "px" => Ok(LayoutClass::PX(value)),
161                "py" => Ok(LayoutClass::PY(value)),
162                "p-child" => Ok(LayoutClass::PChild(value)),
163                "pt-child" => Ok(LayoutClass::PTChild(value)),
164                "pb-child" => Ok(LayoutClass::PBChild(value)),
165                "pl-child" => Ok(LayoutClass::PLChild(value)),
166                "pr-child" => Ok(LayoutClass::PRChild(value)),
167                "px-child" => Ok(LayoutClass::PXChild(value)),
168                "py-child" => Ok(LayoutClass::PYChild(value)),
169                "p-recursive" => Ok(LayoutClass::PRecursive(value)),
170                "pt-recursive" => Ok(LayoutClass::PTRecursive(value)),
171                "pb-recursive" => Ok(LayoutClass::PBRecursive(value)),
172                "pl-recursive" => Ok(LayoutClass::PLRecursive(value)),
173                "pr-recursive" => Ok(LayoutClass::PRRecursive(value)),
174                "px-recursive" => Ok(LayoutClass::PXRecursive(value)),
175                "py-recursive" => Ok(LayoutClass::PYRecursive(value)),
176
177                "justify" => Ok(LayoutClass::Justify(value)),
178
179                "ratio" => Ok(LayoutClass::Ratio(value)),
180                "w" => Ok(LayoutClass::W(value)),
181                "z-index" => Ok(LayoutClass::ZIndex(value)),
182
183                //TODO check if its not row instead of rows
184                //if its the case rename Rows Row (same thing for Cols to Col)
185                c if c.starts_with("row-") => Ok(LayoutClass::Row(input)),
186                c if c.starts_with("col-") => Ok(LayoutClass::Col(input)),
187
188                _ => Err(()),
189            },
190            // all layout class without value
191            (Some(class), None) => match class {
192                "recursive" => Ok(LayoutClass::Recursive),
193                "reverse" => Ok(LayoutClass::Reverse),
194                "screen" => Ok(LayoutClass::Screen),
195                "twin-width" => Ok(LayoutClass::TwinWidth),
196                "nowrap" => Ok(LayoutClass::NoWrap),
197                "hide-bar" => Ok(LayoutClass::HideBar),
198                "relative" => Ok(LayoutClass::Relative),
199                "grow" => Ok(LayoutClass::Grow),
200                "keep-p" => Ok(LayoutClass::KeepP),
201                "keep-pl" => Ok(LayoutClass::KeepPL),
202                "keep-pr" => Ok(LayoutClass::KeepPR),
203                "keep-center" => Ok(LayoutClass::KeepCenter),
204                "shrink" => Ok(LayoutClass::Shrink),
205                "and-text" => Ok(LayoutClass::AndText),
206                _ => Err(()),
207            },
208            _ => Err(()),
209        }
210    }
211}
212
213impl<'a> LayoutClass<'a> {
214    /// Generate the css of the layout class which are utilities
215    /// and insert it inside the Hashset passed.
216    /// This method consumes the LayoutClass, because we dont need it anymore
217    /// after we get the css.
218    pub fn insert_css(self, harmonic_ratio: f64, set: &mut HashSet<String>) {
219        match self {
220            Self::AlignSelf(value) => align_self_css(value, set),
221            Self::BgImg(value) => bg_img_css(value, set),
222            Self::FlexBasis(value) => flex_basis_css(value, set),
223            Self::FlexGrow(value) => flex_grow_css(value, set),
224            Self::FlexShrink(value) => flex_shrink_css(value, set),
225            Self::FontSize(value) => font_size_css(value, harmonic_ratio, set),
226            Self::H(value) => h_css(value, harmonic_ratio, set),
227            Self::HideOver(value) => hide_over_css(value, set),
228            Self::HideUnder(value) => hide_under_css(value, set),
229            Self::LineHeight(value) => line_height_css(value, set),
230            Self::P(value) => p_css(value, harmonic_ratio, set),
231            Self::PT(value) => pt_css(value, harmonic_ratio, set),
232            Self::PB(value) => pb_css(value, harmonic_ratio, set),
233            Self::PL(value) => pl_css(value, harmonic_ratio, set),
234            Self::PR(value) => pr_css(value, harmonic_ratio, set),
235            Self::PX(value) => px_css(value, harmonic_ratio, set),
236            Self::PY(value) => py_css(value, harmonic_ratio, set),
237            Self::PChild(value) => p_child_css(value, harmonic_ratio, set),
238            Self::PTChild(value) => pt_child_css(value, harmonic_ratio, set),
239            Self::PBChild(value) => pb_child_css(value, harmonic_ratio, set),
240            Self::PLChild(value) => pl_child_css(value, harmonic_ratio, set),
241            Self::PRChild(value) => pr_child_css(value, harmonic_ratio, set),
242            Self::PXChild(value) => px_child_css(value, harmonic_ratio, set),
243            Self::PYChild(value) => py_child_css(value, harmonic_ratio, set),
244            Self::PRecursive(value) => p_recursive_css(value, harmonic_ratio, set),
245            Self::PTRecursive(value) => pt_recursive_css(value, harmonic_ratio, set),
246            Self::PBRecursive(value) => pb_recursive_css(value, harmonic_ratio, set),
247            Self::PLRecursive(value) => pl_recursive_css(value, harmonic_ratio, set),
248            Self::PRRecursive(value) => pr_recursive_css(value, harmonic_ratio, set),
249            Self::PXRecursive(value) => px_recursive_css(value, harmonic_ratio, set),
250            Self::PYRecursive(value) => py_recursive_css(value, harmonic_ratio, set),
251            Self::Ratio(value) => ratio_css(value, set),
252            Self::Relative => relative_css(set),
253            Self::W(value) => w_css(value, harmonic_ratio, set),
254            Self::ZIndex(value) => z_index_css(value, set),
255            _ => {}
256        }
257    }
258}
259
260#[cfg(test)]
261mod tests {
262    use super::*;
263
264    #[test]
265    fn create_layout_class_for_rows_area() {
266        let layout_class = "col-3:440px";
267        let cols_variant = LayoutClass::try_from(layout_class);
268        //assert_eq!(cols_variant, LayoutClass::Cols("cols-"));
269        assert_eq!(cols_variant, Ok(LayoutClass::Col("col-3:440px")));
270    }
271
272    #[test]
273    fn create_layout_class_when_value_expected_but_no_set_with_colon() {
274        let layout_class = "max-width:";
275        let max_width_variant = LayoutClass::try_from(layout_class);
276        assert_eq!(max_width_variant, Err(()));
277    }
278
279    #[test]
280    fn create_layout_class_when_value_expected_but_no_set_without_colon() {
281        let layout_class = "max-width";
282        let max_width_variant = LayoutClass::try_from(layout_class);
283        assert_eq!(max_width_variant, Err(()));
284    }
285
286    #[test]
287    fn create_layout_class_from_text() {
288        let layout_class = "max-width:440px";
289        let max_width_variant = LayoutClass::try_from(layout_class);
290        assert_eq!(max_width_variant, Ok(LayoutClass::MaxWidth("440px")));
291    }
292}