Skip to main content

yog_data/res/
mod.rs

1//! [`Res`]: an entry of a mod's `.yres` sets, `@res:Strings.title`.
2
3use std::fmt;
4
5use substrate_data::{Id, Reader, Schema, Shape, Value, ValueRef};
6
7use crate::kinds;
8
9/// An entry of a `.yres` set: the set (upper case, `Strings`) and its key
10/// (`screen.title`), written `@res:Strings.screen.title`.
11#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
12pub struct Res {
13    pub set: String,
14    pub key: String,
15}
16
17impl Res {
18    /// `Set.key`: what the resources list it by.
19    pub fn name(&self) -> String {
20        format!("{}{}{}", self.set, yog_ids::sep::DOT, self.key)
21    }
22
23    /// `spelled` (`Strings.screen.title`) as an entry, if it's one.
24    pub fn parse(spelled: &str) -> Option<Res> {
25        let (set, key) = spelled.split_once(yog_ids::sep::DOT)?;
26        let set_ok = set.starts_with(|c: char| c.is_ascii_uppercase())
27            && set.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_');
28        (set_ok && is_key(key)).then(|| Res {
29            set: set.to_owned(),
30            key: key.to_owned(),
31        })
32    }
33}
34
35/// A key as `.yres` files have them: letters, digits, `_`, dotted.
36pub fn is_key(key: &str) -> bool {
37    key.starts_with(|c: char| c.is_ascii_alphabetic() || c == '_')
38        && key.split(yog_ids::sep::DOT).all(|part| {
39            !part.is_empty() && part.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_')
40        })
41}
42
43impl fmt::Display for Res {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        write!(f, "{}{}", yog_ids::reference::RES, self.name())
46    }
47}
48
49impl Schema for Res {
50    fn shape() -> Shape {
51        substrate_data::schema::ref_shape::<kinds::Res>()
52    }
53    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<Self> {
54        let id = Id::<kinds::Res>::read(v, cx)?;
55        Res::parse(&id.id).or_else(|| {
56            cx.problem(format!(
57                "`{}`: an entry is `@res:Set.key` with an upper-case set (`@res:Strings.title`)",
58                id.id
59            ));
60            None
61        })
62    }
63    fn write(&self) -> Value {
64        Id::<kinds::Res>::new(self.name()).write()
65    }
66}