1use roxmltree::Node;
2use serde::{Deserialize, Serialize};
3use std::borrow::Cow;
4use std::collections::{BTreeMap, HashMap};
5use std::fs::OpenOptions;
6use std::io::Read;
7use std::path::Path;
8
9use crate::utils::prelude::*;
10use anyhow::{format_err, Error};
11
12mod component;
13mod condition;
14mod device;
15pub use component::{ComponentBuilders, FileRef};
16pub use condition::{Condition, Conditions};
17pub use device::{AccessPort, Algorithm, Core, Device, Devices, Memories, Processor};
18
19pub struct Release {
20 pub version: String,
21 pub text: String,
22}
23
24impl FromElem for Release {
25 fn from_elem(e: &Node) -> Result<Self, Error> {
26 assert_root_name(e, "release")?;
27 Ok(Self {
28 version: attr_map(e, "version")?,
29 text: e.text().unwrap().to_string(),
30 })
31 }
32}
33
34#[derive(Default)]
35pub struct Releases(Vec<Release>);
36
37impl Releases {
38 pub fn latest_release(&self) -> &Release {
39 &self.0[0]
40 }
41}
42
43impl FromElem for Releases {
44 fn from_elem(e: &Node) -> Result<Self, Error> {
45 assert_root_name(e, "releases")?;
46 let to_ret: Vec<_> = e
47 .children()
48 .filter(|e| e.is_element())
49 .flat_map(|c| Release::from_elem(&c).ok_warn())
50 .collect();
51 if to_ret.is_empty() {
52 Err(format_err!("There must be at least one release!"))
53 } else {
54 Ok(Releases(to_ret))
55 }
56 }
57}
58
59#[derive(Debug, Serialize, Deserialize)]
60pub struct DumpDevice<'a> {
61 name: &'a str,
62 memories: Cow<'a, Memories>,
63 algorithms: Cow<'a, Vec<Algorithm>>,
64 processors: Cow<'a, Vec<Processor>>,
65 from_pack: FromPack<'a>,
66 vendor: Option<&'a str>,
67 family: &'a str,
68 sub_family: Option<&'a str>,
69}
70
71#[derive(Clone, Debug, Serialize, Deserialize)]
72struct FromPack<'a> {
73 vendor: &'a str,
74 pack: &'a str,
75 version: &'a str,
76 url: &'a str,
77}
78
79impl<'a> FromPack<'a> {
80 fn new(vendor: &'a str, pack: &'a str, version: &'a str, url: &'a str) -> Self {
81 Self {
82 vendor,
83 pack,
84 version,
85 url,
86 }
87 }
88}
89
90impl<'a> DumpDevice<'a> {
91 fn from_device(dev: &'a Device, from_pack: FromPack<'a>) -> Self {
92 Self {
93 name: &dev.name,
94 memories: Cow::Borrowed(&dev.memories),
95 algorithms: Cow::Borrowed(&dev.algorithms),
96 processors: Cow::Borrowed(&dev.processors),
97 from_pack,
98 vendor: dev.vendor.as_deref(),
99 family: &dev.family,
100 sub_family: dev.sub_family.as_deref(),
101 }
102 }
103}
104
105pub struct Package {
106 pub name: String,
107 pub description: String,
108 pub vendor: String,
109 pub url: String,
110 pub license: Option<String>,
111 components: ComponentBuilders,
112 pub releases: Releases,
113 pub conditions: Conditions,
114 pub devices: Devices,
115 pub boards: Vec<Board>,
116}
117
118impl FromElem for Package {
119 fn from_elem(e: &Node) -> Result<Self, Error> {
120 assert_root_name(e, "package")?;
121 let name: String = child_text(e, "name")?;
122 let description: String = child_text(e, "description")?;
123 let vendor: String = child_text(e, "vendor")?;
124 let url: String = child_text(e, "url")?;
125 log::debug!("Working on {}::{}", vendor, name,);
126 let mut components = ComponentBuilders::default();
127 let mut releases = Releases::default();
128 let mut conditions = Conditions::default();
129 let mut devices = Devices::default();
130 let mut boards: Vec<Board> = Vec::new();
131 for child in e.children() {
132 match child.tag_name().name() {
133 "components" => {
134 components = ComponentBuilders::from_elem(&child)
135 .ok_warn()
136 .unwrap_or_default();
137 }
138 "releases" => {
139 releases = Releases::from_elem(&child).ok_warn().unwrap_or_default();
140 }
141 "conditions" => {
142 conditions = Conditions::from_elem(&child).ok_warn().unwrap_or_default();
143 }
144 "devices" => {
145 devices = Devices::from_elem(&child).ok_warn().unwrap_or_default();
146 }
147 "boards" => {
148 boards = Board::vec_from_children(child.children());
149 }
150 _ => {}
151 }
152 }
153 Ok(Self {
154 name,
155 description,
156 vendor,
157 url,
158 components,
159 license: child_text(e, "license").ok(),
160 releases,
161 conditions,
162 devices,
163 boards,
164 })
165 }
166}
167
168#[derive(Debug, Deserialize, Serialize)]
169pub struct Board {
170 name: String,
171 mounted_devices: Vec<String>,
172}
173
174impl FromElem for Board {
175 fn from_elem(e: &Node) -> Result<Self, Error> {
176 Ok(Self {
177 name: attr_map(e, "name")?,
178 mounted_devices: e
179 .children()
180 .flat_map(|c| match c.tag_name().name() {
181 "mountedDevice" => attr_map(&c, "Dname").ok(),
182 _ => None,
183 })
184 .collect(),
185 })
186 }
187}
188
189#[derive(Debug, Serialize)]
190pub struct Component {
191 pub vendor: String,
192 pub class: String,
193 pub group: String,
194 pub sub_group: Option<String>,
195 pub variant: Option<String>,
196 pub version: String,
197 pub api_version: Option<String>,
198 pub condition: Option<String>,
199 pub max_instances: Option<u8>,
200 pub is_default: bool,
201 pub deprecated: bool,
202 pub description: String,
203 pub rte_addition: String,
204 pub files: Vec<FileRef>,
205}
206
207type Components = Vec<Component>;
208
209impl Package {
210 pub fn make_components(&self) -> Components {
211 self.components
212 .0
213 .clone()
214 .into_iter()
215 .map(|comp| Component {
216 vendor: comp.vendor.unwrap_or_else(|| self.vendor.clone()),
217 class: comp.class.unwrap(),
218 group: comp.group.unwrap(),
219 sub_group: comp.sub_group,
220 variant: comp.variant,
221 version: comp
222 .version
223 .unwrap_or_else(|| self.releases.latest_release().version.clone()),
224 api_version: comp.api_version,
225 condition: comp.condition,
226 max_instances: comp.max_instances,
227 is_default: comp.is_default,
228 deprecated: comp.deprecated,
229 description: comp.description,
230 rte_addition: comp.rte_addition,
231 files: comp.files,
232 })
233 .collect()
234 }
235
236 pub fn make_condition_lookup(&self) -> HashMap<&str, &Condition> {
237 let mut map = HashMap::with_capacity(self.conditions.0.len());
238 for cond in self.conditions.0.iter() {
239 if let Some(dup) = map.insert(cond.id.as_str(), cond) {
240 log::warn!("Duplicate Condition found {}", dup.id);
241 }
242 }
243 map
244 }
245
246 pub fn make_dump_devices(&self) -> Vec<(&str, DumpDevice<'_>)> {
247 let from_pack = FromPack::new(
248 &self.vendor,
249 &self.name,
250 &self.releases.latest_release().version,
251 &self.url,
252 );
253 self.devices
254 .0
255 .iter()
256 .map(|(name, d)| (name.as_str(), DumpDevice::from_device(d, from_pack.clone())))
257 .collect()
258 }
259}
260pub fn dump_devices<'a, P: AsRef<Path>, I: IntoIterator<Item = &'a Package>>(
261 pdscs: I,
262 device_dest: Option<P>,
263 board_dest: Option<P>,
264) -> Result<(), Error> {
265 let pdscs: Vec<&Package> = pdscs.into_iter().collect();
266 let devices = pdscs
267 .iter()
268 .flat_map(|pdsc| pdsc.make_dump_devices().into_iter())
269 .collect::<HashMap<_, _>>();
270 match device_dest {
271 Some(to_file) => {
272 if !devices.is_empty() {
273 let mut file_contents = Vec::new();
274 let mut old_devices: HashMap<&str, DumpDevice> = HashMap::new();
275 if let Ok(mut fd) = OpenOptions::new().read(true).open(to_file.as_ref()) {
276 fd.read_to_end(&mut file_contents)?;
277 old_devices = serde_json::from_slice(&file_contents).unwrap_or_default();
278 }
279 let mut all_devices = BTreeMap::new();
280 all_devices.extend(old_devices.iter());
281 all_devices.extend(devices.iter());
282 let mut options = OpenOptions::new();
283 options.write(true);
284 options.create(true);
285 options.truncate(true);
286 if let Ok(fd) = options.open(to_file.as_ref()) {
287 serde_json::to_writer_pretty(fd, &all_devices).unwrap();
288 } else {
289 println!("Could not open file {:?}", to_file.as_ref());
290 }
291 }
292 }
293 None => println!("{}", &serde_json::to_string_pretty(&devices).unwrap()),
294 }
295 let boards = pdscs
296 .iter()
297 .flat_map(|pdsc| pdsc.boards.iter())
298 .map(|b| (&b.name, b))
299 .collect::<HashMap<_, _>>();
300 match board_dest {
301 Some(to_file) => {
302 let mut file_contents = Vec::new();
303 let mut old_boards: HashMap<String, Board> = HashMap::new();
304 if let Ok(mut fd) = OpenOptions::new().read(true).open(to_file.as_ref()) {
305 fd.read_to_end(&mut file_contents)?;
306 old_boards = serde_json::from_slice(&file_contents).unwrap_or_default();
307 }
308 let mut all_boards = BTreeMap::new();
309 all_boards.extend(old_boards.iter());
310 all_boards.extend(boards.iter());
311 let mut options = OpenOptions::new();
312 options.write(true);
313 options.create(true);
314 options.truncate(true);
315 if let Ok(fd) = options.open(to_file.as_ref()) {
316 serde_json::to_writer_pretty(fd, &all_boards).unwrap();
317 } else {
318 println!("Could not open file {:?}", to_file.as_ref());
319 }
320 }
321 None => println!("{}", &serde_json::to_string_pretty(&devices).unwrap()),
322 }
323 Ok(())
324}
325
326pub fn dumps_components<'a, I>(pdscs: I) -> Result<String, Error>
327where
328 I: IntoIterator<Item = &'a Package>,
329{
330 let components = pdscs
331 .into_iter()
332 .flat_map(|pdsc| pdsc.make_components().into_iter())
333 .collect::<Vec<_>>();
334 Ok(serde_json::to_string_pretty(&components)?)
335}