1#[derive(Clone, Debug)]
3pub struct SelectorState {
4 pub tag: String,
5 pub classes: Option<Vec<String>>,
6 pub id: Option<String>,
7 pub attributes: Option<Vec<String>>,
8}
9
10impl SelectorState {
11 pub fn try_save(&mut self, mode: ParserMode, mut buffer: String) -> String {
13 match mode {
14 ParserMode::None => {
15 if self.tag.is_empty() {
16 self.tag = buffer;
18 buffer = String::new();
19 }
20 }
21 ParserMode::Class => {
22 if self.classes.is_none() {
23 self.classes = Some(vec![buffer]);
25 buffer = String::new();
26 } else if let Some(ref mut classes) = self.classes {
27 classes.push(buffer);
29 buffer = String::new();
30 }
31 }
32 ParserMode::Id => {
33 if self.id.is_none() {
34 self.id = Some(buffer);
36 buffer = String::new();
37 }
38 }
39 ParserMode::Attribute => {
40 if self.attributes.is_none() {
41 self.attributes = Some(vec![buffer]);
43 buffer = String::new();
44 } else if let Some(ref mut attributes) = self.attributes {
45 attributes.push(buffer);
47 buffer = String::new();
48 }
49 }
50 }
51
52 buffer
53 }
54
55 pub fn render(self) -> String {
57 let mut class_string = String::new();
58 let mut id_string = String::new();
59 let mut attributes_string = String::new();
60
61 if let Some(classes) = self.classes {
62 class_string = " class=\"".to_string();
63
64 for class in classes {
65 class_string.push_str(&(class + " "));
66 }
67
68 class_string += "\"";
69 }
70
71 if let Some(id) = self.id {
72 id_string = format!(" id=\"{id}\"");
73 }
74
75 if let Some(attributes) = self.attributes {
76 for attribute in attributes {
77 attributes_string.push_str(&format!(" {attribute}"));
78 }
79 }
80
81 format!("<{}{class_string}{id_string}{attributes_string}>", self.tag)
82 }
83}
84
85#[derive(PartialEq, Eq)]
87pub enum ParserMode {
88 None,
89 Class,
90 Id,
91 Attribute,
92}
93
94pub struct Selector(String);
96
97impl Selector {
98 pub fn new(input: String) -> Self {
100 Self(input)
101 }
102
103 pub fn parse(self) -> SelectorState {
105 let mut state = SelectorState {
106 tag: String::new(),
107 classes: None,
108 id: None,
109 attributes: None,
110 };
111
112 let mut chars = self.0.chars();
114 let mut mode: ParserMode = ParserMode::None;
115 let mut buffer: String = String::new();
116
117 while let Some(char) = chars.next() {
118 match char {
119 '.' => {
120 if mode == ParserMode::Attribute {
121 buffer.push(char);
123 continue;
124 }
125
126 buffer = state.try_save(mode, buffer.clone());
127 mode = ParserMode::Class
128 }
129 '#' => {
130 if mode == ParserMode::Attribute {
131 buffer.push(char);
133 continue;
134 }
135
136 buffer = state.try_save(mode, buffer.clone());
137 mode = ParserMode::Id
138 }
139 '[' => {
140 buffer = state.try_save(mode, buffer.clone());
141 mode = ParserMode::Attribute
142 }
143 ']' => {
144 buffer = state.try_save(mode, buffer.clone());
145 mode = ParserMode::None
146 }
147 _ => buffer.push(char),
148 }
149 }
150
151 state.try_save(mode, buffer.clone()); state
154 }
155}