1use std::collections::HashMap;
2use std::fs;
3use std::path::PathBuf;
4use crate::common::parser::{ParsedManifest, parse};
5use crate::common::pool::{DynamicPool, PathMap, ChildrenMap, KeyList, YamlValueList};
6use crate::common::bit;
7use crate::ports::provided::ManifestError;
8
9#[derive(Debug, Default)]
11pub struct MetaIndices {
12 pub load: Option<u16>,
13 pub store: Option<u16>,
14 pub state: Option<u16>,
15}
16
17pub struct Manifest {
30 manifest_dir: PathBuf,
31 files: HashMap<String, ParsedManifest>,
32 pub dynamic: DynamicPool,
34 pub path_map: PathMap,
35 pub children_map: ChildrenMap,
36 pub keys: KeyList,
37 pub values: YamlValueList,
38}
39
40impl Manifest {
41 pub fn new(manifest_dir: &str) -> Self {
42 Self {
43 manifest_dir: PathBuf::from(manifest_dir),
44 files: HashMap::new(),
45 dynamic: DynamicPool::new(),
46 path_map: PathMap::new(),
47 children_map: ChildrenMap::new(),
48 keys: KeyList::new(),
49 values: YamlValueList::new(),
50 }
51 }
52
53 pub fn load(&mut self, file: &str) -> Result<(), ManifestError> {
79 crate::fn_log!("Manifest", "load", file);
80 if self.files.contains_key(file) {
81 return Ok(());
82 }
83
84 let yml_path = self.manifest_dir.join(format!("{}.yml", file));
85 let yaml_path = self.manifest_dir.join(format!("{}.yaml", file));
86 let yml_exists = yml_path.exists();
87 let yaml_exists = yaml_path.exists();
88
89 if yml_exists && yaml_exists {
90 return Err(ManifestError::AmbiguousFile(format!(
91 "both '{}.yml' and '{}.yaml' exist.",
92 file, file
93 )));
94 }
95
96 let path = if yml_exists {
97 yml_path
98 } else if yaml_exists {
99 yaml_path
100 } else {
101 return Err(ManifestError::FileNotFound(format!(
102 "'{}.yml' or '{}.yaml'", file, file
103 )));
104 };
105
106 let content = fs::read_to_string(&path)
107 .map_err(|e| ManifestError::ReadError(e.to_string()))?;
108
109 let pm = parse(
110 file,
111 &content,
112 &mut self.dynamic,
113 &mut self.path_map,
114 &mut self.children_map,
115 &mut self.keys,
116 &mut self.values,
117 ).map_err(|e| ManifestError::ParseError(e))?;
118
119 self.files.insert(file.to_string(), pm);
120 Ok(())
121 }
122
123 pub fn file_key_idx(&self, file: &str) -> Option<u16> {
125 self.files.get(file).map(|pm| pm.file_key_idx)
126 }
127
128 pub fn find(&self, file: &str, path: &str) -> Option<u16> {
149 let file_idx = self.files.get(file)?.file_key_idx;
150 let file_record = self.keys.get(file_idx)?;
151
152 if path.is_empty() {
153 return Some(file_idx);
154 }
155
156 let segments: Vec<&str> = path.split('.').collect();
157 let top_level = self.children_of(file_record);
158 self.find_in(&segments, &top_level)
159 }
160
161 fn find_in(&self, segments: &[&str], candidates: &[u16]) -> Option<u16> {
163 let target = segments[0];
164 let rest = &segments[1..];
165
166 for &idx in candidates {
167 let record = self.keys.get(idx)?;
168
169 if bit::get(record, bit::OFFSET_ROOT, bit::MASK_ROOT) != bit::ROOT_NULL {
171 continue;
172 }
173
174 let dyn_idx = bit::get(record, bit::OFFSET_DYNAMIC, bit::MASK_DYNAMIC) as u16;
175 if self.dynamic.get(dyn_idx)? != target {
176 continue;
177 }
178
179 if rest.is_empty() {
180 return Some(idx);
181 }
182
183 let next = self.children_of(record);
184 if next.is_empty() {
185 return None;
186 }
187 return self.find_in(rest, &next);
188 }
189
190 None
191 }
192
193 fn children_of(&self, record: u64) -> Vec<u16> {
195 let child_idx = bit::get(record, bit::OFFSET_CHILD, bit::MASK_CHILD) as u16;
196 if child_idx == 0 {
197 return vec![];
198 }
199 let has_children = bit::get(record, bit::OFFSET_HAS_CHILDREN, bit::MASK_HAS_CHILDREN);
200 if has_children == 1 {
201 self.children_map.get(child_idx)
202 .map(|s| s.to_vec())
203 .unwrap_or_default()
204 } else {
205 vec![child_idx]
206 }
207 }
208
209 pub fn get_meta(&self, file: &str, path: &str) -> MetaIndices {
229 crate::fn_log!("Manifest", "get_meta", &format!("{}.{}", file, path));
230 let file_idx = match self.files.get(file) {
231 Some(pm) => pm.file_key_idx,
232 None => return MetaIndices::default(),
233 };
234
235 let file_record = match self.keys.get(file_idx) {
236 Some(r) => r,
237 None => return MetaIndices::default(),
238 };
239
240 let segments: Vec<&str> = if path.is_empty() {
241 vec![]
242 } else {
243 path.split('.').collect()
244 };
245
246 let mut meta = MetaIndices::default();
247
248 self.collect_meta(file_record, &mut meta);
250
251 let mut candidates = self.children_of(file_record);
253 for segment in &segments {
254 let mut found_idx = None;
255 for &idx in &candidates {
256 let record = match self.keys.get(idx) {
257 Some(r) => r,
258 None => continue,
259 };
260 if bit::get(record, bit::OFFSET_ROOT, bit::MASK_ROOT) != bit::ROOT_NULL {
261 continue;
262 }
263 let dyn_idx = bit::get(record, bit::OFFSET_DYNAMIC, bit::MASK_DYNAMIC) as u16;
264 if self.dynamic.get(dyn_idx) == Some(segment) {
265 self.collect_meta(record, &mut meta);
266 found_idx = Some(idx);
267 break;
268 }
269 }
270 match found_idx {
271 Some(idx) => {
272 let record = self.keys.get(idx).unwrap();
273 candidates = self.children_of(record);
274 }
275 None => return MetaIndices::default(),
276 }
277 }
278
279 meta
280 }
281
282 fn collect_meta(&self, record: u64, meta: &mut MetaIndices) {
284 let children = self.children_of(record);
285 for &idx in &children {
286 let child = match self.keys.get(idx) {
287 Some(r) => r,
288 None => continue,
289 };
290 let root = bit::get(child, bit::OFFSET_ROOT, bit::MASK_ROOT);
291 match root {
292 bit::ROOT_LOAD => meta.load = Some(idx),
293 bit::ROOT_STORE => meta.store = Some(idx),
294 bit::ROOT_STATE => meta.state = Some(idx),
295 _ => {}
296 }
297 }
298 }
299
300 pub fn get_value(&self, file: &str, path: &str) -> Vec<(u16, u16)> {
316 let node_idx = match self.find(file, path) {
317 Some(idx) => idx,
318 None => return vec![],
319 };
320
321 let record = match self.keys.get(node_idx) {
322 Some(r) => r,
323 None => return vec![],
324 };
325
326 let mut result = Vec::new();
327 let children = self.children_of(record);
328
329 for &idx in &children {
330 let child = match self.keys.get(idx) {
331 Some(r) => r,
332 None => continue,
333 };
334 if bit::get(child, bit::OFFSET_ROOT, bit::MASK_ROOT) != bit::ROOT_NULL {
336 continue;
337 }
338 if bit::get(child, bit::OFFSET_IS_LEAF, bit::MASK_IS_LEAF) == 0 {
340 continue;
341 }
342 let dyn_idx = bit::get(child, bit::OFFSET_DYNAMIC, bit::MASK_DYNAMIC) as u16;
343 let value_idx = bit::get(child, bit::OFFSET_CHILD, bit::MASK_CHILD) as u16;
344 result.push((dyn_idx, value_idx));
345 }
346
347 result
348 }
349}