Skip to main content

specfold_core/model/
registry.rs

1//! The type registry: the built-in preset with a project's overrides applied.
2
3use super::doctype::{self, Form, KeyKind, TypeDef};
4use serde::{Deserialize, Serialize};
5use std::collections::BTreeMap;
6
7/// Overrides for one type from spec.toml.
8#[derive(Debug, Clone, Default, Deserialize, Serialize)]
9#[serde(deny_unknown_fields)]
10pub struct TypeOverride {
11    pub enabled: Option<bool>,
12    pub about: Option<String>,
13    pub key: Option<KeyKind>,
14    pub form: Option<Form>,
15    pub statuses: Option<Vec<String>>,
16    pub initial: Option<String>,
17    pub sealed: Option<bool>,
18    pub fields: Option<Vec<String>>,
19    pub template: Option<String>,
20    pub transitions: Option<BTreeMap<String, Vec<String>>>,
21    pub require_when: Option<BTreeMap<String, Vec<String>>>,
22}
23
24#[derive(Debug, Clone)]
25pub struct Registry {
26    pub types: Vec<TypeDef>,
27}
28
29fn apply(t: &mut TypeDef, o: &TypeOverride) {
30    if let Some(v) = &o.about {
31        t.about = v.clone();
32    }
33    if let Some(v) = o.key {
34        t.key = v;
35    }
36    if let Some(v) = o.form {
37        t.form = v;
38    }
39    if let Some(v) = &o.statuses {
40        t.statuses = v.clone();
41    }
42    if let Some(v) = &o.initial {
43        t.initial = v.clone();
44    }
45    if let Some(v) = o.sealed {
46        t.sealed = v;
47    }
48    if let Some(v) = &o.fields {
49        t.fields = v.clone();
50    }
51    if let Some(v) = &o.template {
52        t.template = v.clone();
53    }
54    if let Some(v) = &o.transitions {
55        t.transitions = v.clone();
56    }
57    if let Some(v) = &o.require_when {
58        t.require_when = v.clone();
59    }
60}
61
62impl Registry {
63    pub fn new(overrides: &BTreeMap<String, TypeOverride>) -> Self {
64        let mut types = doctype::builtin();
65        for (name, o) in overrides {
66            let pos = types.iter().position(|t| &t.name == name);
67            if o.enabled == Some(false) {
68                if let Some(p) = pos {
69                    types.remove(p);
70                }
71                continue;
72            }
73            match pos {
74                Some(p) => apply(&mut types[p], o),
75                None => {
76                    let mut t = doctype::custom(name);
77                    apply(&mut t, o);
78                    types.push(t);
79                }
80            }
81        }
82        Registry { types }
83    }
84
85    pub fn get(&self, name: &str) -> Option<&TypeDef> {
86        self.types.iter().find(|t| t.name == name)
87    }
88
89    pub fn names(&self) -> Vec<&str> {
90        self.types.iter().map(|t| t.name.as_str()).collect()
91    }
92}