Skip to main content

logo_parser/
config.rs

1// SPDX-FileCopyrightText: 2023 CELESTIFYX Team
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4use std::collections::HashMap;
5
6use serde::{
7    Deserialize,
8    Serialize
9};
10
11use chromakitx::AnyColor;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub(super) struct LogoEntry {
15    #[serde(rename = "type")]
16    pub(super) logo_type: String,
17    pub(super) ascii: Vec<String>
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21#[serde(untagged)]
22pub(super) enum ColorValue {
23    Reference(String),
24    Array(Vec<ColorDef>)
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28#[serde(untagged)]
29pub(super) enum ColorDef {
30    Simple(String),
31    Named(HashMap<String, String>)
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub(super) struct LogoConfig {
36    pub(super) logos: Vec<LogoEntry>,
37    pub(super) colors: Vec<ColorValue>
38}
39
40impl LogoConfig {
41    pub(super) fn validate(&self) -> Result<(), String> {
42        if self.logos.is_empty() {
43            return Err("At least one logo is required".to_string());
44        }
45
46        for logo in &self.logos {
47            if !logo.logo_type.eq_ignore_ascii_case("large") && !logo.logo_type.eq_ignore_ascii_case("small") {
48                return Err(format!("Logo type must be 'large' or 'small', found '{}'", logo.logo_type));
49            }
50        }
51
52        if self.colors.len() != 3 {
53            return Err(format!("Expected exactly 3 color elements, found {}", self.colors.len()));
54        }
55
56        if !matches!(&self.colors[0], ColorValue::Reference(_)) {
57            return Err("First color must be a reference string (e.g., '%0')".to_string());
58        }
59
60        if !matches!(&self.colors[1], ColorValue::Reference(_)) {
61            return Err("Second color must be a reference string (e.g., '%0')".to_string());
62        }
63
64        if !matches!(&self.colors[2], ColorValue::Array(_)) {
65            return Err("Third color element must be an array of color definitions".to_string());
66        }
67
68        Ok(())
69    }
70
71    pub(super) fn get_large_logo(&self) -> Option<Vec<String>> {
72        self.logos.iter().find(|l: &&LogoEntry| l.logo_type.eq_ignore_ascii_case("large")).map(|l: &LogoEntry| l.ascii.clone())
73    }
74
75    pub(super) fn get_small_logo(&self) -> Option<Vec<String>> {
76        self.logos.iter().find(|l: &&LogoEntry| l.logo_type.eq_ignore_ascii_case("small")).map(|l: &LogoEntry| l.ascii.clone())
77    }
78
79    pub(super) fn get_title_color_ref(&self) -> Option<&str> {
80        match self.colors.first()? {
81            ColorValue::Reference(s) => Some(s),
82            ColorValue::Array(_) => None
83        }
84    }
85
86    pub(super) fn get_keys_color_ref(&self) -> Option<&str> {
87        match self.colors.get(1)? {
88            ColorValue::Reference(s) => Some(s),
89            ColorValue::Array(_) => None
90        }
91    }
92
93    pub(super) fn get_color_defs(&self) -> Option<&[ColorDef]> {
94        match self.colors.get(2)? {
95            ColorValue::Array(arr) => Some(arr),
96            ColorValue::Reference(_) => None
97        }
98    }
99}
100
101#[derive(Debug, Clone)]
102pub struct ColorConfig {
103    pub title_color: AnyColor,
104    pub keys_color: AnyColor,
105    pub ascii_colors: Vec<AnyColor>
106}