1use crate::err::Error;
3use crate::{Node, Serde};
4use std::cell::RefCell;
5use std::collections::HashMap;
6use std::rc::{Rc, Weak};
7
8#[derive(Debug)]
10struct Extra<'e> {
11 pub end: bool,
12 pub pos: usize,
13 pub tag: &'e str,
14}
15
16#[derive(Eq, PartialEq)]
18enum ChildrenProcess {
19 BeginTag,
20 CloseTag,
21 None,
22 Plain,
23}
24
25enum TagProcess {
27 Attrs,
28 Quote,
29 None,
30 Tag,
31}
32
33fn rde<'t>(
40 h: &'t str,
41 pre: Option<Weak<RefCell<Node>>>,
42) -> Result<(Rc<RefCell<Node>>, Option<Extra<'t>>), Error> {
43 let mut pos = 0_usize;
44 if h.is_empty() {
45 return Ok((Rc::new(RefCell::new(Node::default())), None));
46 } else if h.find("</").is_none() {
47 return Ok((Rc::new(RefCell::new(self::plain(h, pre))), None));
48 }
49
50 let tree = Rc::new(RefCell::new(Node::default()));
52 let tw = Rc::downgrade(&tree);
53 let (tag, attrs) = self::tag(&h[pos..], &mut pos)?;
54
55 let mut children: Vec<Rc<RefCell<Node>>> = vec![];
57 let mut cext = self::ch(&h[pos..], Some(tw.clone()), tag, &mut children)?;
58
59 pos += cext.pos;
61 while !cext.end {
62 cext = self::ch(&h[pos..], Some(tw.clone()), tag, &mut children)?;
63 pos += cext.pos;
64 }
65
66 let ext = if (pos + 1) != h.len() {
68 Some(Extra {
69 end: false,
70 pos,
71 tag: cext.tag,
72 })
73 } else {
74 None
75 };
76
77 let mut bt = tree.borrow_mut();
78 bt.pre = pre;
79 bt.tag = tag.to_string();
80 bt.attrs = attrs;
81 bt.children = children;
82 drop(bt);
83
84 Ok((tree, ext))
85}
86
87fn ch<'t>(
89 cht: &'t str,
90 pre: Option<Weak<RefCell<Node>>>,
91 tag: &'t str,
92 children: &mut Vec<Rc<RefCell<Node>>>,
93) -> Result<Extra<'t>, Error> {
94 let mut itag = tag;
95 let mut process = ChildrenProcess::None;
96 let (mut t, mut c) = ((0, 0), (0, 0));
97 for (p, q) in cht.chars().enumerate() {
98 match q {
99 '<' => {
100 if process == ChildrenProcess::Plain {
101 c.1 = p;
102 }
103
104 process = ChildrenProcess::BeginTag;
105 t.0 = p;
106 t.1 = p;
107 }
108 '/' => {
109 if &cht[t.0..(t.0 + 1)] == "<" {
110 process = ChildrenProcess::CloseTag;
111 } else if process != ChildrenProcess::Plain {
112 return Err(Error::DeserializeHtmlError(format!(
113 "children parse failed {}, cht: {}, process: {}",
114 &tag,
115 &cht,
116 &cht[t.0..(t.0 + 1)],
117 )));
118 }
119 }
120 '>' => {
121 t.1 = p;
122 match process {
123 ChildrenProcess::BeginTag => {
124 let (tree, ext) = self::rde(&cht[t.0..], pre.clone())?;
125 children.push(tree);
126
127 if let Some(cext) = ext {
129 return Ok(Extra {
130 end: false,
131 tag: cext.tag,
132 pos: cext.pos + t.0,
133 });
134 }
135 }
136 ChildrenProcess::CloseTag => {
137 itag = &cht[(t.0 + 1)..t.1].trim()[1..].trim()[..];
139 if itag != tag {
140 return Err(Error::DeserializeHtmlError(format!(
141 "children parse failed {}, cht: {}, close_tag: {}",
142 &tag, &cht, &itag
143 )));
144 } else if !cht[c.0..c.1].is_empty() {
145 children.push(Rc::new(RefCell::new(self::plain(&cht[c.0..c.1], pre))));
146 }
147
148 return Ok(Extra {
149 end: true,
150 pos: p,
151 tag: itag,
152 });
153 }
154 _ => {
155 }
157 }
158 }
159 x if !x.is_whitespace() => {
160 match process {
161 ChildrenProcess::None => {
162 process = ChildrenProcess::Plain;
163 c.0 = p;
164 c.1 = p;
165 }
166 ChildrenProcess::Plain => {
167 c.1 = p;
168 }
169 _ => {
170 }
172 }
173 }
174 _ => {
175 }
177 }
178 }
179 Ok(Extra {
180 end: true,
181 pos: cht.len(),
182 tag: itag,
183 })
184}
185
186fn plain<'t>(h: &'t str, pre: Option<Weak<RefCell<Node>>>) -> Node {
188 let mut attrs = HashMap::<String, String>::new();
189 attrs.insert("text".into(), h.into());
190
191 Node {
192 pre,
193 tag: "plain".into(),
194 attrs,
195 children: vec![],
196 }
197}
198
199fn tag<'t>(h: &'t str, pos: &mut usize) -> Result<(&'t str, HashMap<String, String>), Error> {
201 let (mut tag, mut key, mut value) = ((0, 0), (0, 0), (0, 0));
202 let mut attrs = HashMap::<String, String>::new();
203 let mut process = TagProcess::None;
204 for (p, q) in h.chars().enumerate() {
205 match q {
206 '<' => {
207 process = TagProcess::Tag;
208 tag.0 = p + 1;
209 tag.1 = p + 1;
210 }
211 '>' => {
212 match process {
213 TagProcess::Tag => tag.1 = p,
214 TagProcess::Attrs => {
215 if !&h[key.0..key.1].trim().is_empty() {
216 attrs.insert(
217 h[key.0..key.1].trim().to_string(),
218 h[value.0..value.1].trim().into(),
219 );
220 }
221 }
222 _ => {}
223 }
224
225 *pos = *pos + p + 1;
226 return Ok((&h[tag.0..tag.1].trim(), attrs));
227 }
228 '"' => match process {
229 TagProcess::Quote => {
230 process = TagProcess::Attrs;
231 value.1 = p;
232 }
233 _ => {
234 value.0 = p + 1;
235 value.1 = p + 1;
236 process = TagProcess::Quote;
237 }
238 },
239 '=' => match process {
240 TagProcess::Attrs => key.1 = p,
241 _ => {
242 return Err(Error::DeserializeHtmlError(format!(
243 "html tag parse failed: {}, html: {}",
244 &h[tag.0..tag.1],
245 &h
246 )))
247 }
248 },
249 x if x.is_whitespace() => match process {
250 TagProcess::Tag => {
251 if h[tag.0..tag.1].trim().is_empty() {
252 tag.1 = p;
253 } else {
254 process = TagProcess::Attrs;
255 key.0 = p + 1;
256 key.1 = p + 1;
257 }
258 }
259 TagProcess::Quote => {
260 value.1 = p;
261 }
262 TagProcess::Attrs => {
263 if (key.1 - key.0 != 0) && (value.1 - value.0 != 0) {
264 attrs.insert(
265 h[key.0..key.1].trim().to_string(),
266 h[value.0..value.1].trim().into(),
267 );
268 key.0 = p;
269 key.1 = p;
270 }
271 }
272 _ => {}
273 },
274 x if !x.is_whitespace() => match process {
275 TagProcess::Tag => {
276 tag.1 = p + 1;
277 }
278 TagProcess::Quote => {
279 value.1 = p;
280 }
281 TagProcess::Attrs => {
282 if value.0 == 0 {
283 key.1 = p;
284 } else {
285 value.1 = p;
286 }
287 }
288 _ => {}
289 },
290 _ => {
291 return Err(Error::DeserializeHtmlError(format!(
292 "html tag parse failed: {}, html: {}, char: {}",
293 &h[tag.0..tag.1],
294 &h,
295 &q
296 )))
297 }
298 }
299 }
300
301 Err(Error::DeserializeHtmlError(format!(
302 "html tag parse failed: {}, html: {}",
303 &h[tag.0..tag.1],
304 &h
305 )))
306}
307
308impl<'t> Serde<Node, String, Error> for Node {
309 fn de(h: String) -> Result<Node, Error> {
310 Ok(self::rde(Box::leak(Box::new(h)), None)?
311 .0
312 .borrow()
313 .to_owned())
314 }
315
316 fn ser(&self) -> String {
317 let mut html = "".to_string();
318 let mut attrs = " ".to_string();
319 let mut children = "".to_string();
320
321 if self.tag == "plain" {
323 html.push_str(&self.attrs.get("text").unwrap_or(&"".into()));
324 } else {
325 for (k, v) in self.attrs.iter() {
326 attrs.push_str(&format!("{}=\"{}\" ", k, v));
327 }
328
329 for i in &self.children {
330 children.push_str(&i.borrow().to_owned().ser());
331 }
332
333 if attrs.trim().is_empty() {
334 attrs.drain(..);
335 }
336
337 html.push_str(&format!(
338 "<{}{}>{}</{}>",
339 &self.tag,
340 attrs.trim_end(),
341 children,
342 &self.tag,
343 ));
344 }
345
346 html
347 }
348}