1use substrate_data::schema::NamedType;
4use substrate_data::typed::{Spelled, classify};
5use substrate_data::{Kind, Value};
6
7use crate::{Res, kinds};
8
9const RGB_DIGITS: usize = 6;
11const ARGB_DIGITS: usize = 8;
12const OPAQUE: u32 = 0xFF00_0000;
14
15#[derive(Debug, Clone, PartialEq)]
17pub enum Color {
18 Argb(u32),
19 Res(Res),
20}
21
22impl Color {
23 pub fn parse(s: &str) -> Option<u32> {
25 let hex = s.strip_prefix(yog_ids::sep::TAG)?;
26 let value = u32::from_str_radix(hex, 16).ok()?;
27 match hex.len() {
28 RGB_DIGITS => Some(OPAQUE | value),
29 ARGB_DIGITS => Some(value),
30 _ => None,
31 }
32 }
33
34 pub fn format(argb: u32) -> String {
36 format!("{}{argb:08X}", yog_ids::sep::TAG)
37 }
38}
39
40impl NamedType for Color {
41 const NAME: &'static str = yog_ids::typed::COLOR;
42 type Stored = Value;
43 fn to_stored(&self) -> Value {
44 match self {
45 Color::Argb(c) => Value::Int(i64::from(*c)),
46 Color::Res(r) => substrate_data::Schema::write(r),
47 }
48 }
49 fn from_stored(stored: Value) -> Option<Self> {
50 match stored {
51 Value::Int(c) => u32::try_from(c).ok().map(Color::Argb),
52 Value::Str(s) if s.starts_with(yog_ids::sep::TAG) => Color::parse(&s).map(Color::Argb),
53 Value::Str(s) => match classify(&s).ok()? {
54 Spelled::Ref(r) if r.kind.as_str() == kinds::Res::NAME => {
55 Res::parse(r.id.as_str()).map(Color::Res)
56 }
57 _ => None,
58 },
59 Value::Ref(r) if r.kind.as_str() == kinds::Res::NAME => {
60 Res::parse(r.id.as_str()).map(Color::Res)
61 }
62 _ => None,
63 }
64 }
65}
66
67substrate_data::named_schema!(Color);