1use alloc::format;
12use alloc::string::ToString;
13use alloc::vec::Vec;
14
15use crate::errors::XmlError;
16use crate::parser::{XmlElement, parse_xml_tree};
17use crate::types::{parse_long, parse_ulong};
18use crate::xtypes_def::{
19 BitField, BitValue, BitmaskType, BitsetType, EnumLiteral, EnumType, Extensibility, ModuleEntry,
20 PrimitiveType, StructMember, StructType, TypeDef, TypeLibrary, TypeRef, TypedefType, UnionCase,
21 UnionDiscriminator, UnionType,
22};
23
24pub fn parse_type_libraries(xml: &str) -> Result<Vec<TypeLibrary>, XmlError> {
34 let doc = parse_xml_tree(xml)?;
35 let mut out = Vec::new();
36 match doc.root.name.as_str() {
37 "dds" => {
38 for child in &doc.root.children {
39 if child.name == "types" {
40 out.push(parse_types_element(child)?);
41 }
42 }
43 }
44 "types" => out.push(parse_types_element(&doc.root)?),
45 other => {
46 return Err(XmlError::InvalidXml(format!(
47 "expected <dds> or <types> root, got <{other}>"
48 )));
49 }
50 }
51 Ok(out)
52}
53
54pub fn parse_types_element(el: &XmlElement) -> Result<TypeLibrary, XmlError> {
59 let name = el.attribute("name").unwrap_or("").to_string();
60 let mut lib = TypeLibrary {
61 name,
62 types: Vec::new(),
63 };
64 for child in &el.children {
65 lib.types.push(parse_type_def(child)?);
66 }
67 Ok(lib)
68}
69
70fn parse_type_def(el: &XmlElement) -> Result<TypeDef, XmlError> {
73 match el.name.as_str() {
74 "module" => Ok(TypeDef::Module(parse_module(el)?)),
75 "struct" => Ok(TypeDef::Struct(parse_struct(el)?)),
76 "enum" => Ok(TypeDef::Enum(parse_enum(el)?)),
77 "union" => Ok(TypeDef::Union(parse_union(el)?)),
78 "typedef" => Ok(TypeDef::Typedef(parse_typedef(el)?)),
79 "bitmask" => Ok(TypeDef::Bitmask(parse_bitmask(el)?)),
80 "bitset" => Ok(TypeDef::Bitset(parse_bitset(el)?)),
81 "include" => Ok(TypeDef::Include(parse_include(el)?)),
82 "forward_dcl" | "forwardDcl" => Ok(TypeDef::ForwardDcl(parse_forward_dcl(el)?)),
83 "const" => Ok(TypeDef::Const(parse_const(el)?)),
84 other => Err(XmlError::UnknownElement(other.to_string())),
85 }
86}
87
88fn parse_include(el: &XmlElement) -> Result<crate::xtypes_def::IncludeEntry, XmlError> {
89 let file = require_attr(el, "file")?.to_string();
90 Ok(crate::xtypes_def::IncludeEntry { file })
91}
92
93fn parse_forward_dcl(el: &XmlElement) -> Result<crate::xtypes_def::ForwardDeclEntry, XmlError> {
94 let name = require_attr(el, "name")?.to_string();
95 let kind = el.attribute("kind").unwrap_or("STRUCT").to_string();
97 Ok(crate::xtypes_def::ForwardDeclEntry { name, kind })
98}
99
100fn parse_const(el: &XmlElement) -> Result<crate::xtypes_def::ConstEntry, XmlError> {
101 let name = require_attr(el, "name")?.to_string();
102 let type_name = require_attr(el, "type")?.to_string();
103 let value = require_attr(el, "value")?.to_string();
104 Ok(crate::xtypes_def::ConstEntry {
105 name,
106 type_name,
107 value,
108 })
109}
110
111fn parse_module(el: &XmlElement) -> Result<ModuleEntry, XmlError> {
114 let name = require_attr(el, "name")?.to_string();
115 let mut types = Vec::new();
116 for child in &el.children {
117 types.push(parse_type_def(child)?);
118 }
119 Ok(ModuleEntry { name, types })
120}
121
122fn parse_struct(el: &XmlElement) -> Result<StructType, XmlError> {
123 let name = require_attr(el, "name")?.to_string();
124 let extensibility = el
125 .attribute("extensibility")
126 .map(parse_extensibility)
127 .transpose()?;
128 let base_type = el
129 .attribute("baseType")
130 .or_else(|| el.attribute("base_type"))
131 .map(ToString::to_string);
132 let mut members = Vec::new();
133 for child in &el.children {
134 if child.name == "member" {
135 members.push(parse_member(child)?);
136 }
137 }
138 Ok(StructType {
139 name,
140 extensibility,
141 base_type,
142 members,
143 })
144}
145
146fn parse_extensibility(s: &str) -> Result<Extensibility, XmlError> {
147 match s {
148 "final" | "FINAL" => Ok(Extensibility::Final),
149 "appendable" | "APPENDABLE" => Ok(Extensibility::Appendable),
150 "mutable" | "MUTABLE" => Ok(Extensibility::Mutable),
151 other => Err(XmlError::BadEnum(other.to_string())),
152 }
153}
154
155fn parse_member(el: &XmlElement) -> Result<StructMember, XmlError> {
156 let name = require_attr(el, "name")?.to_string();
157 let type_str = require_attr(el, "type")?;
158 let type_ref = parse_type_ref(type_str);
159 let key = parse_attr_bool(el, "key")?;
160 let optional = parse_attr_bool(el, "optional")?;
161 let must_understand =
162 parse_attr_bool(el, "mustUnderstand")? || parse_attr_bool(el, "must_understand")?;
163 let id = el.attribute("id").map(parse_ulong).transpose()?;
164 let string_max_length = el
165 .attribute("stringMaxLength")
166 .map(parse_ulong)
167 .transpose()?;
168 let sequence_max_length = el
169 .attribute("sequenceMaxLength")
170 .map(parse_ulong)
171 .transpose()?;
172 let array_dimensions = el
173 .attribute("arrayDimensions")
174 .map(parse_dimensions)
175 .transpose()?
176 .unwrap_or_default();
177 Ok(StructMember {
178 name,
179 type_ref,
180 key,
181 optional,
182 must_understand,
183 id,
184 string_max_length,
185 sequence_max_length,
186 array_dimensions,
187 })
188}
189
190fn parse_type_ref(s: &str) -> TypeRef {
191 if let Some(p) = PrimitiveType::from_xml(s) {
192 TypeRef::Primitive(p)
193 } else {
194 TypeRef::Named(s.to_string())
195 }
196}
197
198fn parse_attr_bool(el: &XmlElement, key: &str) -> Result<bool, XmlError> {
199 match el.attribute(key) {
200 None => Ok(false),
201 Some(v) => crate::types::parse_bool(v),
202 }
203}
204
205fn parse_dimensions(s: &str) -> Result<Vec<u32>, XmlError> {
206 let mut out = Vec::new();
207 for piece in s.split(',') {
208 let t = piece.trim();
209 if t.is_empty() {
210 continue;
211 }
212 let v = parse_ulong(t)?;
213 out.push(v);
214 }
215 Ok(out)
216}
217
218fn parse_enum(el: &XmlElement) -> Result<EnumType, XmlError> {
219 let name = require_attr(el, "name")?.to_string();
220 let bit_bound = el.attribute("bitBound").map(parse_ulong).transpose()?;
221 let mut enumerators = Vec::new();
222 for child in &el.children {
223 if child.name == "enumerator" {
224 let n = require_attr(child, "name")?.to_string();
225 let value = child.attribute("value").map(parse_long).transpose()?;
226 enumerators.push(EnumLiteral { name: n, value });
227 }
228 }
229 Ok(EnumType {
230 name,
231 bit_bound,
232 enumerators,
233 })
234}
235
236fn parse_union(el: &XmlElement) -> Result<UnionType, XmlError> {
237 let name = require_attr(el, "name")?.to_string();
238 let disc_str = require_attr(el, "discriminator")?;
239 let discriminator = parse_type_ref(disc_str);
240 let mut cases = Vec::new();
241 for child in el.children_named("case") {
242 cases.push(parse_union_case(child)?);
243 }
244 Ok(UnionType {
245 name,
246 discriminator,
247 cases,
248 })
249}
250
251fn parse_union_case(el: &XmlElement) -> Result<UnionCase, XmlError> {
252 let mut discriminators = Vec::new();
253 let mut member: Option<StructMember> = None;
254 for child in &el.children {
255 match child.name.as_str() {
256 "caseDiscriminator" => {
257 let v = require_attr(child, "value")?;
258 if v == "default" {
259 discriminators.push(UnionDiscriminator::Default);
260 } else {
261 discriminators.push(UnionDiscriminator::Value(v.to_string()));
262 }
263 }
264 "member" => {
265 member = Some(parse_member(child)?);
266 }
267 _ => {}
268 }
269 }
270 let member = member.ok_or_else(|| XmlError::MissingRequiredElement("member".to_string()))?;
271 Ok(UnionCase {
272 discriminators,
273 member,
274 })
275}
276
277fn parse_typedef(el: &XmlElement) -> Result<TypedefType, XmlError> {
278 let name = require_attr(el, "name")?.to_string();
279 let type_str = require_attr(el, "type")?;
280 let type_ref = parse_type_ref(type_str);
281 let array_dimensions = el
282 .attribute("arrayDimensions")
283 .map(parse_dimensions)
284 .transpose()?
285 .unwrap_or_default();
286 let sequence_max_length = el
287 .attribute("sequenceMaxLength")
288 .map(parse_ulong)
289 .transpose()?;
290 let string_max_length = el
291 .attribute("stringMaxLength")
292 .map(parse_ulong)
293 .transpose()?;
294 Ok(TypedefType {
295 name,
296 type_ref,
297 array_dimensions,
298 sequence_max_length,
299 string_max_length,
300 })
301}
302
303fn parse_bitmask(el: &XmlElement) -> Result<BitmaskType, XmlError> {
304 let name = require_attr(el, "name")?.to_string();
305 let bit_bound = el.attribute("bitBound").map(parse_ulong).transpose()?;
306 let mut bit_values = Vec::new();
307 for child in el.children_named("bit_value") {
308 let n = require_attr(child, "name")?.to_string();
309 let position = child.attribute("position").map(parse_ulong).transpose()?;
310 bit_values.push(BitValue { name: n, position });
311 }
312 Ok(BitmaskType {
313 name,
314 bit_bound,
315 bit_values,
316 })
317}
318
319fn parse_bitset(el: &XmlElement) -> Result<BitsetType, XmlError> {
320 let name = require_attr(el, "name")?.to_string();
321 let mut bit_fields = Vec::new();
322 for child in el.children_named("bitfield") {
323 let n = require_attr(child, "name")?.to_string();
324 let type_str = require_attr(child, "type")?;
325 let mask = require_attr(child, "mask")?.to_string();
326 bit_fields.push(BitField {
327 name: n,
328 type_ref: parse_type_ref(type_str),
329 mask,
330 });
331 }
332 Ok(BitsetType { name, bit_fields })
333}
334
335fn require_attr<'a>(el: &'a XmlElement, key: &str) -> Result<&'a str, XmlError> {
336 el.attribute(key)
337 .ok_or_else(|| XmlError::MissingRequiredElement(format!("@{key} on <{}>", el.name)))
338}
339
340#[cfg(test)]
341#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
342mod tests {
343 use super::*;
344
345 #[test]
346 fn parse_simple_struct() {
347 let xml = r#"<types>
348 <struct name="State">
349 <member name="id" type="long" key="true"/>
350 </struct>
351 </types>"#;
352 let libs = parse_type_libraries(xml).expect("parse");
353 assert_eq!(libs.len(), 1);
354 let TypeDef::Struct(s) = &libs[0].types[0] else {
355 panic!("expected struct");
356 };
357 assert_eq!(s.name, "State");
358 assert_eq!(s.members.len(), 1);
359 assert!(s.members[0].key);
360 }
361
362 #[test]
363 fn parse_module_nested() {
364 let xml = r#"<types>
365 <module name="Outer">
366 <module name="Inner">
367 <struct name="X"/>
368 </module>
369 </module>
370 </types>"#;
371 let libs = parse_type_libraries(xml).expect("parse");
372 let TypeDef::Module(m) = &libs[0].types[0] else {
373 panic!()
374 };
375 assert_eq!(m.name, "Outer");
376 let TypeDef::Module(inner) = &m.types[0] else {
377 panic!()
378 };
379 assert_eq!(inner.name, "Inner");
380 }
381
382 #[test]
383 fn dds_root_with_multiple_types_blocks() {
384 let xml = r#"<dds>
385 <types><struct name="A"/></types>
386 <types><struct name="B"/></types>
387 </dds>"#;
388 let libs = parse_type_libraries(xml).expect("parse");
389 assert_eq!(libs.len(), 2);
390 }
391
392 #[test]
393 fn unknown_root_rejected() {
394 let xml = r#"<other/>"#;
395 let err = parse_type_libraries(xml).expect_err("err");
396 assert!(matches!(err, XmlError::InvalidXml(_)));
397 }
398
399 #[test]
402 fn parse_include_element() {
403 let xml = r#"<types>
404 <include file="shared/common.xml"/>
405 <struct name="Local"/>
406 </types>"#;
407 let libs = parse_type_libraries(xml).expect("parse");
408 assert_eq!(libs[0].types.len(), 2);
409 let TypeDef::Include(inc) = &libs[0].types[0] else {
410 panic!("expected Include");
411 };
412 assert_eq!(inc.file, "shared/common.xml");
413 }
414
415 #[test]
416 fn parse_forward_dcl_element() {
417 let xml = r#"<types>
418 <forward_dcl name="Node" kind="STRUCT"/>
419 <struct name="Node">
420 <member name="payload" type="long"/>
421 </struct>
422 </types>"#;
423 let libs = parse_type_libraries(xml).expect("parse");
424 let TypeDef::ForwardDcl(fwd) = &libs[0].types[0] else {
425 panic!("expected ForwardDcl");
426 };
427 assert_eq!(fwd.name, "Node");
428 assert_eq!(fwd.kind, "STRUCT");
429 }
430
431 #[test]
432 fn parse_forward_dcl_default_kind_struct() {
433 let xml = r#"<types>
434 <forward_dcl name="X"/>
435 </types>"#;
436 let libs = parse_type_libraries(xml).expect("parse");
437 let TypeDef::ForwardDcl(fwd) = &libs[0].types[0] else {
438 panic!("expected ForwardDcl");
439 };
440 assert_eq!(fwd.kind, "STRUCT");
441 }
442
443 #[test]
444 fn parse_const_element() {
445 let xml = r#"<types>
446 <const name="MaxSize" type="long" value="1024"/>
447 <const name="Greeting" type="string" value="hello"/>
448 </types>"#;
449 let libs = parse_type_libraries(xml).expect("parse");
450 assert_eq!(libs[0].types.len(), 2);
451 let TypeDef::Const(c1) = &libs[0].types[0] else {
452 panic!("expected Const");
453 };
454 assert_eq!(c1.name, "MaxSize");
455 assert_eq!(c1.type_name, "long");
456 assert_eq!(c1.value, "1024");
457 let TypeDef::Const(c2) = &libs[0].types[1] else {
458 panic!("expected Const");
459 };
460 assert_eq!(c2.value, "hello");
461 }
462
463 #[test]
464 fn parse_const_missing_value_attribute_rejected() {
465 let xml = r#"<types>
466 <const name="X" type="long"/>
467 </types>"#;
468 let res = parse_type_libraries(xml);
469 assert!(res.is_err());
470 }
471
472 #[test]
473 fn parse_include_missing_file_attribute_rejected() {
474 let xml = r#"<types>
475 <include/>
476 </types>"#;
477 let res = parse_type_libraries(xml);
478 assert!(res.is_err());
479 }
480}