reddit_rs/models/
color.rs1use 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}