1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::{Colors, Error, Image, ImageSrc, Serde, Text, TextStyle, Tree, Unit};

impl Serde<Image, String> for Image {
    fn de(s: String) -> Result<Image, Error> {
        let t = Tree::de(s)?;
        if t.children.len() != 1 {
            return Err(Error::DeserializeHtmlError(
                "deserialize Text failed, children's length should be 1".into(),
            ));
        }

        let child: Tree = match t.children.len() > 0 {
            true => t.children[0].borrow().to_owned(),
            false => Tree::default(),
        };

        Ok(Image::new(
            t.attrs.get("src").unwrap_or(&"".into()).to_string(),
            child,
        ))
    }

    fn ser(&self) -> String {
        let t: Tree = self.into();
        t.ser()
    }
}

impl Serde<ImageSrc, String> for ImageSrc {
    fn de(s: String) -> Result<ImageSrc, Error> {
        Ok(ImageSrc(s))
    }

    fn ser(&self) -> String {
        format!("background-image: url({})", self.0)
    }
}

impl Serde<Text, String> for Text {
    fn de(s: String) -> Result<Text, Error> {
        let t = Tree::de(s)?;
        if t.children.len() != 1 {
            return Err(Error::DeserializeHtmlError(
                "deserialize Text failed, children's length should be 1".into(),
            ));
        }

        let text = t.children[0].borrow();
        Ok(Text::new(
            text.attrs
                .get("text")
                .unwrap_or(&"".to_string())
                .to_string(),
            TextStyle::de(t.attrs.get("style").unwrap_or(&"".into()).to_string())?.into(),
        ))
    }

    fn ser(&self) -> String {
        let t: Tree = self.into();
        t.ser()
    }
}

impl Serde<TextStyle, String> for TextStyle {
    fn de(s: String) -> Result<TextStyle, Error> {
        let mut ts = TextStyle::default();
        s.split(";").collect::<Vec<&str>>().iter().for_each(|x| {
            if x.len() < 1 {
                return;
            }

            let v = x[(x.find(":").unwrap_or(0) + 1)..].trim();
            match x {
                k if k.contains("color") => {
                    ts.color = Colors::de(v.into()).unwrap_or(Colors::Black)
                }
                k if k.contains("font-weight") => {
                    ts.weight = Unit::de(v.into()).unwrap_or(Unit::None(400.0));
                    ts.bold = match ts.weight {
                        Unit::None(x) => x == 700.0,
                        _ => false,
                    }
                }
                k if k.contains("font-style") => {
                    ts.italic = match v {
                        "italic" => true,
                        _ => false,
                    };
                }
                k if k.contains("font-size") => {
                    ts.size = Unit::de(v.into()).unwrap_or(Unit::Rem(1.0))
                }
                k if k.contains("height") => {
                    ts.height = Unit::de(v.into()).unwrap_or(Unit::Rem(1.0))
                }
                k if k.contains("font-stretch") => {
                    ts.stretch = Unit::de(v.into()).unwrap_or(Unit::Percent(100.0))
                }
                _ => {}
            }
        });

        Ok(ts)
    }

    fn ser(&self) -> String {
        format!(
            "color: {}; font-weight: {}; font-style: {}; font-size: {}; font-stretch: {}; line-height: {};",
            self.color.ser(), match self.bold {
                true => "700".into(),
                false => self.weight.ser(),
            },
            match self.italic {
                true => "italic",
                false => "normal"
            },
            self.size.ser(),
            self.stretch.ser(),
            self.height.ser(),
        )
    }
}