1use std::cell::Cell;
4use std::collections::{HashMap, HashSet, hash_map::Entry as HashMapEntry};
5
6use tracing::{debug, trace, warn};
7use viva_genapi_xml::{
8 AccessMode, Addressing, EnumEntryDecl, EnumValueSrc, NodeDecl, Visibility, XmlModel,
9};
10
11use crate::bitops::{extract, insert};
12use crate::conversions::{
13 apply_scale, bytes_to_i64, encode_bitfield_value, encode_float, get_raw_or_read, i64_to_bytes,
14 interpret_bitfield_value, map_bitops_error, round_to_i64,
15};
16use crate::nodes::{
17 BooleanNode, CategoryNode, CommandNode, ConverterNode, EnumMapping, EnumNode, FloatNode,
18 IntConverterNode, IntegerNode, Node, SkNode, StringNode,
19};
20use crate::swissknife::{
21 EvalError as SkEvalError, collect_identifiers, evaluate as eval_ast, parse_expression,
22};
23use crate::{GenApiError, RegisterIo, SkOutput};
24
25#[derive(Debug)]
28pub struct NodeMap {
29 version: String,
30 nodes: HashMap<String, Node>,
31 dependents: HashMap<String, Vec<String>>,
32 generation: Cell<u64>,
33}
34
35fn register_addressing_dependency(
36 dependents: &mut HashMap<String, Vec<String>>,
37 node_name: &str,
38 addressing: &Addressing,
39) {
40 match addressing {
41 Addressing::Fixed { .. } => {}
42 Addressing::BySelector { selector, .. } => {
43 dependents
44 .entry(selector.clone())
45 .or_default()
46 .push(node_name.to_string());
47 }
48 Addressing::Indirect { p_address_node, .. } => {
49 dependents
50 .entry(p_address_node.clone())
51 .or_default()
52 .push(node_name.to_string());
53 }
54 }
55}
56
57fn ensure_readable(access: &AccessMode, name: &str) -> Result<(), GenApiError> {
58 if matches!(access, AccessMode::WO) {
59 return Err(GenApiError::Access(name.to_string()));
60 }
61 Ok(())
62}
63
64fn ensure_writable(access: &AccessMode, name: &str) -> Result<(), GenApiError> {
65 if matches!(access, AccessMode::RO) {
66 return Err(GenApiError::Access(name.to_string()));
67 }
68 Ok(())
69}
70
71impl NodeMap {
72 pub fn version(&self) -> &str {
74 &self.version
75 }
76
77 pub fn node(&self, name: &str) -> Option<&Node> {
79 self.nodes.get(name)
80 }
81
82 pub fn node_names(&self) -> impl Iterator<Item = &str> {
84 self.nodes.keys().map(|s| s.as_str())
85 }
86
87 pub fn dependents(&self, name: &str) -> &[String] {
91 self.dependents
92 .get(name)
93 .map(|v| v.as_slice())
94 .unwrap_or(&[])
95 }
96
97 pub fn categories(&self) -> Vec<(&str, &[String])> {
99 self.nodes
100 .values()
101 .filter_map(|node| match node {
102 Node::Category(cat) => Some((cat.name.as_str(), cat.children.as_slice())),
103 _ => None,
104 })
105 .collect()
106 }
107
108 pub fn nodes_at_visibility(&self, level: Visibility) -> Vec<&str> {
113 self.nodes
114 .iter()
115 .filter(|(_, node)| node.visibility() <= level)
116 .map(|(name, _)| name.as_str())
117 .collect()
118 }
119
120 pub fn try_from_xml(model: XmlModel) -> Result<Self, GenApiError> {
122 let mut nodes = HashMap::new();
123 let mut dependents: HashMap<String, Vec<String>> = HashMap::new();
124 for decl in model.nodes {
125 match decl {
126 NodeDecl::Integer {
127 name,
128 meta,
129 addressing,
130 len,
131 access,
132 min,
133 max,
134 inc,
135 unit,
136 bitfield,
137 selectors,
138 selected_if,
139 pvalue,
140 p_max,
141 p_min,
142 value,
143 } => {
144 if let Some(ref addr) = addressing {
145 register_addressing_dependency(&mut dependents, &name, addr);
146 }
147 if let Some(ref pv) = pvalue {
148 dependents.entry(pv.clone()).or_default().push(name.clone());
149 }
150 if let Some(ref pm) = p_max {
151 dependents.entry(pm.clone()).or_default().push(name.clone());
152 }
153 if let Some(ref pm) = p_min {
154 dependents.entry(pm.clone()).or_default().push(name.clone());
155 }
156 for (selector, _) in &selected_if {
157 dependents
158 .entry(selector.clone())
159 .or_default()
160 .push(name.clone());
161 }
162 let node = IntegerNode {
163 name: name.clone(),
164 meta,
165 addressing,
166 len,
167 access,
168 min,
169 max,
170 inc,
171 unit,
172 bitfield,
173 selectors,
174 selected_if,
175 pvalue,
176 p_max,
177 p_min,
178 value,
179 cache: std::cell::RefCell::new(None),
180 raw_cache: std::cell::RefCell::new(None),
181 };
182 nodes.insert(name, Node::Integer(node));
183 }
184 NodeDecl::Float {
185 name,
186 meta,
187 addressing,
188 access,
189 min,
190 max,
191 unit,
192 scale,
193 offset,
194 selectors,
195 selected_if,
196 pvalue,
197 } => {
198 if let Some(ref addr) = addressing {
199 register_addressing_dependency(&mut dependents, &name, addr);
200 }
201 if let Some(ref pv) = pvalue {
202 dependents.entry(pv.clone()).or_default().push(name.clone());
203 }
204 for (selector, _) in &selected_if {
205 dependents
206 .entry(selector.clone())
207 .or_default()
208 .push(name.clone());
209 }
210 let node = FloatNode {
211 name: name.clone(),
212 meta,
213 addressing,
214 access,
215 min,
216 max,
217 unit,
218 scale,
219 offset,
220 selectors,
221 selected_if,
222 pvalue,
223 cache: std::cell::RefCell::new(None),
224 };
225 nodes.insert(name, Node::Float(node));
226 }
227 NodeDecl::Enum {
228 name,
229 meta,
230 addressing,
231 access,
232 entries,
233 default,
234 selectors,
235 selected_if,
236 pvalue,
237 } => {
238 if let Some(ref addr) = addressing {
239 register_addressing_dependency(&mut dependents, &name, addr);
240 }
241 if let Some(ref pv) = pvalue {
242 dependents.entry(pv.clone()).or_default().push(name.clone());
243 }
244 for (selector, _) in &selected_if {
245 dependents
246 .entry(selector.clone())
247 .or_default()
248 .push(name.clone());
249 }
250 let mut providers = Vec::new();
251 let mut provider_set = HashSet::new();
252 for entry in &entries {
253 if let EnumValueSrc::FromNode(node_name) = &entry.value {
254 dependents
255 .entry(node_name.clone())
256 .or_default()
257 .push(name.clone());
258 if provider_set.insert(node_name.clone()) {
259 providers.push(node_name.clone());
260 }
261 }
262 }
263 providers.sort();
264 let node = EnumNode {
265 name: name.clone(),
266 meta,
267 addressing,
268 access,
269 pvalue,
270 entries,
271 default,
272 selectors,
273 selected_if,
274 providers,
275 value_cache: std::cell::RefCell::new(None),
276 mapping_cache: std::cell::RefCell::new(None),
277 };
278 nodes.insert(name, Node::Enum(node));
279 }
280 NodeDecl::Boolean {
281 name,
282 meta,
283 addressing,
284 len,
285 access,
286 bitfield,
287 selectors,
288 selected_if,
289 pvalue,
290 on_value,
291 off_value,
292 } => {
293 if let Some(ref addr) = addressing {
294 register_addressing_dependency(&mut dependents, &name, addr);
295 }
296 if let Some(ref pv) = pvalue {
297 dependents.entry(pv.clone()).or_default().push(name.clone());
298 }
299 for (selector, _) in &selected_if {
300 dependents
301 .entry(selector.clone())
302 .or_default()
303 .push(name.clone());
304 }
305 let node = BooleanNode {
306 name: name.clone(),
307 meta,
308 addressing,
309 len,
310 access,
311 bitfield,
312 selectors,
313 selected_if,
314 pvalue,
315 on_value,
316 off_value,
317 cache: std::cell::RefCell::new(None),
318 raw_cache: std::cell::RefCell::new(None),
319 };
320 nodes.insert(name, Node::Boolean(node));
321 }
322 NodeDecl::Command {
323 name,
324 meta,
325 address,
326 len,
327 pvalue,
328 command_value,
329 } => {
330 if let Some(ref pv) = pvalue {
331 dependents.entry(pv.clone()).or_default().push(name.clone());
332 }
333 let node = CommandNode {
334 name: name.clone(),
335 meta,
336 address,
337 len,
338 pvalue,
339 command_value,
340 };
341 nodes.insert(name, Node::Command(node));
342 }
343 NodeDecl::Category {
344 name,
345 meta,
346 children,
347 } => {
348 let node = CategoryNode {
349 name: name.clone(),
350 meta,
351 children,
352 };
353 nodes.insert(name, Node::Category(node));
354 }
355 NodeDecl::SwissKnife(decl) => {
356 let name = decl.name;
357 let meta = decl.meta;
358 let expr = decl.expr;
359 let variables = decl.variables;
360 let output = decl.output;
361 let ast = parse_expression(&expr).map_err(|err| GenApiError::ExprParse {
362 name: name.clone(),
363 msg: err.to_string(),
364 })?;
365 let mut used = HashSet::new();
366 collect_identifiers(&ast, &mut used);
367 for ident in &used {
368 if !variables.iter().any(|(var, _)| var == ident) {
369 return Err(GenApiError::UnknownVariable {
370 name: name.clone(),
371 var: ident.clone(),
372 });
373 }
374 }
375 for (_, provider) in &variables {
376 dependents
377 .entry(provider.clone())
378 .or_default()
379 .push(name.clone());
380 }
381 let node = SkNode {
382 name: name.clone(),
383 meta,
384 output,
385 ast,
386 vars: variables,
387 cache: std::cell::RefCell::new(None),
388 };
389 nodes.insert(name, Node::SwissKnife(node));
390 }
391 NodeDecl::Converter(decl) => {
392 let name = decl.name;
393 let ast_to = parse_expression(&decl.formula_to).map_err(|err| {
394 GenApiError::ExprParse {
395 name: name.clone(),
396 msg: format!("FormulaTo: {err}"),
397 }
398 })?;
399 let ast_from = parse_expression(&decl.formula_from).map_err(|err| {
400 GenApiError::ExprParse {
401 name: name.clone(),
402 msg: format!("FormulaFrom: {err}"),
403 }
404 })?;
405 for (_, provider) in &decl.variables_to {
407 dependents
408 .entry(provider.clone())
409 .or_default()
410 .push(name.clone());
411 }
412 for (_, provider) in &decl.variables_from {
413 if !decl.variables_to.iter().any(|(_, p)| p == provider) {
414 dependents
415 .entry(provider.clone())
416 .or_default()
417 .push(name.clone());
418 }
419 }
420 dependents
422 .entry(decl.p_value.clone())
423 .or_default()
424 .push(name.clone());
425 let node = ConverterNode {
426 name: name.clone(),
427 meta: decl.meta,
428 p_value: decl.p_value,
429 ast_to,
430 ast_from,
431 vars_to: decl.variables_to,
432 vars_from: decl.variables_from,
433 unit: decl.unit,
434 output: decl.output,
435 cache: std::cell::RefCell::new(None),
436 };
437 nodes.insert(name, Node::Converter(node));
438 }
439 NodeDecl::IntConverter(decl) => {
440 let name = decl.name;
441 let ast_to = parse_expression(&decl.formula_to).map_err(|err| {
442 GenApiError::ExprParse {
443 name: name.clone(),
444 msg: format!("FormulaTo: {err}"),
445 }
446 })?;
447 let ast_from = parse_expression(&decl.formula_from).map_err(|err| {
448 GenApiError::ExprParse {
449 name: name.clone(),
450 msg: format!("FormulaFrom: {err}"),
451 }
452 })?;
453 for (_, provider) in &decl.variables_to {
454 dependents
455 .entry(provider.clone())
456 .or_default()
457 .push(name.clone());
458 }
459 for (_, provider) in &decl.variables_from {
460 if !decl.variables_to.iter().any(|(_, p)| p == provider) {
461 dependents
462 .entry(provider.clone())
463 .or_default()
464 .push(name.clone());
465 }
466 }
467 dependents
468 .entry(decl.p_value.clone())
469 .or_default()
470 .push(name.clone());
471 let node = IntConverterNode {
472 name: name.clone(),
473 meta: decl.meta,
474 p_value: decl.p_value,
475 ast_to,
476 ast_from,
477 vars_to: decl.variables_to,
478 vars_from: decl.variables_from,
479 unit: decl.unit,
480 cache: std::cell::RefCell::new(None),
481 };
482 nodes.insert(name, Node::IntConverter(node));
483 }
484 NodeDecl::String(decl) => {
485 let name = decl.name;
486 register_addressing_dependency(&mut dependents, &name, &decl.addressing);
487 let node = StringNode {
488 name: name.clone(),
489 meta: decl.meta,
490 addressing: decl.addressing,
491 access: decl.access,
492 cache: std::cell::RefCell::new(None),
493 };
494 nodes.insert(name, Node::String(node));
495 }
496 }
497 }
498
499 Ok(NodeMap {
500 version: model.version,
501 nodes,
502 dependents,
503 generation: Cell::new(0),
504 })
505 }
506
507 pub fn get_integer(&self, name: &str, io: &dyn RegisterIo) -> Result<i64, GenApiError> {
509 if let Some(output) = self.nodes.get(name).and_then(|node| match node {
510 Node::SwissKnife(sk) => Some(sk.output),
511 _ => None,
512 }) {
513 return match output {
514 SkOutput::Integer => {
515 let node = match self.nodes.get(name) {
516 Some(Node::SwissKnife(node)) => node,
517 _ => unreachable!("node vanished during lookup"),
518 };
519 let mut stack = HashSet::new();
520 let value = self.evaluate_swissknife(node, io, &mut stack)?;
521 round_to_i64(name, value)
522 }
523 SkOutput::Float => Err(GenApiError::Type(name.to_string())),
524 };
525 }
526 let node = self.get_integer_node(name)?;
527 ensure_readable(&node.access, name)?;
528 self.ensure_selectors(name, &node.selected_if, io)?;
529 if let Some(v) = node.value {
531 return Ok(v);
532 }
533 if let Some(ref pv) = node.pvalue {
535 let pv = pv.clone();
536 return self.get_integer(&pv, io);
537 }
538 let addressing = node
539 .addressing
540 .as_ref()
541 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
542 let (address, len) = self.resolve_address(name, addressing, io)?;
543 if let Some(value) = *node.cache.borrow() {
544 return Ok(value);
545 }
546 let raw = io.read(address, len as usize).map_err(|err| match err {
547 GenApiError::Io(_) => err,
548 other => other,
549 })?;
550 let value = if let Some(bitfield) = node.bitfield {
551 let extracted = extract(&raw, bitfield).map_err(|err| map_bitops_error(name, err))?;
552 interpret_bitfield_value(name, extracted, bitfield.bit_length, node.min < 0)?
553 } else {
554 bytes_to_i64(name, &raw)?
555 };
556 debug!(node = %name, raw = value, "read integer feature");
557 node.cache.replace(Some(value));
558 node.raw_cache.replace(Some(raw));
559 Ok(value)
560 }
561
562 pub fn set_integer(
564 &mut self,
565 name: &str,
566 value: i64,
567 io: &dyn RegisterIo,
568 ) -> Result<(), GenApiError> {
569 let node = self.get_integer_node(name)?;
570 ensure_writable(&node.access, name)?;
571 self.ensure_selectors(name, &node.selected_if, io)?;
572 if let Some(ref pv) = node.pvalue {
573 let pv = pv.clone();
574 return self.set_integer(&pv, value, io);
575 }
576 let addressing = node
577 .addressing
578 .as_ref()
579 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
580 let (address, len) = self.resolve_address(name, addressing, io)?;
581 if value < node.min || value > node.max {
582 return Err(GenApiError::Range(name.to_string()));
583 }
584 if let Some(inc) = node.inc
585 && inc != 0
586 && (value - node.min) % inc != 0
587 {
588 return Err(GenApiError::Range(name.to_string()));
589 }
590 if let Some(bitfield) = node.bitfield {
591 let encoded = encode_bitfield_value(name, value, bitfield.bit_length, node.min < 0)?;
592 let mut raw = get_raw_or_read(&node.raw_cache, io, address, len)?;
593 insert(&mut raw, bitfield, encoded).map_err(|err| map_bitops_error(name, err))?;
594 debug!(node = %name, raw = value, "write integer feature");
595 io.write(address, &raw).map_err(|err| match err {
596 GenApiError::Io(_) => err,
597 other => other,
598 })?;
599 node.cache.replace(Some(value));
600 node.raw_cache.replace(Some(raw));
601 } else {
602 let bytes = i64_to_bytes(name, value, len)?;
603 debug!(node = %name, raw = value, "write integer feature");
604 io.write(address, &bytes).map_err(|err| match err {
605 GenApiError::Io(_) => err,
606 other => other,
607 })?;
608 node.cache.replace(Some(value));
609 node.raw_cache.replace(Some(bytes));
610 }
611 self.invalidate_dependents(name);
612 Ok(())
613 }
614
615 pub fn get_float(&self, name: &str, io: &dyn RegisterIo) -> Result<f64, GenApiError> {
617 if let Some(output) = self.nodes.get(name).and_then(|node| match node {
618 Node::SwissKnife(sk) => Some(sk.output),
619 _ => None,
620 }) {
621 return match output {
622 SkOutput::Float => {
623 let node = match self.nodes.get(name) {
624 Some(Node::SwissKnife(node)) => node,
625 _ => unreachable!("node vanished during lookup"),
626 };
627 let mut stack = HashSet::new();
628 let value = self.evaluate_swissknife(node, io, &mut stack)?;
629 Ok(value)
630 }
631 SkOutput::Integer => self.get_integer(name, io).map(|v| v as f64),
632 };
633 }
634 let node = self.get_float_node(name)?;
635 ensure_readable(&node.access, name)?;
636 self.ensure_selectors(name, &node.selected_if, io)?;
637 if let Some(ref pv) = node.pvalue {
638 let pv = pv.clone();
639 return self.get_float(&pv, io);
640 }
641 let addressing = node
642 .addressing
643 .as_ref()
644 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
645 let (address, len) = self.resolve_address(name, addressing, io)?;
646 if let Some(value) = *node.cache.borrow() {
647 return Ok(value);
648 }
649 let raw = io.read(address, len as usize).map_err(|err| match err {
650 GenApiError::Io(_) => err,
651 other => other,
652 })?;
653 let raw_value = bytes_to_i64(name, &raw)?;
654 let value = apply_scale(node, raw_value as f64);
655 debug!(node = %name, raw = raw_value, value, "read float feature");
656 node.cache.replace(Some(value));
657 Ok(value)
658 }
659
660 pub fn set_float(
662 &mut self,
663 name: &str,
664 value: f64,
665 io: &dyn RegisterIo,
666 ) -> Result<(), GenApiError> {
667 let node = self.get_float_node(name)?;
668 ensure_writable(&node.access, name)?;
669 self.ensure_selectors(name, &node.selected_if, io)?;
670 if let Some(ref pv) = node.pvalue {
671 let pv = pv.clone();
672 return self.set_float(&pv, value, io);
673 }
674 let addressing = node
675 .addressing
676 .as_ref()
677 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
678 let (address, len) = self.resolve_address(name, addressing, io)?;
679 if value < node.min || value > node.max {
680 return Err(GenApiError::Range(name.to_string()));
681 }
682 let raw = encode_float(node, value)?;
683 let bytes = i64_to_bytes(name, raw, len)?;
684 debug!(node = %name, raw, value, "write float feature");
685 io.write(address, &bytes).map_err(|err| match err {
686 GenApiError::Io(_) => err,
687 other => other,
688 })?;
689 node.cache.replace(Some(value));
690 self.invalidate_dependents(name);
691 Ok(())
692 }
693
694 pub fn get_enum(&self, name: &str, io: &dyn RegisterIo) -> Result<String, GenApiError> {
696 let node = self.get_enum_node(name)?;
697 ensure_readable(&node.access, name)?;
698 self.ensure_selectors(name, &node.selected_if, io)?;
699 if let Some(ref pv) = node.pvalue {
701 let pv = pv.clone();
702 if let Some(value) = node.value_cache.borrow().clone() {
703 return Ok(value);
704 }
705 let raw_value = self.get_integer(&pv, io)?;
706 let entry = self.lookup_enum_entry(node, raw_value, io)?;
707 node.value_cache.replace(Some(entry.clone()));
708 return Ok(entry);
709 }
710 let addressing = node
711 .addressing
712 .as_ref()
713 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing")))?;
714 let (address, len) = self.resolve_address(name, addressing, io)?;
715 if let Some(value) = node.value_cache.borrow().clone() {
716 return Ok(value);
717 }
718 let raw = io.read(address, len as usize).map_err(|err| match err {
719 GenApiError::Io(_) => err,
720 other => other,
721 })?;
722 let raw_value = bytes_to_i64(name, &raw)?;
723 let entry = self.lookup_enum_entry(node, raw_value, io)?;
724 debug!(node = %name, raw = raw_value, entry = %entry, "read enum feature");
725 node.value_cache.replace(Some(entry.clone()));
726 Ok(entry)
727 }
728
729 pub fn set_enum(
731 &mut self,
732 name: &str,
733 entry: &str,
734 io: &dyn RegisterIo,
735 ) -> Result<(), GenApiError> {
736 let node = self.get_enum_node(name)?;
737 ensure_writable(&node.access, name)?;
738 self.ensure_selectors(name, &node.selected_if, io)?;
739 if let Some(ref pv) = node.pvalue {
740 let pv = pv.clone();
741 let entry_decl = node
742 .entries
743 .iter()
744 .find(|candidate| candidate.name == entry)
745 .ok_or_else(|| GenApiError::EnumNoSuchEntry {
746 node: name.to_string(),
747 entry: entry.to_string(),
748 })?;
749 let raw_value = self.resolve_enum_entry_value(node, entry_decl, io)?;
750 let entry_str = entry.to_string();
751 self.set_integer(&pv, raw_value, io)?;
753 let node = self.get_enum_node(name)?;
754 node.value_cache.replace(Some(entry_str));
755 node.invalidate();
756 self.invalidate_dependents(name);
757 return Ok(());
758 }
759 let addressing = node
760 .addressing
761 .as_ref()
762 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing")))?;
763 let (address, len) = self.resolve_address(name, addressing, io)?;
764 let entry_decl = node
765 .entries
766 .iter()
767 .find(|candidate| candidate.name == entry)
768 .ok_or_else(|| GenApiError::EnumNoSuchEntry {
769 node: name.to_string(),
770 entry: entry.to_string(),
771 })?;
772 let raw = self.resolve_enum_entry_value(node, entry_decl, io)?;
773 let bytes = i64_to_bytes(name, raw, len)?;
774 debug!(node = %name, raw, entry, "write enum feature");
775 io.write(address, &bytes).map_err(|err| match err {
776 GenApiError::Io(_) => err,
777 other => other,
778 })?;
779 node.value_cache.replace(None);
780 self.invalidate_dependents(name);
781 Ok(())
782 }
783
784 pub fn enum_entries(&self, name: &str) -> Result<Vec<String>, GenApiError> {
786 let node = self.get_enum_node(name)?;
787 if let Some(mapping) = node.mapping_cache.borrow().as_ref() {
788 let mut names: Vec<_> = mapping.by_name.keys().cloned().collect();
789 names.sort();
790 names.dedup();
791 return Ok(names);
792 }
793 let mut names: Vec<_> = node
794 .entries
795 .iter()
796 .map(|entry| entry.name.clone())
797 .collect();
798 names.sort();
799 names.dedup();
800 Ok(names)
801 }
802
803 pub fn get_bool(&self, name: &str, io: &dyn RegisterIo) -> Result<bool, GenApiError> {
805 let node = self.get_bool_node(name)?;
806 ensure_readable(&node.access, name)?;
807 self.ensure_selectors(name, &node.selected_if, io)?;
808 if let Some(ref pv) = node.pvalue {
809 let pv = pv.clone();
810 let raw = self.get_integer(&pv, io)?;
811 let on = node.on_value.unwrap_or(1);
812 return Ok(raw == on);
813 }
814 let addressing = node
815 .addressing
816 .as_ref()
817 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
818 let bitfield = node
819 .bitfield
820 .ok_or_else(|| GenApiError::Parse(format!("{name}: boolean without bitfield")))?;
821 let (address, len) = self.resolve_address(name, addressing, io)?;
822 if let Some(value) = *node.cache.borrow() {
823 return Ok(value);
824 }
825 let raw = io.read(address, len as usize).map_err(|err| match err {
826 GenApiError::Io(_) => err,
827 other => other,
828 })?;
829 let raw_value = extract(&raw, bitfield).map_err(|err| map_bitops_error(name, err))?;
830 let value = raw_value != 0;
831 debug!(node = %name, raw = raw_value, value, "read boolean feature");
832 node.cache.replace(Some(value));
833 node.raw_cache.replace(Some(raw));
834 Ok(value)
835 }
836
837 pub fn set_bool(
839 &mut self,
840 name: &str,
841 value: bool,
842 io: &dyn RegisterIo,
843 ) -> Result<(), GenApiError> {
844 let node = self.get_bool_node(name)?;
845 ensure_writable(&node.access, name)?;
846 self.ensure_selectors(name, &node.selected_if, io)?;
847 if let Some(ref pv) = node.pvalue {
848 let pv = pv.clone();
849 let on = node.on_value.unwrap_or(1);
850 let off = node.off_value.unwrap_or(0);
851 let raw = if value { on } else { off };
852 return self.set_integer(&pv, raw, io);
853 }
854 let addressing = node
855 .addressing
856 .as_ref()
857 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
858 let bitfield = node
859 .bitfield
860 .ok_or_else(|| GenApiError::Parse(format!("{name}: boolean without bitfield")))?;
861 let (address, len) = self.resolve_address(name, addressing, io)?;
862 let encoded = if value { 1 } else { 0 };
863 let mut raw = get_raw_or_read(&node.raw_cache, io, address, len)?;
864 insert(&mut raw, bitfield, encoded).map_err(|err| map_bitops_error(name, err))?;
865 debug!(node = %name, raw = encoded, value, "write boolean feature");
866 io.write(address, &raw).map_err(|err| match err {
867 GenApiError::Io(_) => err,
868 other => other,
869 })?;
870 node.cache.replace(Some(value));
871 node.raw_cache.replace(Some(raw));
872 self.invalidate_dependents(name);
873 Ok(())
874 }
875
876 pub fn exec_command(&mut self, name: &str, io: &dyn RegisterIo) -> Result<(), GenApiError> {
878 let node = self.get_command_node(name)?;
879 let cmd_value = node.command_value.unwrap_or(1);
881
882 if let Some(ref pv) = node.pvalue {
883 let pv = pv.clone();
885 debug!(node = %name, "execute command via pValue");
886 return self.set_integer(&pv, cmd_value, io);
887 }
888
889 let address = node
890 .address
891 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no address or pValue")))?;
892 if node.len == 0 {
893 return Err(GenApiError::Parse(format!(
894 "command node {name} has zero length"
895 )));
896 }
897 let data = i64_to_bytes(name, cmd_value, node.len)?;
898 debug!(node = %name, "execute command");
899 io.write(address, &data).map_err(|err| match err {
900 GenApiError::Io(_) => err,
901 other => other,
902 })?;
903 self.invalidate_dependents(name);
904 Ok(())
905 }
906
907 fn get_integer_node(&self, name: &str) -> Result<&IntegerNode, GenApiError> {
908 match self.nodes.get(name) {
909 Some(Node::Integer(node)) => Ok(node),
910 Some(_) => Err(GenApiError::Type(name.to_string())),
911 None => Err(GenApiError::NodeNotFound(name.to_string())),
912 }
913 }
914
915 fn get_float_node(&self, name: &str) -> Result<&FloatNode, GenApiError> {
916 match self.nodes.get(name) {
917 Some(Node::Float(node)) => Ok(node),
918 Some(_) => Err(GenApiError::Type(name.to_string())),
919 None => Err(GenApiError::NodeNotFound(name.to_string())),
920 }
921 }
922
923 fn get_enum_node(&self, name: &str) -> Result<&EnumNode, GenApiError> {
924 match self.nodes.get(name) {
925 Some(Node::Enum(node)) => Ok(node),
926 Some(_) => Err(GenApiError::Type(name.to_string())),
927 None => Err(GenApiError::NodeNotFound(name.to_string())),
928 }
929 }
930
931 fn get_bool_node(&self, name: &str) -> Result<&BooleanNode, GenApiError> {
932 match self.nodes.get(name) {
933 Some(Node::Boolean(node)) => Ok(node),
934 Some(_) => Err(GenApiError::Type(name.to_string())),
935 None => Err(GenApiError::NodeNotFound(name.to_string())),
936 }
937 }
938
939 fn get_command_node(&self, name: &str) -> Result<&CommandNode, GenApiError> {
940 match self.nodes.get(name) {
941 Some(Node::Command(node)) => Ok(node),
942 Some(_) => Err(GenApiError::Type(name.to_string())),
943 None => Err(GenApiError::NodeNotFound(name.to_string())),
944 }
945 }
946
947 fn ensure_selectors(
948 &self,
949 node_name: &str,
950 rules: &[(String, Vec<String>)],
951 io: &dyn RegisterIo,
952 ) -> Result<(), GenApiError> {
953 for (selector, allowed) in rules {
954 if allowed.is_empty() {
955 continue;
956 }
957 let current = self.get_selector_value(selector, io)?;
958 if !allowed.iter().any(|value| value == ¤t) {
959 return Err(GenApiError::Unavailable(format!(
960 "node '{node_name}' unavailable for selector '{selector}={current}'"
961 )));
962 }
963 }
964 Ok(())
965 }
966
967 fn lookup_enum_entry(
968 &self,
969 node: &EnumNode,
970 raw_value: i64,
971 io: &dyn RegisterIo,
972 ) -> Result<String, GenApiError> {
973 {
974 let mut cache = node.mapping_cache.borrow_mut();
975 if cache.is_none() {
976 *cache = Some(self.build_enum_mapping(node, io)?);
977 }
978 if let Some(mapping) = cache.as_ref()
979 && let Some(entry) = mapping.by_value.get(&raw_value)
980 {
981 return Ok(entry.clone());
982 }
983 *cache = Some(self.build_enum_mapping(node, io)?);
984 if let Some(mapping) = cache.as_ref()
985 && let Some(entry) = mapping.by_value.get(&raw_value)
986 {
987 return Ok(entry.clone());
988 }
989 }
990 Err(GenApiError::EnumValueUnknown {
991 node: node.name.clone(),
992 value: raw_value,
993 })
994 }
995
996 fn build_enum_mapping(
997 &self,
998 node: &EnumNode,
999 io: &dyn RegisterIo,
1000 ) -> Result<EnumMapping, GenApiError> {
1001 let mut by_value = HashMap::new();
1002 let mut by_name = HashMap::new();
1003
1004 for entry in &node.entries {
1005 let value = self.resolve_enum_entry_value(node, entry, io)?;
1006 match by_value.entry(value) {
1007 HashMapEntry::Vacant(slot) => {
1008 slot.insert(entry.name.clone());
1009 }
1010 HashMapEntry::Occupied(existing) => {
1011 warn!(
1012 enum_node = %node.name,
1013 value,
1014 kept = %existing.get(),
1015 dropped = %entry.name,
1016 "duplicate enum value"
1017 );
1018 }
1019 }
1020 by_name.insert(entry.name.clone(), value);
1021 }
1022
1023 let mut summary: Vec<_> = by_value
1024 .iter()
1025 .map(|(value, name)| (*value, name.clone()))
1026 .collect();
1027 summary.sort_by_key(|(value, _)| *value);
1028 debug!(node = %node.name, entries = ?summary, "build enum mapping");
1029
1030 Ok(EnumMapping { by_value, by_name })
1031 }
1032
1033 fn resolve_enum_entry_value(
1034 &self,
1035 node: &EnumNode,
1036 entry: &EnumEntryDecl,
1037 io: &dyn RegisterIo,
1038 ) -> Result<i64, GenApiError> {
1039 match &entry.value {
1040 EnumValueSrc::Literal(value) => Ok(*value),
1041 EnumValueSrc::FromNode(provider) => {
1042 let value = self.get_integer(provider, io)?;
1043 trace!(
1044 enum_node = %node.name,
1045 entry = %entry.name,
1046 provider = %provider,
1047 value,
1048 "resolved enum entry from provider"
1049 );
1050 Ok(value)
1051 }
1052 }
1053 }
1054
1055 fn resolve_address(
1056 &self,
1057 node_name: &str,
1058 addressing: &Addressing,
1059 io: &dyn RegisterIo,
1060 ) -> Result<(u64, u32), GenApiError> {
1061 match addressing {
1062 Addressing::Fixed { address, len } => Ok((*address, *len)),
1063 Addressing::BySelector { selector, map } => {
1064 let value = self.get_selector_value(selector, io)?;
1065 if let Some((_, (address, len))) = map.iter().find(|(name, _)| name == &value) {
1066 let addr = *address;
1067 let len = *len;
1068 debug!(
1069 node = %node_name,
1070 selector = %selector,
1071 value = %value,
1072 address = format_args!("0x{addr:X}"),
1073 len,
1074 "resolve address via selector"
1075 );
1076 Ok((addr, len))
1077 } else {
1078 Err(GenApiError::Unavailable(format!(
1079 "node '{node_name}' unavailable for selector '{selector}={value}'"
1080 )))
1081 }
1082 }
1083 Addressing::Indirect {
1084 p_address_node,
1085 len,
1086 } => {
1087 let addr_value = self.get_integer(p_address_node, io)?;
1088 if addr_value <= 0 {
1089 return Err(GenApiError::BadIndirectAddress {
1090 name: node_name.to_string(),
1091 addr: addr_value,
1092 });
1093 }
1094 let addr =
1095 u64::try_from(addr_value).map_err(|_| GenApiError::BadIndirectAddress {
1096 name: node_name.to_string(),
1097 addr: addr_value,
1098 })?;
1099 if addr == 0 {
1100 return Err(GenApiError::BadIndirectAddress {
1101 name: node_name.to_string(),
1102 addr: addr_value,
1103 });
1104 }
1105 debug!(
1106 node = %node_name,
1107 source = %p_address_node,
1108 address = format_args!("0x{addr:X}"),
1109 len = *len,
1110 "resolve address via pAddress"
1111 );
1112 Ok((addr, *len))
1113 }
1114 }
1115 }
1116
1117 fn get_selector_value(
1118 &self,
1119 selector: &str,
1120 io: &dyn RegisterIo,
1121 ) -> Result<String, GenApiError> {
1122 match self.nodes.get(selector) {
1123 Some(Node::Enum(_)) => self.get_enum(selector, io),
1124 Some(Node::Boolean(_)) => Ok(self.get_bool(selector, io)?.to_string()),
1125 Some(Node::Integer(_)) => Ok(self.get_integer(selector, io)?.to_string()),
1126 Some(_) => Err(GenApiError::Parse(format!(
1127 "selector {selector} has unsupported type"
1128 ))),
1129 None => Err(GenApiError::NodeNotFound(selector.to_string())),
1130 }
1131 }
1132
1133 fn evaluate_swissknife(
1134 &self,
1135 node: &SkNode,
1136 io: &dyn RegisterIo,
1137 stack: &mut HashSet<String>,
1138 ) -> Result<f64, GenApiError> {
1139 if let Some((value, generation)) = *node.cache.borrow()
1140 && generation == self.generation.get()
1141 {
1142 return Ok(value);
1143 }
1144 if !stack.insert(node.name.clone()) {
1145 stack.remove(&node.name);
1146 return Err(GenApiError::ExprEval {
1147 name: node.name.clone(),
1148 msg: "cyclic dependency".into(),
1149 });
1150 }
1151 let current_gen = self.generation.get();
1152 let result = (|| {
1153 let mut values: HashMap<String, f64> = HashMap::new();
1154 let mut inputs = Vec::new();
1155 for (var, provider) in &node.vars {
1156 let value = self.resolve_numeric(provider, io, stack)?;
1157 values.insert(var.clone(), value);
1158 inputs.push((var.clone(), value));
1159 }
1160 let mut resolver = |ident: &str| -> Result<f64, SkEvalError> {
1161 values
1162 .get(ident)
1163 .copied()
1164 .ok_or_else(|| SkEvalError::UnknownVariable(ident.to_string()))
1165 };
1166 let value = match eval_ast(&node.ast, &mut resolver) {
1167 Ok(value) => value,
1168 Err(SkEvalError::UnknownVariable(var)) => {
1169 return Err(GenApiError::UnknownVariable {
1170 name: node.name.clone(),
1171 var,
1172 });
1173 }
1174 Err(SkEvalError::DivisionByZero) => {
1175 return Err(GenApiError::ExprEval {
1176 name: node.name.clone(),
1177 msg: "division by zero".into(),
1178 });
1179 }
1180 Err(SkEvalError::UnknownFunction(func)) => {
1181 return Err(GenApiError::ExprEval {
1182 name: node.name.clone(),
1183 msg: format!("unknown function: {func}"),
1184 });
1185 }
1186 Err(SkEvalError::ArityMismatch {
1187 name: func,
1188 expected,
1189 got,
1190 }) => {
1191 return Err(GenApiError::ExprEval {
1192 name: node.name.clone(),
1193 msg: format!("function {func} expects {expected} args, got {got}"),
1194 });
1195 }
1196 };
1197 debug!(node = %node.name, inputs = ?inputs, output = value, "evaluate SwissKnife");
1198 Ok(value)
1199 })();
1200 stack.remove(&node.name);
1201 match result {
1202 Ok(value) => {
1203 node.cache.replace(Some((value, current_gen)));
1204 Ok(value)
1205 }
1206 Err(err) => Err(err),
1207 }
1208 }
1209
1210 fn resolve_numeric(
1211 &self,
1212 provider: &str,
1213 io: &dyn RegisterIo,
1214 stack: &mut HashSet<String>,
1215 ) -> Result<f64, GenApiError> {
1216 match self.nodes.get(provider) {
1217 Some(Node::Integer(_)) => self.get_integer(provider, io).map(|v| v as f64),
1218 Some(Node::Float(_)) => self.get_float(provider, io),
1219 Some(Node::Boolean(_)) => Ok(if self.get_bool(provider, io)? {
1220 1.0
1221 } else {
1222 0.0
1223 }),
1224 Some(Node::Enum(_)) => self.get_enum_numeric(provider, io).map(|v| v as f64),
1225 Some(Node::SwissKnife(node)) => self.evaluate_swissknife(node, io, stack),
1226 Some(Node::Converter(node)) => self.evaluate_converter(node, io, stack),
1227 Some(Node::IntConverter(node)) => self
1228 .evaluate_int_converter(node, io, stack)
1229 .map(|v| v as f64),
1230 Some(_) => Err(GenApiError::Type(provider.to_string())),
1231 None => Err(GenApiError::NodeNotFound(provider.to_string())),
1232 }
1233 }
1234
1235 fn get_enum_numeric(&self, name: &str, io: &dyn RegisterIo) -> Result<i64, GenApiError> {
1236 let entry = self.get_enum(name, io)?;
1237 let node = self.get_enum_node(name)?;
1238 {
1239 let mut mapping = node.mapping_cache.borrow_mut();
1240 if mapping.is_none() {
1241 *mapping = Some(self.build_enum_mapping(node, io)?);
1242 }
1243 if let Some(map) = mapping.as_ref()
1244 && let Some(value) = map.by_name.get(&entry)
1245 {
1246 return Ok(*value);
1247 }
1248 }
1249 Err(GenApiError::EnumNoSuchEntry {
1250 node: name.to_string(),
1251 entry,
1252 })
1253 }
1254
1255 fn invalidate_dependents(&self, name: &str) {
1256 self.bump_generation();
1257 if let Some(children) = self.dependents.get(name) {
1258 let mut visited = HashSet::new();
1259 for child in children {
1260 self.invalidate_recursive(child, &mut visited);
1261 }
1262 }
1263 }
1264
1265 fn invalidate_recursive(&self, name: &str, visited: &mut HashSet<String>) {
1266 if !visited.insert(name.to_string()) {
1267 return;
1268 }
1269 if let Some(node) = self.nodes.get(name) {
1270 node.invalidate_cache();
1271 }
1272 if let Some(children) = self.dependents.get(name) {
1273 for child in children {
1274 self.invalidate_recursive(child, visited);
1275 }
1276 }
1277 }
1278
1279 fn bump_generation(&self) {
1280 let current = self.generation.get();
1281 self.generation.set(current.wrapping_add(1));
1282 }
1283
1284 fn get_converter_node(&self, name: &str) -> Result<&ConverterNode, GenApiError> {
1289 match self.nodes.get(name) {
1290 Some(Node::Converter(node)) => Ok(node),
1291 Some(_) => Err(GenApiError::Type(name.to_string())),
1292 None => Err(GenApiError::NodeNotFound(name.to_string())),
1293 }
1294 }
1295
1296 fn get_int_converter_node(&self, name: &str) -> Result<&IntConverterNode, GenApiError> {
1297 match self.nodes.get(name) {
1298 Some(Node::IntConverter(node)) => Ok(node),
1299 Some(_) => Err(GenApiError::Type(name.to_string())),
1300 None => Err(GenApiError::NodeNotFound(name.to_string())),
1301 }
1302 }
1303
1304 fn get_string_node(&self, name: &str) -> Result<&StringNode, GenApiError> {
1305 match self.nodes.get(name) {
1306 Some(Node::String(node)) => Ok(node),
1307 Some(_) => Err(GenApiError::Type(name.to_string())),
1308 None => Err(GenApiError::NodeNotFound(name.to_string())),
1309 }
1310 }
1311
1312 pub fn get_converter(&self, name: &str, io: &dyn RegisterIo) -> Result<f64, GenApiError> {
1314 let node = self.get_converter_node(name)?;
1315 if let Some((value, generation)) = *node.cache.borrow()
1316 && generation == self.generation.get()
1317 {
1318 return Ok(value);
1319 }
1320 let mut stack = HashSet::new();
1321 let value = self.evaluate_converter(node, io, &mut stack)?;
1322 node.cache.replace(Some((value, self.generation.get())));
1323 Ok(value)
1324 }
1325
1326 pub fn get_int_converter(&self, name: &str, io: &dyn RegisterIo) -> Result<i64, GenApiError> {
1328 let node = self.get_int_converter_node(name)?;
1329 if let Some((value, generation)) = *node.cache.borrow()
1330 && generation == self.generation.get()
1331 {
1332 return Ok(value);
1333 }
1334 let mut stack = HashSet::new();
1335 let value = self.evaluate_int_converter(node, io, &mut stack)?;
1336 node.cache.replace(Some((value, self.generation.get())));
1337 Ok(value)
1338 }
1339
1340 pub fn get_string(&self, name: &str, io: &dyn RegisterIo) -> Result<String, GenApiError> {
1342 let node = self.get_string_node(name)?;
1343 ensure_readable(&node.access, name)?;
1344 if let Some((ref value, generation)) = *node.cache.borrow()
1345 && generation == self.generation.get()
1346 {
1347 return Ok(value.clone());
1348 }
1349 let (address, len) = self.resolve_address(name, &node.addressing, io)?;
1350 let raw = io.read(address, len as usize)?;
1351 let end = raw.iter().position(|&b| b == 0).unwrap_or(raw.len());
1353 let value = String::from_utf8_lossy(&raw[..end]).to_string();
1354 node.cache
1355 .replace(Some((value.clone(), self.generation.get())));
1356 debug!(node = %name, value = %value, "get_string");
1357 Ok(value)
1358 }
1359
1360 pub fn set_string(
1362 &self,
1363 name: &str,
1364 value: &str,
1365 io: &dyn RegisterIo,
1366 ) -> Result<(), GenApiError> {
1367 let node = self.get_string_node(name)?;
1368 ensure_writable(&node.access, name)?;
1369 let (address, len) = self.resolve_address(name, &node.addressing, io)?;
1370 let mut buf = vec![0u8; len as usize];
1372 let bytes = value.as_bytes();
1373 let copy_len = bytes.len().min(len as usize);
1374 buf[..copy_len].copy_from_slice(&bytes[..copy_len]);
1375 io.write(address, &buf)?;
1376 node.cache
1377 .replace(Some((value.to_string(), self.generation.get())));
1378 self.invalidate_dependents(name);
1379 debug!(node = %name, value = %value, "set_string");
1380 Ok(())
1381 }
1382
1383 fn evaluate_converter(
1384 &self,
1385 node: &ConverterNode,
1386 io: &dyn RegisterIo,
1387 stack: &mut HashSet<String>,
1388 ) -> Result<f64, GenApiError> {
1389 if !stack.insert(node.name.clone()) {
1390 stack.remove(&node.name);
1391 return Err(GenApiError::ExprEval {
1392 name: node.name.clone(),
1393 msg: "cyclic dependency".into(),
1394 });
1395 }
1396
1397 let result = (|| {
1398 let mut values: HashMap<String, f64> = HashMap::new();
1400 for (var, provider) in &node.vars_to {
1401 let value = self.resolve_numeric(provider, io, stack)?;
1402 values.insert(var.clone(), value);
1403 }
1404 let mut resolver = |ident: &str| -> Result<f64, SkEvalError> {
1406 values
1407 .get(ident)
1408 .copied()
1409 .ok_or_else(|| SkEvalError::UnknownVariable(ident.to_string()))
1410 };
1411 match eval_ast(&node.ast_to, &mut resolver) {
1412 Ok(value) => {
1413 debug!(node = %node.name, value, "evaluate Converter");
1414 Ok(value)
1415 }
1416 Err(SkEvalError::UnknownVariable(var)) => Err(GenApiError::UnknownVariable {
1417 name: node.name.clone(),
1418 var,
1419 }),
1420 Err(SkEvalError::DivisionByZero) => Err(GenApiError::ExprEval {
1421 name: node.name.clone(),
1422 msg: "division by zero".into(),
1423 }),
1424 Err(SkEvalError::UnknownFunction(func)) => Err(GenApiError::ExprEval {
1425 name: node.name.clone(),
1426 msg: format!("unknown function: {func}"),
1427 }),
1428 Err(SkEvalError::ArityMismatch {
1429 name: func,
1430 expected,
1431 got,
1432 }) => Err(GenApiError::ExprEval {
1433 name: node.name.clone(),
1434 msg: format!("function {func} expects {expected} args, got {got}"),
1435 }),
1436 }
1437 })();
1438
1439 stack.remove(&node.name);
1440 result
1441 }
1442
1443 fn evaluate_int_converter(
1444 &self,
1445 node: &IntConverterNode,
1446 io: &dyn RegisterIo,
1447 stack: &mut HashSet<String>,
1448 ) -> Result<i64, GenApiError> {
1449 if !stack.insert(node.name.clone()) {
1450 stack.remove(&node.name);
1451 return Err(GenApiError::ExprEval {
1452 name: node.name.clone(),
1453 msg: "cyclic dependency".into(),
1454 });
1455 }
1456
1457 let result = (|| {
1458 let mut values: HashMap<String, f64> = HashMap::new();
1459 for (var, provider) in &node.vars_to {
1460 let value = self.resolve_numeric(provider, io, stack)?;
1461 values.insert(var.clone(), value);
1462 }
1463 let mut resolver = |ident: &str| -> Result<f64, SkEvalError> {
1464 values
1465 .get(ident)
1466 .copied()
1467 .ok_or_else(|| SkEvalError::UnknownVariable(ident.to_string()))
1468 };
1469 match eval_ast(&node.ast_to, &mut resolver) {
1470 Ok(value) => {
1471 let int_value = round_to_i64(&node.name, value)?;
1472 debug!(node = %node.name, int_value, "evaluate IntConverter");
1473 Ok(int_value)
1474 }
1475 Err(SkEvalError::UnknownVariable(var)) => Err(GenApiError::UnknownVariable {
1476 name: node.name.clone(),
1477 var,
1478 }),
1479 Err(SkEvalError::DivisionByZero) => Err(GenApiError::ExprEval {
1480 name: node.name.clone(),
1481 msg: "division by zero".into(),
1482 }),
1483 Err(SkEvalError::UnknownFunction(func)) => Err(GenApiError::ExprEval {
1484 name: node.name.clone(),
1485 msg: format!("unknown function: {func}"),
1486 }),
1487 Err(SkEvalError::ArityMismatch {
1488 name: func,
1489 expected,
1490 got,
1491 }) => Err(GenApiError::ExprEval {
1492 name: node.name.clone(),
1493 msg: format!("function {func} expects {expected} args, got {got}"),
1494 }),
1495 }
1496 })();
1497
1498 stack.remove(&node.name);
1499 result
1500 }
1501}
1502
1503impl From<XmlModel> for NodeMap {
1504 fn from(model: XmlModel) -> Self {
1505 NodeMap::try_from_xml(model).expect("invalid GenApi model")
1506 }
1507}