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
use crate::errors;
use serde::Serialize;
use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use svg::node::Value;
use svgtypes::Color;

mod matrix;
mod path;
mod view_box;

/** We distinguish between some attribute types, because they have to be handle
*  specidal (tansform).
* But mostly we convert attributes to strings.
 */

#[derive(Serialize, Hash, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum SVGAttValue {
    String(String),
    Matrix(matrix::MatrixValue),
    Path(path::PathValue),
    ViewBox(view_box::ViewBoxValue),
}

impl SVGAttValue {
    pub fn from_prop(prop: &str, value: &Value) -> errors::Result<SVGAttValue> {
        match prop {
            "transform" => {
                // parse the transformation
                Ok(SVGAttValue::Matrix(matrix::MatrixValue::from_string(
                    value,
                )?))
            }
            "viewBox" => Ok(SVGAttValue::ViewBox(view_box::ViewBoxValue::from_string(
                value,
            )?)),
            "d" => Ok(SVGAttValue::Path(path::PathValue::from_string(value)?)),
            "fill" | "stroke" => {
                let color = Color::from_str(value.to_string().as_str())?;
                if color.alpha == 255 {
                    Ok(SVGAttValue::String(format!(
                        "#{:02x}{:02x}{:02x}",
                        color.red, color.green, color.blue
                    )))
                } else {
                    Ok(SVGAttValue::String(format!(
                        "#{:02x}{:02x}{:02x}{:02x}",
                        color.red, color.green, color.blue, color.alpha
                    )))
                }
            }
            _ => Ok(SVGAttValue::String(value.to_string())),
        }
    }

    pub fn hash_with_modifier<H: Hasher>(&self, with_pos: bool, _with_style: bool, hasher: &mut H) {
        match &self {
            SVGAttValue::String(s) => s.hash(hasher),
            SVGAttValue::Matrix(m) => m.hash(hasher),
            SVGAttValue::ViewBox(v) => v.hash(hasher),
            SVGAttValue::Path(p) => p.hash_with_modifier(with_pos, hasher),
        }
    }
}

impl Display for SVGAttValue {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match &self {
            SVGAttValue::String(s) => write!(f, "{}", s),
            SVGAttValue::Matrix(m) => m.fmt(f),
            SVGAttValue::ViewBox(v) => v.fmt(f),
            SVGAttValue::Path(p) => p.fmt(f),
        }
    }
}