Topus
相较javascript,rust有更加严谨的语法,编译期能发现bug的优点。既然javascript能写html,是不是用rust写html体验更好。基于此想法,我写了topus。
我的想法是
- 构建一个简单
struct DOM,由上至下有enum Node和enum Attribute。 - 实现
Display trait,通过to_string()转换成字符串 - 创建
html文件,写入字符串
Attribute
为了减少学习难度,所有字符串类型为String,而不是带有生命周期的&str。
enum Attribute有两个attribute变种。
Boolean(String),代表布尔属性,如hidden。Normal { key: String, value: Sting },代表普通属性,如style="display: None"。
创建方式
- 直接创建
let hidden = Boolean;
let style = Normal ;
let http_equiv = Normal ;
- 宏创建
let macro_hidden = attribute!;
let macro_style = attribute!;
let macro_http_equiv = attribute!;
推荐使用宏创建Attribute,方便快捷。
断言
assert_eq!;
assert_eq!;
assert_eq!;
创建Vec<Attribute>
使用attributes宏可以很方便的创建Vec
let attributes = attributes!;
assert_eq!;
细心的应该发现问题了,html和style="display:None" 属性是逆向加入Vec容器的。
Node
enum Node有三个变种。
Element { node_name: String, attributes: Vec<Attribute>, child_nodes: Vec<Node>},代表element node。Text { node_value: String },代表text node。Comment { node_value: String },代表comment node。
创建方式
- 直接创建
let text = Text ;
let comment = Comment ;
let doctype = Element ;
let a = Element ;
- 宏创建
let macro_text = text!;
let macro_comment = comment!;
let macro_doctype = element!;
let macro_a = element!;
断言
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
细心的又发现了,macro_a.to_string() 中的hidden 和style="display: None" 属性顺序是正向了,因为在实现Display trait 过程中,通过attributes.iter().rev()逆转了attributes的显示顺序。
创建Vec<Node>
使用elements宏可以很方便的创建Vec<Node>
let nodes = nodes!;
assert_eq!;
同样的,head和body 节点是逆序的。
使用epxression
在element! 宏调用中我们也可以传入表达式参数。如
let html = element!;
Attribute和Node表达式后面要跟着,,Vec<Attribute>和Vec<Node>表达式后面要跟着;。
生成html文件
通过build!宏,生成html文件。
build!;