builder_rust/library/scheme/
mod.rs1pub mod color;
19
20use serde::{Deserialize, Deserializer};
21use std::collections::HashMap;
22use unicode_normalization::UnicodeNormalization;
23
24use crate::library::constants::{REQUIRED_BASE16_PALETTE_KEYS, REQUIRED_BASE24_PALETTE_KEYS};
25use crate::library::scheme::color::Color;
26
27#[derive(Deserialize)]
28pub struct SchemeWrapper {
29 pub system: String,
30 pub name: String,
31 pub author: String,
32 pub description: Option<String>,
33 pub variant: Option<String>,
34 pub palette: HashMap<String, String>,
35}
36
37#[derive(Debug)]
38pub struct Scheme {
39 pub system: String,
40 pub name: String,
41 pub slug: String,
42 pub author: String,
43 pub description: Option<String>,
44 pub variant: String,
45 pub palette: HashMap<String, Color>,
46}
47
48fn slugify(input: &str) -> String {
49 input
50 .nfd() .filter(char::is_ascii) .collect::<String>()
53 .to_lowercase()
54 .replace(' ', "-")
55 .chars()
56 .filter(|c| c.is_alphanumeric() || *c == '-') .collect()
58}
59
60impl<'de> Deserialize<'de> for Scheme {
61 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
62 where
63 D: Deserializer<'de>,
64 {
65 let wrapper = SchemeWrapper::deserialize(deserializer)?;
66 let slug = slugify(&wrapper.name);
67 let variant = wrapper.variant.unwrap_or(String::from("dark"));
68
69 match wrapper.system.as_str() {
70 "base16" => {
71 let contains_all_keys = REQUIRED_BASE16_PALETTE_KEYS
72 .iter()
73 .all(|&key| wrapper.palette.contains_key(key));
74
75 if !contains_all_keys {
76 return Err(serde::de::Error::custom(format!(
77 "{} scheme does not contain the required palette properties",
78 wrapper.system
79 )));
80 }
81 }
82 "base24" => {
83 let contains_all_keys = REQUIRED_BASE24_PALETTE_KEYS
84 .iter()
85 .all(|&key| wrapper.palette.contains_key(key));
86
87 if !contains_all_keys {
88 return Err(serde::de::Error::custom(format!(
89 "{} scheme does not contain the required palette properties",
90 wrapper.system
91 )));
92 }
93 }
94 _ => {
95 return Err(serde::de::Error::custom(format!(
96 "Unknown system: {}",
97 wrapper.system
98 )))
99 }
100 }
101
102 let palette_result: Result<HashMap<String, Color>, _> = wrapper
103 .palette
104 .into_iter()
105 .map(|(key, value)| {
106 Color::new(value)
107 .map(|color| (key, color))
108 .map_err(|e| serde::de::Error::custom(e.to_string()))
109 })
110 .collect();
111
112 Ok(Scheme {
113 name: wrapper.name,
114 slug,
115 system: wrapper.system,
116 author: wrapper.author,
117 description: wrapper.description,
118 variant,
119 palette: palette_result?,
120 })
121 }
122}