chipi_core/bindings/
resolve.rs1use std::collections::HashMap;
7use std::path::PathBuf;
8
9use crate::error::Error;
10use crate::parser::parse_file_with_deps;
11use crate::types::{ValidatedDef, ValidatedSubDecoder};
12use crate::validate::validate;
13
14use super::types::BindingsFile;
15
16pub struct ResolvedBindings {
19 pub file: BindingsFile,
20 pub all_files: Vec<PathBuf>,
23 pub specs: Vec<ResolvedSpec>,
25}
26
27pub struct ResolvedSpec {
28 pub path: PathBuf,
29 pub def: ValidatedDef,
30}
31
32impl ResolvedBindings {
33 pub fn find_decoder(&self, name: &str) -> Option<&ResolvedSpec> {
36 self.specs.iter().find(|s| s.def.config.name == name)
37 }
38
39 pub fn find_subdecoder(&self, name: &str) -> Option<(&ResolvedSpec, &ValidatedSubDecoder)> {
42 for spec in &self.specs {
43 for sd in &spec.def.sub_decoders {
44 if sd.name == name {
45 return Some((spec, sd));
46 }
47 }
48 }
49 None
50 }
51
52 pub fn find_decoder_or_sub(
54 &self,
55 name: &str,
56 ) -> Option<(&ResolvedSpec, Option<&ValidatedSubDecoder>)> {
57 if let Some(s) = self.find_decoder(name) {
58 return Some((s, None));
59 }
60 if let Some((s, sd)) = self.find_subdecoder(name) {
61 return Some((s, Some(sd)));
62 }
63 None
64 }
65
66 pub fn all_decoder_names(&self) -> Vec<String> {
68 let mut names = Vec::new();
69 for spec in &self.specs {
70 names.push(spec.def.config.name.clone());
71 for sd in &spec.def.sub_decoders {
72 names.push(sd.name.clone());
73 }
74 }
75 names
76 }
77}
78
79pub fn resolve(file: BindingsFile) -> Result<ResolvedBindings, Vec<Error>> {
82 let mut all_files: Vec<PathBuf> = Vec::new();
83 all_files.push(file.path.clone());
84 for (p, _) in &file.bindings_includes {
85 all_files.push(p.clone());
86 }
87
88 let mut seen: HashMap<PathBuf, ()> = HashMap::new();
90 let mut specs: Vec<ResolvedSpec> = Vec::new();
91 let mut errors: Vec<Error> = Vec::new();
92
93 for (path, _span) in &file.spec_includes {
94 if seen.contains_key(path) {
95 continue;
96 }
97 seen.insert(path.clone(), ());
98
99 let (def, deps) = match parse_file_with_deps(path) {
100 Ok(v) => v,
101 Err(errs) => {
102 errors.extend(errs);
103 continue;
104 }
105 };
106
107 for dep in deps {
108 if !all_files.contains(&dep) {
109 all_files.push(dep);
110 }
111 }
112 if !all_files.contains(path) {
113 all_files.push(path.clone());
114 }
115
116 match validate(&def) {
117 Ok(v) => specs.push(ResolvedSpec {
118 path: path.clone(),
119 def: v,
120 }),
121 Err(errs) => errors.extend(errs),
122 }
123 }
124
125 if !errors.is_empty() {
126 return Err(errors);
127 }
128
129 Ok(ResolvedBindings {
130 file,
131 all_files,
132 specs,
133 })
134}