substrate_data/schema/dictionary/
dictionary.rs1use std::collections::BTreeMap;
5
6use super::entries::Entries;
7use crate::model::borrowed::ValueRef;
8use crate::model::value::{KindName, Map, Path, Ref, RefKey, Seg, Value};
9use crate::schema::{Reader, Resolve, Schema, Shape, Unresolved, is_metadata_key};
10
11#[derive(Debug, Clone, Default, PartialEq)]
44pub struct Dictionary {
45 kinds: BTreeMap<KindName, Entries>,
46}
47
48impl Dictionary {
49 #[must_use]
51 pub fn new() -> Self {
52 Self::default()
53 }
54
55 pub fn insert(&mut self, kind: KindName, id: RefKey, value: Value) -> Option<Value> {
58 self.kinds.entry(kind).or_default().insert(id, value)
59 }
60
61 pub fn declare(&mut self, kind: KindName) {
64 self.kinds.entry(kind).or_default();
65 }
66
67 #[must_use]
69 pub fn holds(&self, kind: KindName) -> bool {
70 self.kinds.contains_key(&kind)
71 }
72
73 #[must_use]
75 pub fn get(&self, r: &Ref) -> Option<&Value> {
76 self.kinds.get(&r.kind)?.get(&r.id)
77 }
78
79 pub fn kinds(&self) -> impl Iterator<Item = KindName> + '_ {
81 self.kinds.keys().copied()
82 }
83
84 pub fn entries(&self, kind: KindName) -> impl Iterator<Item = (&RefKey, &Value)> {
86 self.kinds.get(&kind).into_iter().flat_map(Entries::iter)
87 }
88
89 #[must_use]
91 pub fn len(&self) -> usize {
92 self.kinds.values().map(Entries::len).sum()
93 }
94
95 #[must_use]
97 pub fn is_empty(&self) -> bool {
98 self.len() == 0
99 }
100}
101
102impl Resolve for Dictionary {
103 fn reference(&mut self, r: &Ref, _path: &Path) -> Result<RefKey, Unresolved> {
104 match self.kinds.get(&r.kind) {
105 Some(entries) if entries.get(&r.id).is_none() => Err(Unresolved::Missing(r.clone())),
106 _ => Ok(r.id.clone()),
107 }
108 }
109
110 fn expand(&mut self, r: &Ref, _path: &Path) -> Result<Option<Value>, Unresolved> {
111 let Some(entries) = self.kinds.get(&r.kind) else {
112 return Ok(None);
113 };
114 entries
115 .get(&r.id)
116 .cloned()
117 .map(Some)
118 .ok_or_else(|| Unresolved::Missing(r.clone()))
119 }
120}
121
122fn read_kind(
124 dictionary: &mut Dictionary,
125 kind: &str,
126 v: &ValueRef<'_>,
127 cx: &mut Reader<'_>,
128) -> Option<()> {
129 let kind = KindName::new(kind)
130 .map_err(|e| cx.problem_of(crate::Problem::BadTyped, e.to_string()))
131 .ok()?;
132 let entries = cx.map(v)?;
133 dictionary.declare(kind);
134 let mut ok = true;
135 for (id, value) in entries.iter().filter(|(id, _)| !is_metadata_key(id)) {
136 let read = cx.at(Seg::Key(id.to_string()), |cx| {
137 RefKey::new(id)
138 .map_err(|e| cx.problem_of(crate::Problem::BadId, e.to_string()))
139 .ok()
140 });
141 match read {
142 Some(key) => {
143 dictionary.insert(kind, key, value.to_value());
144 }
145 None => ok = false,
146 }
147 }
148 ok.then_some(())
149}
150
151fn words() -> Shape {
152 Shape::Map(<Value as Schema>::shape)
153}
154
155impl Schema for Dictionary {
156 fn shape() -> Shape {
157 Shape::Map(words)
158 }
159 fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<Self> {
160 let kinds = cx.map(v)?;
161 let mut out = Dictionary::new();
162 let mut ok = true;
163 for (kind, entries) in kinds.iter().filter(|(k, _)| !is_metadata_key(k)) {
164 let read = cx.at(Seg::Key(kind.to_string()), |cx| {
165 read_kind(&mut out, kind, entries, cx)
166 });
167 ok &= read.is_some();
168 }
169 ok.then_some(out)
170 }
171 fn write(&self) -> Value {
172 let kinds = self.kinds.iter().map(|(kind, entries)| {
173 let values: Map = entries
174 .iter()
175 .map(|(id, v)| (id.as_str().to_owned(), v.clone()))
176 .collect();
177 (kind.as_str().to_owned(), Value::Map(values))
178 });
179 Value::Map(kinds.collect())
180 }
181}