Skip to main content

yog_data/color/
mod.rs

1//! [`Color`]: `#RRGGBB`, `#AARRGGBB`, or a `.yres` colour.
2
3use substrate_data::schema::NamedType;
4use substrate_data::typed::{Spelled, classify};
5use substrate_data::{Kind, Value};
6
7use crate::{Res, kinds};
8
9/// Hex digits of a colour without alpha, and with it.
10const RGB_DIGITS: usize = 6;
11const ARGB_DIGITS: usize = 8;
12/// What a colour written without alpha is: fully opaque.
13const OPAQUE: u32 = 0xFF00_0000;
14
15/// A colour: ARGB, or a `.yres` colour.
16#[derive(Debug, Clone, PartialEq)]
17pub enum Color {
18    Argb(u32),
19    Res(Res),
20}
21
22impl Color {
23    /// `#RRGGBB` (opaque) or `#AARRGGBB`.
24    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    /// `#AARRGGBB`.
35    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);