Skip to main content

danceinterpreter_rs/dataloading/
staticinfo.rs

1use iced::Color;
2use serde::{Deserialize, Serialize};
3
4#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
5#[serde(default)]
6pub struct StaticInfo {
7    pub name: String,
8    pub is_favorite: bool,
9    #[serde(with = "color_format", default)]
10    pub color: Option<Color>,
11}
12
13impl StaticInfo {
14    #[allow(dead_code)]
15    pub fn new(name: String) -> Self {
16        StaticInfo {
17            name,
18            is_favorite: false,
19            color: None,
20        }
21    }
22}
23
24mod color_format {
25    use super::*;
26    use serde::{Deserialize, Deserializer, Serializer};
27
28    pub fn serialize<S>(color: &Option<Color>, serializer: S) -> Result<S::Ok, S::Error>
29    where
30        S: Serializer,
31    {
32        match color {
33            Some(c) => {
34                let r = (c.r * 255.0) as u8;
35                let g = (c.g * 255.0) as u8;
36                let b = (c.b * 255.0) as u8;
37                let hex = format!("#{:02X}{:02X}{:02X}", r, g, b);
38                serializer.serialize_some(&hex)
39            }
40            None => serializer.serialize_none(),
41        }
42    }
43
44    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Color>, D::Error>
45    where
46        D: Deserializer<'de>,
47    {
48        let s: Option<String> = Option::deserialize(deserializer)?;
49        match s {
50            Some(hex) => {
51                let hex = hex.trim_start_matches('#');
52                if hex.len() != 6 {
53                    return Ok(None);
54                }
55                let (Ok(r), Ok(g), Ok(b)) = (
56                    u8::from_str_radix(&hex[0..2], 16),
57                    u8::from_str_radix(&hex[2..4], 16),
58                    u8::from_str_radix(&hex[4..6], 16),
59                ) else {
60                    return Ok(None);
61                };
62                Ok(Some(Color::from_rgb8(r, g, b)))
63            }
64            None => Ok(None),
65        }
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_color_serialization() {
75        let static_info = StaticInfo {
76            name: "Waltz".to_string(),
77            is_favorite: true,
78            color: Some(Color::from_rgb8(255, 0, 128)),
79        };
80
81        let json = serde_json::to_string(&static_info).unwrap();
82        assert!(json.contains("\"color\":\"#FF0080\""));
83    }
84
85    #[test]
86    fn test_color_deserialization() {
87        let json = r##"{"name":"Tango","is_favorite":false,"color":"#00FF00"}"##;
88        let static_info: StaticInfo = serde_json::from_str(json).unwrap();
89
90        assert_eq!(static_info.name, "Tango");
91        assert_eq!(static_info.color, Some(Color::from_rgb8(0, 255, 0)));
92    }
93
94    #[test]
95    fn test_color_deserialization_invalid() {
96        let json = r##"{"name":"Tango","is_favorite":false,"color":"invalid"}"##;
97        let static_info: StaticInfo = serde_json::from_str(json).unwrap();
98
99        assert_eq!(static_info.color, None);
100    }
101}