1use std::collections::HashMap;
2use std::path::PathBuf;
3use crate::core::parser::{ParsedManifest, Value, parse};
4use crate::core::pool::DynamicPool;
5use crate::core::fixed_bits;
6use crate::ports::provided::ManifestError;
7use crate::ports::required::FileClient;
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 file: Box<dyn FileClient>,
32 files: HashMap<String, ParsedManifest>,
33 pub dynamic: DynamicPool,
34 pub keys: Vec<u64>,
35 pub values: Vec<[u64; 2]>,
36 pub path_map: Vec<Vec<u16>>,
37 pub children_map: Vec<Vec<u16>>,
38}
39
40impl Manifest {
41 pub fn new(manifest_dir: &str) -> Self {
42 Self {
43 manifest_dir: PathBuf::from(manifest_dir),
44 file: Box::new(crate::ports::default::DefaultFileClient),
45 files: HashMap::new(),
46 dynamic: DynamicPool::new(),
47 keys: vec![0],
48 values: vec![[0, 0]],
49 path_map: vec![vec![]],
50 children_map: vec![vec![]],
51 }
52 }
53
54 pub fn with_file(mut self, client: impl FileClient + 'static) -> Self {
77 self.file = Box::new(client);
78 self
79 }
80
81 pub fn load(&mut self, file: &str) -> Result<(), ManifestError> {
107 crate::fn_log!("Manifest", "load", file);
108 if self.files.contains_key(file) {
109 return Ok(());
110 }
111
112 let yml_path = self.manifest_dir.join(format!("{}.yml", file));
113 let yaml_path = self.manifest_dir.join(format!("{}.yaml", file));
114
115 let yml_key = yml_path.to_string_lossy();
116 let yaml_key = yaml_path.to_string_lossy();
117 let yml_content = self.file.get(&yml_key);
118 let yaml_content = self.file.get(&yaml_key);
119
120 let content = match (yml_content, yaml_content) {
121 (Some(_), Some(_)) => return Err(ManifestError::AmbiguousFile(format!(
122 "both '{}.yml' and '{}.yaml' exist.", file, file
123 ))),
124 (Some(c), None) => c,
125 (None, Some(c)) => c,
126 (None, None) => return Err(ManifestError::FileNotFound(format!(
127 "'{}.yml' or '{}.yaml'", file, file
128 ))),
129 };
130
131 let yaml_root: serde_yaml_ng::Value = serde_yaml_ng::from_str(&content)
132 .map_err(|e| ManifestError::ParseError(format!("YAML parse error: {}", e)))?;
133
134 let pm = parse(
135 file,
136 yaml_to_value(yaml_root),
137 &mut self.dynamic,
138 &mut self.keys,
139 &mut self.values,
140 &mut self.path_map,
141 &mut self.children_map,
142 ).map_err(|e| ManifestError::ParseError(e))?;
143
144 self.files.insert(file.to_string(), pm);
145 Ok(())
146 }
147
148 pub fn file_key_idx(&self, file: &str) -> Option<u16> {
150 self.files.get(file).map(|pm| pm.file_key_idx)
151 }
152
153 pub fn find(&self, file: &str, path: &str) -> Option<u16> {
174 let file_idx = self.files.get(file)?.file_key_idx;
175 let file_record = self.keys.get(file_idx as usize).copied()?;
176
177 if path.is_empty() {
178 return Some(file_idx);
179 }
180
181 let segments: Vec<&str> = path.split('.').collect();
182 let top_level = self.children_of(file_record);
183 self.find_in(&segments, &top_level)
184 }
185
186 fn find_in(&self, segments: &[&str], candidates: &[u16]) -> Option<u16> {
188 let target = segments[0];
189 let rest = &segments[1..];
190
191 for &idx in candidates {
192 let record = self.keys.get(idx as usize).copied()?;
193
194 if fixed_bits::get(record, fixed_bits::K_OFFSET_ROOT, fixed_bits::K_MASK_ROOT) != fixed_bits::ROOT_NULL {
196 continue;
197 }
198
199 let dyn_idx = fixed_bits::get(record, fixed_bits::K_OFFSET_DYNAMIC, fixed_bits::K_MASK_DYNAMIC) as u16;
200 if self.dynamic.get(dyn_idx)? != target {
201 continue;
202 }
203
204 if rest.is_empty() {
205 return Some(idx);
206 }
207
208 let next = self.children_of(record);
209 if next.is_empty() {
210 return None;
211 }
212 return self.find_in(rest, &next);
213 }
214
215 None
216 }
217
218 fn children_of(&self, record: u64) -> Vec<u16> {
220 let child_idx = fixed_bits::get(record, fixed_bits::K_OFFSET_CHILD, fixed_bits::K_MASK_CHILD) as usize;
221 if child_idx == 0 {
222 return vec![];
223 }
224 let has_children = fixed_bits::get(record, fixed_bits::K_OFFSET_HAS_CHILDREN, fixed_bits::K_MASK_HAS_CHILDREN);
225 if has_children == 1 {
226 self.children_map.get(child_idx)
227 .map(|s: &Vec<u16>| s.to_vec())
228 .unwrap_or_default()
229 } else {
230 vec![child_idx as u16]
231 }
232 }
233
234 pub fn get_meta(&self, file: &str, path: &str) -> MetaIndices {
254 crate::fn_log!("Manifest", "get_meta", &format!("{}.{}", file, path));
255 let file_idx = match self.files.get(file) {
256 Some(pm) => pm.file_key_idx,
257 None => return MetaIndices::default(),
258 };
259
260 let file_record = match self.keys.get(file_idx as usize).copied() {
261 Some(r) => r,
262 None => return MetaIndices::default(),
263 };
264
265 let segments: Vec<&str> = if path.is_empty() {
266 vec![]
267 } else {
268 path.split('.').collect()
269 };
270
271 let mut meta = MetaIndices::default();
272
273 self.collect_meta(file_record, &mut meta);
275
276 let mut candidates = self.children_of(file_record);
278 for segment in &segments {
279 let mut found_idx = None;
280 for &idx in &candidates {
281 let record = match self.keys.get(idx as usize).copied() {
282 Some(r) => r,
283 None => continue,
284 };
285 if fixed_bits::get(record, fixed_bits::K_OFFSET_ROOT, fixed_bits::K_MASK_ROOT) != fixed_bits::ROOT_NULL {
286 continue;
287 }
288 let dyn_idx = fixed_bits::get(record, fixed_bits::K_OFFSET_DYNAMIC, fixed_bits::K_MASK_DYNAMIC) as u16;
289 if self.dynamic.get(dyn_idx) == Some(segment) {
290 self.collect_meta(record, &mut meta);
291 found_idx = Some(idx);
292 break;
293 }
294 }
295 match found_idx {
296 Some(idx) => {
297 let record = self.keys[idx as usize];
298 candidates = self.children_of(record);
299 }
300 None => return MetaIndices::default(),
301 }
302 }
303
304 meta
305 }
306
307 fn collect_meta(&self, record: u64, meta: &mut MetaIndices) {
309 let children = self.children_of(record);
310 for &idx in &children {
311 let child = match self.keys.get(idx as usize).copied() {
312 Some(r) => r,
313 None => continue,
314 };
315 let root = fixed_bits::get(child, fixed_bits::K_OFFSET_ROOT, fixed_bits::K_MASK_ROOT);
316 match root {
317 fixed_bits::ROOT_LOAD => meta.load = Some(idx),
318 fixed_bits::ROOT_STORE => meta.store = Some(idx),
319 fixed_bits::ROOT_STATE => meta.state = Some(idx),
320 _ => {}
321 }
322 }
323 }
324
325 pub fn get_value(&self, file: &str, path: &str) -> Vec<(u16, u16)> {
341 let node_idx = match self.find(file, path) {
342 Some(idx) => idx,
343 None => return vec![],
344 };
345
346 let record = match self.keys.get(node_idx as usize).copied() {
347 Some(r) => r,
348 None => return vec![],
349 };
350
351 let mut result = Vec::new();
352 let children = self.children_of(record);
353
354 for &idx in &children {
355 let child = match self.keys.get(idx as usize).copied() {
356 Some(r) => r,
357 None => continue,
358 };
359 if fixed_bits::get(child, fixed_bits::K_OFFSET_ROOT, fixed_bits::K_MASK_ROOT) != fixed_bits::ROOT_NULL {
361 continue;
362 }
363 if fixed_bits::get(child, fixed_bits::K_OFFSET_IS_LEAF, fixed_bits::K_MASK_IS_LEAF) == 0 {
365 continue;
366 }
367 let dyn_idx = fixed_bits::get(child, fixed_bits::K_OFFSET_DYNAMIC, fixed_bits::K_MASK_DYNAMIC) as u16;
368 let value_idx = fixed_bits::get(child, fixed_bits::K_OFFSET_CHILD, fixed_bits::K_MASK_CHILD) as u16;
369 result.push((dyn_idx, value_idx));
370 }
371
372 result
373 }
374}
375
376fn yaml_to_value(v: serde_yaml_ng::Value) -> Value {
377 match v {
378 serde_yaml_ng::Value::Mapping(m) => Value::Mapping(
379 m.into_iter()
380 .filter_map(|(k, v)| {
381 let key = match k {
382 serde_yaml_ng::Value::String(s) => s,
383 _ => return None,
384 };
385 Some((key, yaml_to_value(v)))
386 })
387 .collect(),
388 ),
389 serde_yaml_ng::Value::String(s) => Value::Scalar(s),
390 serde_yaml_ng::Value::Number(n) => Value::Scalar(n.to_string()),
391 serde_yaml_ng::Value::Bool(b) => Value::Scalar(b.to_string()),
392 serde_yaml_ng::Value::Null => Value::Null,
393 _ => Value::Null,
394 }
395}