reddit_rs/models/
color.rs

1use std::ops::Range;
2
3use serde::{de::Unexpected, Deserialize, Deserializer, Serialize};
4
5#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
6pub enum Color {
7    Transparent,
8    Rgb { r: u8, g: u8, b: u8 },
9}
10
11impl Color {
12    pub(crate) fn from_hex_str<'de, D>(deserializer: D) -> Result<Option<Self>, D::Error>
13    where
14        D: Deserializer<'de>,
15    {
16        fn get_rgb_value<'de, D: Deserializer<'de>>(
17            hex: &str,
18            range: Range<usize>,
19        ) -> Result<u8, <D as Deserializer<'de>>::Error> {
20            use serde::de::Error;
21
22            let value = if let Some(value) = hex
23                .get(range)
24                .and_then(|val| u8::from_str_radix(val, 16).ok())
25            {
26                value
27            } else {
28                return Err(D::Error::invalid_value(
29                    Unexpected::Other("non-hex string"),
30                    &"hex string of format #RRGGBB",
31                ));
32            };
33            Ok(value)
34        }
35
36        let hex = match Option::<String>::deserialize(deserializer) {
37            Ok(Some(s)) if s == "transparent" => return Ok(Some(Self::Transparent)),
38            Ok(Some(hex)) => hex,
39            Ok(None) => return Ok(None),
40            Err(why) => return Err(why),
41        };
42
43        if hex.is_empty() {
44            return Ok(None);
45        }
46
47        Ok(Some(Self::Rgb {
48            r: get_rgb_value::<D>(&hex, 1..3)?,
49            g: get_rgb_value::<D>(&hex, 3..5)?,
50            b: get_rgb_value::<D>(&hex, 5..7)?,
51        }))
52    }
53}