# Topus 相较`javascript`,`rust`有更加严谨的语法,编译期能发现bug的优点。既然`javascript`能写`html`,是不是用`rust`写`html`体验更好。基于此想法,我写了`topus`。 我的想法是 1. 构建一个简单`struct DOM`,由上至下有`enum Node`和`enum Attribute`。 2. 实现`Display trait`,通过`to_string()`转换成字符串 3. 创建`html`文件,写入字符串 ## Attribute 为了减少学习难度,所有字符串类型为`String`,而不是带有生命周期的`&str`。 `enum Attribute`有两个`attribute`变种。 1. `Boolean(String)`,代表布尔属性,如`hidden`。 2. `Normal { key: String, value: Sting }`,代表普通属性,如`style="display: None"`。 ### 创建方式 1. 直接创建 ``` rust let hidden = Attribute::Boolean("hidden".to_string()); let style = Attribute::Normal { key: "style".to_string(), value: "display: None".to_string() }; let http_equiv = Attribute::Normal { key: "http-equiv".to_string(), value: "X-UA-Compatible".to_string() }; ``` 2. 宏创建 ``` rust let macro_hidden = attribute!(hidden); let macro_style = attribute!(style="display: None"); let macro_http_equiv = attribute!(http-equiv="X-UA-Compatible"); ``` 推荐使用宏创建`Attribute`,方便快捷。 ### 断言 ``` rust assert_eq!(hidden, macro_hidden); assert_eq!(style, macro_style); assert_eq!(http_equiv, macro_http_equiv); ``` ### 创建`Vec` 使用attributes宏可以很方便的创建Vec ``` rust let attributes = attributes!(html style="display:None"); assert_eq!( vec![ Attribute::Normal{ key: "style".to_string(), value: "display:None".to_string() }, Attribute::Boolean("html".to_string())], attributes); ``` 细心的应该发现问题了,`html`和`style="display:None"` 属性是逆向加入`Vec`容器的。 ## Node `enum Node`有三个变种。 1. ` Element { node_name: String, attributes: Vec, child_nodes: Vec}`,代表`element node`。 2. `Text { node_value: String }`,代表`text node`。 3. `Comment { node_value: String }`,代表`comment node`。 ### 创建方式 1. 直接创建 ``` rust let text = Node::Text { node_value: "hello world".to_string() }; let comment = Node::Comment { node_value: "comment".to_string()}; let doctype = Node::Element { node_name: "!DOCTYPE".to_string(), attributes: attributes!(html), child_nodes: Vec::::with_capacity(0) }; let a = Node::Element { node_name: "a".to_string(), attributes: attributes!(hidden style="display:None"), child_nodes: Vec::::with_capacity(0) }; ``` 2. 宏创建 ``` rust let macro_text = text!("hello world"); let macro_comment = comment!("comment"); let macro_doctype = element!(!DOCTYPE html); let macro_a = element!(a hidden style="display:None"); ``` ### 断言 ``` rust assert_eq!(text, macro_text); assert_eq!(comment, macro_comment); assert_eq!(doctype, macro_doctype); assert_eq!(a, macro_a); assert_eq!("